| | 310 | def _renderYLabel(self, cx, tick): |
| | 311 | """Aux method for _renderAxis""" |
| | 312 | |
| | 313 | if callable(tick): |
| | 314 | return |
| | 315 | |
| | 316 | x = self.area.x |
| | 317 | y = self.area.y + tick[0] * self.area.h |
| | 318 | |
| | 319 | cx.new_path() |
| | 320 | cx.move_to(x, y) |
| | 321 | cx.line_to(x - self.options.axis.tickSize, y) |
| | 322 | cx.close_path() |
| | 323 | cx.stroke() |
| | 324 | |
| | 325 | label = unicode(tick[1]) |
| | 326 | extents = cx.text_extents(label) |
| | 327 | labelWidth = extents[2] |
| | 328 | labelHeight = extents[3] |
| | 329 | |
| | 330 | if self.options.axis.y.rotate: |
| | 331 | radians = math.radians(self.options.axis.y.rotate) |
| | 332 | cx.move_to(x - self.options.axis.tickSize |
| | 333 | - (labelWidth * math.cos(radians)) |
| | 334 | - 4, |
| | 335 | y + (labelWidth * math.sin(radians)) |
| | 336 | + labelHeight / (2.0 / math.cos(radians))) |
| | 337 | cx.rotate(-radians) |
| | 338 | cx.show_text(label) |
| | 339 | cx.rotate(radians) # this is probably faster than a save/restore |
| | 340 | else: |
| | 341 | cx.move_to(x - self.options.axis.tickSize - labelWidth - 4, |
| | 342 | y + labelHeight / 2.0) |
| | 343 | cx.show_text(label) |
| | 344 | |
| | 345 | return label |
| | 346 | |
| | 347 | def _renderXLabel(self, cx, tick, fontAscent): |
| | 348 | if callable(tick): |
| | 349 | return |
| | 350 | |
| | 351 | x = self.area.x + tick[0] * self.area.w |
| | 352 | y = self.area.y + self.area.h |
| | 353 | |
| | 354 | cx.new_path() |
| | 355 | cx.move_to(x, y) |
| | 356 | cx.line_to(x, y + self.options.axis.tickSize) |
| | 357 | cx.close_path() |
| | 358 | cx.stroke() |
| | 359 | |
| | 360 | label = unicode(tick[1]) |
| | 361 | extents = cx.text_extents(label) |
| | 362 | labelWidth = extents[2] |
| | 363 | labelHeight = extents[3] |
| | 364 | |
| | 365 | if self.options.axis.x.rotate: |
| | 366 | radians = math.radians(self.options.axis.x.rotate) |
| | 367 | cx.move_to(x - (labelHeight * math.cos(radians)), |
| | 368 | y + self.options.axis.tickSize |
| | 369 | + (labelHeight * math.cos(radians)) |
| | 370 | + 4.0) |
| | 371 | cx.rotate(radians) |
| | 372 | cx.show_text(label) |
| | 373 | cx.rotate(-radians) |
| | 374 | else: |
| | 375 | cx.move_to(x - labelWidth / 2.0, |
| | 376 | y + self.options.axis.tickSize |
| | 377 | + fontAscent + 4.0) |
| | 378 | cx.show_text(label) |
| | 379 | return label |
| | 380 | |
| | 381 | def _getTickSize(self, cx, ticks, rotate): |
| | 382 | tickExtents = [cx.text_extents(unicode(tick[1]))[2:4] for tick in ticks] |
| | 383 | tickWidth = tickHeight = 0.0 |
| | 384 | if tickExtents: |
| | 385 | tickHeight = tickHeight = self.options.axis.tickSize + 4.0 |
| | 386 | widths, heights = zip(*tickExtents) |
| | 387 | maxWidth, maxHeight = max(widths), max(heights) |
| | 388 | if rotate: |
| | 389 | radians = math.radians(rotate) |
| | 390 | sinRadians = math.sin(radians) |
| | 391 | cosRadians = math.cos(radians) |
| | 392 | maxHeight = maxWidth * sinRadians + maxHeight * cosRadians |
| | 393 | maxWidth = maxWidth * cosRadians + maxHeight * sinRadians |
| | 394 | tickWidth += maxWidth |
| | 395 | tickHeight += maxHeight |
| | 396 | return tickWidth, tickHeight |
| | 397 | |
| | 398 | def _renderAxisLabel(self, cx, tickWidth, tickHeight, label, x, y, vertical=False): |
| | 399 | cx.new_path() |
| | 400 | cx.select_font_face(self.options.axis.labelFont, |
| | 401 | cairo.FONT_SLANT_NORMAL, |
| | 402 | cairo.FONT_WEIGHT_BOLD) |
| | 403 | labelWidth = cx.text_extents(label)[2] |
| | 404 | fontAscent = cx.font_extents()[0] |
| | 405 | if vertical: |
| | 406 | cx.move_to(x, y + labelWidth / 2) |
| | 407 | radians = math.radians(90) |
| | 408 | cx.rotate(-radians) |
| | 409 | else: |
| | 410 | cx.move_to(x - labelWidth / 2.0, y + fontAscent) |
| | 411 | |
| | 412 | cx.show_text(label) |
| | 413 | |
| 342 | | drawYLabel(tick) |
| 343 | | |
| | 426 | self._renderYLabel(cx, tick) |
| | 427 | |
| | 428 | if self.options.axis.y.label: |
| | 429 | cx.save() |
| | 430 | rotate = self.options.axis.y.rotate |
| | 431 | tickWidth, tickHeight = self._getTickSize(cx, self.yticks, rotate) |
| | 432 | label = unicode(self.options.axis.y.label) |
| | 433 | x = self.area.x - tickWidth - 4.0 |
| | 434 | y = self.area.y + 0.5 * self.area.h |
| | 435 | self._renderAxisLabel(cx, tickWidth, tickHeight, label, x, y, True) |
| | 436 | cx.restore() |
| | 437 | |
| | 438 | # draws the vertical line representing the Y axis |
| 374 | | drawXLabel(tick) |
| 375 | | |
| | 449 | self._renderXLabel(cx, tick, fontAscent) |
| | 450 | |
| | 451 | if self.options.axis.x.label: |
| | 452 | cx.save() |
| | 453 | rotate = self.options.axis.x.rotate |
| | 454 | tickWidth, tickHeight = self._getTickSize(cx, self.xticks, rotate) |
| | 455 | label = unicode(self.options.axis.x.label) |
| | 456 | x = self.area.x + self.area.w / 2.0 |
| | 457 | y = self.area.y + self.area.h + tickHeight + 4.0 |
| | 458 | self._renderAxisLabel(cx, tickWidth, tickHeight, label, x, y, False) |
| | 459 | cx.restore() |
| | 460 | |
| | 461 | # draws the horizontal line representing the X axis |