|
2 | 2 | unicode_literals) |
3 | 3 | import six |
4 | 4 |
|
5 | | -from matplotlib import docstring |
| 5 | +from matplotlib import docstring, transforms |
6 | 6 | from matplotlib.offsetbox import (AnchoredOffsetbox, AuxTransformBox, |
7 | 7 | DrawingArea, TextArea, VPacker) |
8 | | -from matplotlib.patches import Rectangle, Ellipse |
9 | | - |
| 8 | +from matplotlib.patches import Rectangle, Ellipse, ArrowStyle, FancyArrowPatch, PathPatch |
| 9 | +from matplotlib.text import TextPath |
10 | 10 |
|
11 | 11 | __all__ = ['AnchoredDrawingArea', 'AnchoredAuxTransformBox', |
12 | | - 'AnchoredEllipse', 'AnchoredSizeBar'] |
| 12 | + 'AnchoredEllipse', 'AnchoredSizeBar','AnchoredDirectionArrows'] |
13 | 13 |
|
14 | 14 |
|
15 | 15 | class AnchoredDrawingArea(AnchoredOffsetbox): |
@@ -374,3 +374,171 @@ def __init__(self, transform, size, label, loc, |
374 | 374 | child=self._box, |
375 | 375 | prop=fontproperties, |
376 | 376 | frameon=frameon, **kwargs) |
| 377 | + |
| 378 | +class AnchoredDirectionArrows(AnchoredOffsetbox): |
| 379 | + @docstring.dedent |
| 380 | + def __init__(self, transform, label_x, label_y, length=0.15, fontsize=0.08, loc=2, |
| 381 | + angle=0, aspect_ratio=1, pad=0.1, borderpad=0.1, |
| 382 | + frameon=False, color='black', alpha=1, sep_x=0.01,sep_y=0, fontproperties=None, |
| 383 | + back_length=0.15, head_width=10, head_length=15, tail_width=2, |
| 384 | + lw=0.5, text_props={}, arrow_props={}, |
| 385 | + **kwargs): |
| 386 | + """ |
| 387 | + Draw a direction indicator arrows |
| 388 | +
|
| 389 | + Parameters |
| 390 | + ---------- |
| 391 | + transform : `matplotlib.transforms.Transform` |
| 392 | + The transformation object for the coordinate system in use, i.e., |
| 393 | + :attr:`matplotlib.axes.Axes.transData`. |
| 394 | +
|
| 395 | + length : int or float |
| 396 | + Length of the arrow, given in coordinates of |
| 397 | + *transform*. |
| 398 | +
|
| 399 | + label : str |
| 400 | + Label to display. |
| 401 | +
|
| 402 | + loc : int |
| 403 | + Location of this size bar. Valid location codes are:: |
| 404 | +
|
| 405 | + 'upper right' : 1, |
| 406 | + 'upper left' : 2, |
| 407 | + 'lower left' : 3, |
| 408 | + 'lower right' : 4, |
| 409 | + 'right' : 5, |
| 410 | + 'center left' : 6, |
| 411 | + 'center right' : 7, |
| 412 | + 'lower center' : 8, |
| 413 | + 'upper center' : 9, |
| 414 | + 'center' : 10 |
| 415 | +
|
| 416 | + pad : int or float, optional |
| 417 | + Padding around the label and size bar, in fraction of the font |
| 418 | + size. Defaults to 0.1. |
| 419 | +
|
| 420 | + borderpad : int or float, optional |
| 421 | + Border padding, in fraction of the font size. |
| 422 | + Defaults to 0.1. |
| 423 | +
|
| 424 | + sep_x : int or float, optional |
| 425 | + Separation between the arrows and labels in ??? |
| 426 | + Defaults to 0.01. |
| 427 | +
|
| 428 | + frameon : bool, optional |
| 429 | + If True, draw a box around the horizontal bar and label. |
| 430 | + Defaults to False. |
| 431 | +
|
| 432 | + color : str, optional |
| 433 | + Color for the size bar and label. |
| 434 | + Defaults to black. |
| 435 | +
|
| 436 | + fontproperties : `matplotlib.font_manager.FontProperties`, optional |
| 437 | + Font properties for the label text. |
| 438 | +
|
| 439 | + **kwargs : |
| 440 | + Keyworded arguments to pass to |
| 441 | + :class:`matplotlib.offsetbox.AnchoredOffsetbox`. |
| 442 | +
|
| 443 | + Attributes |
| 444 | + ---------- |
| 445 | + size_bar : `matplotlib.offsetbox.AuxTransformBox` |
| 446 | + Container for the size bar. |
| 447 | +
|
| 448 | + txt_label : `matplotlib.offsetbox.TextArea` |
| 449 | + Container for the label of the size bar. |
| 450 | +
|
| 451 | + Notes |
| 452 | + ----- |
| 453 | + If *prop* is passed as a keyworded argument, but *fontproperties* is |
| 454 | + not, then *prop* is be assumed to be the intended *fontproperties*. |
| 455 | + Using both *prop* and *fontproperties* is not supported. |
| 456 | +
|
| 457 | + Examples |
| 458 | + -------- |
| 459 | + >>> import matplotlib.pyplot as plt |
| 460 | + >>> import numpy as np |
| 461 | + >>> from mpl_toolkits.axes_grid1.anchored_artists import \ |
| 462 | +AnchoredDirectionArrows |
| 463 | + >>> fig, ax = plt.subplots() |
| 464 | + >>> ax.imshow(np.random.random((10,10))) |
| 465 | + >>> arrows = AnchoredDirectionArrows(ax.transData, 3, '3 data units', 4) |
| 466 | + >>> ax.add_artist(bar) |
| 467 | + >>> fig.show() |
| 468 | +
|
| 469 | + Using all the optional parameters |
| 470 | +
|
| 471 | + >>> import matplotlib.font_manager as fm |
| 472 | + >>> fontprops = fm.FontProperties(size=14, family='monospace') |
| 473 | + >>> bar = AnchoredSizeBar(ax.transData, 3, '3 units', 4, pad=0.5, \ |
| 474 | +sep=5, borderpad=0.5, frameon=False, \ |
| 475 | +size_vertical=0.5, color='white', \ |
| 476 | +fontproperties=fontprops) |
| 477 | + """ |
| 478 | + arrowstyle = ArrowStyle("Simple", |
| 479 | + head_width=head_width, |
| 480 | + head_length=head_length, |
| 481 | + tail_width=tail_width) |
| 482 | + |
| 483 | + if fontproperties is None and 'prop' in kwargs: |
| 484 | + fontproperties = kwargs.pop('prop') |
| 485 | + |
| 486 | + if 'color' not in arrow_props: |
| 487 | + arrow_props['color'] = color |
| 488 | + |
| 489 | + if 'alpha' not in arrow_props: |
| 490 | + arrow_props['alpha'] = alpha |
| 491 | + |
| 492 | + if 'color' not in text_props: |
| 493 | + text_props['color'] = color |
| 494 | + text_props['ec'] = color |
| 495 | + |
| 496 | + if 'alpha' not in text_props: |
| 497 | + text_props['alpha'] = alpha |
| 498 | + |
| 499 | + if 'lw' not in text_props: |
| 500 | + text_props['lw'] = lw |
| 501 | + |
| 502 | + t_start = transform |
| 503 | + t = transforms.Affine2D().rotate_deg(angle) |
| 504 | + t_end = t_start + t |
| 505 | + t_text = t_start#_end + Affine2D().rotate_deg(angle) |
| 506 | + |
| 507 | + self._box = AuxTransformBox(t_end) |
| 508 | + |
| 509 | + length_x = length |
| 510 | + length_y = length*aspect_ratio |
| 511 | + |
| 512 | + self.arrow_x = FancyArrowPatch( |
| 513 | + (0,back_length*length_y), |
| 514 | + (length_x,back_length*length_y), |
| 515 | + arrowstyle=arrowstyle, |
| 516 | + shrinkA=0.0, |
| 517 | + shrinkB=0.0, |
| 518 | + **arrow_props) |
| 519 | + |
| 520 | + self.arrow_y = FancyArrowPatch( |
| 521 | + (back_length*length_x,0), |
| 522 | + (back_length*length_x,length_y), |
| 523 | + arrowstyle=arrowstyle, |
| 524 | + shrinkA=0.0, |
| 525 | + shrinkB=0.0, |
| 526 | + **arrow_props) |
| 527 | + |
| 528 | + self._box.add_artist(self.arrow_x) |
| 529 | + self._box.add_artist(self.arrow_y) |
| 530 | + |
| 531 | + #Label X |
| 532 | + text_path_x = TextPath((length_x+sep_x, back_length*length_y+sep_y), label_x, size=fontsize, prop=fontproperties, roatation=angle) |
| 533 | + self.p_x = PathPatch(text_path_x, transform=t_start, **text_props) |
| 534 | + self._box.add_artist(self.p_x) |
| 535 | + |
| 536 | + #Label Y |
| 537 | + text_path_y = TextPath((length_x*back_length+sep_x, length_y*(1-back_length)+sep_y), label_y, size=fontsize, prop=fontproperties) |
| 538 | + self.p_y = PathPatch(text_path_y, **text_props) |
| 539 | + self._box.add_artist(self.p_y) |
| 540 | + |
| 541 | + AnchoredOffsetbox.__init__(self, loc, pad=pad, borderpad=borderpad, |
| 542 | + child=self._box, |
| 543 | + frameon=frameon, **kwargs) |
| 544 | + |
0 commit comments