axisline_style.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. from __future__ import (absolute_import, division, print_function,
  2. unicode_literals)
  3. import six
  4. from matplotlib.patches import _Style, FancyArrowPatch
  5. from matplotlib.transforms import IdentityTransform
  6. from matplotlib.path import Path
  7. import numpy as np
  8. class _FancyAxislineStyle(object):
  9. class SimpleArrow(FancyArrowPatch):
  10. """
  11. The artist class that will be returned for SimpleArrow style.
  12. """
  13. _ARROW_STYLE = "->"
  14. def __init__(self, axis_artist, line_path, transform,
  15. line_mutation_scale):
  16. self._axis_artist = axis_artist
  17. self._line_transform = transform
  18. self._line_path = line_path
  19. self._line_mutation_scale = line_mutation_scale
  20. FancyArrowPatch.__init__(self,
  21. path=self._line_path,
  22. arrowstyle=self._ARROW_STYLE,
  23. arrow_transmuter=None,
  24. patchA=None,
  25. patchB=None,
  26. shrinkA=0.,
  27. shrinkB=0.,
  28. mutation_scale=line_mutation_scale,
  29. mutation_aspect=None,
  30. transform=IdentityTransform(),
  31. )
  32. def set_line_mutation_scale(self, scale):
  33. self.set_mutation_scale(scale*self._line_mutation_scale)
  34. def _extend_path(self, path, mutation_size=10):
  35. """
  36. Extend the path to make a room for drawing arrow.
  37. """
  38. from matplotlib.bezier import get_cos_sin
  39. x0, y0 = path.vertices[-2]
  40. x1, y1 = path.vertices[-1]
  41. cost, sint = get_cos_sin(x0, y0, x1, y1)
  42. d = mutation_size * 1.
  43. x2, y2 = x1 + cost*d, y1+sint*d
  44. if path.codes is None:
  45. _path = Path(np.concatenate([path.vertices, [[x2, y2]]]))
  46. else:
  47. _path = Path(np.concatenate([path.vertices, [[x2, y2]]]),
  48. np.concatenate([path.codes, [Path.LINETO]]))
  49. return _path
  50. def set_path(self, path):
  51. self._line_path = path
  52. def draw(self, renderer):
  53. """
  54. Draw the axis line.
  55. 1) transform the path to the display coordinate.
  56. 2) extend the path to make a room for arrow
  57. 3) update the path of the FancyArrowPatch.
  58. 4) draw
  59. """
  60. path_in_disp = self._line_transform.transform_path(self._line_path)
  61. mutation_size = self.get_mutation_scale() #line_mutation_scale()
  62. extented_path = self._extend_path(path_in_disp,
  63. mutation_size=mutation_size)
  64. self._path_original = extented_path
  65. FancyArrowPatch.draw(self, renderer)
  66. class FilledArrow(SimpleArrow):
  67. """
  68. The artist class that will be returned for SimpleArrow style.
  69. """
  70. _ARROW_STYLE = "-|>"
  71. class AxislineStyle(_Style):
  72. """
  73. :class:`AxislineStyle` is a container class which defines style classes
  74. for AxisArtists.
  75. An instance of any axisline style class is an callable object,
  76. whose call signature is ::
  77. __call__(self, axis_artist, path, transform)
  78. When called, this should return a mpl artist with following
  79. methods implemented. ::
  80. def set_path(self, path):
  81. # set the path for axisline.
  82. def set_line_mutation_scale(self, scale):
  83. # set the scale
  84. def draw(self, renderer):
  85. # draw
  86. """
  87. _style_list = {}
  88. class _Base(object):
  89. # The derived classes are required to be able to be initialized
  90. # w/o arguments, i.e., all its argument (except self) must have
  91. # the default values.
  92. def __init__(self):
  93. """
  94. initialization.
  95. """
  96. super(AxislineStyle._Base, self).__init__()
  97. def __call__(self, axis_artist, transform):
  98. """
  99. Given the AxisArtist instance, and transform for the path
  100. (set_path method), return the mpl artist for drawing the axis line.
  101. """
  102. return self.new_line(axis_artist, transform)
  103. class SimpleArrow(_Base):
  104. """
  105. A simple arrow.
  106. """
  107. ArrowAxisClass = _FancyAxislineStyle.SimpleArrow
  108. def __init__(self, size=1):
  109. """
  110. *size*
  111. size of the arrow as a fraction of the ticklabel size.
  112. """
  113. self.size = size
  114. super(AxislineStyle.SimpleArrow, self).__init__()
  115. def new_line(self, axis_artist, transform):
  116. linepath = Path([(0,0), (0, 1)])
  117. axisline = self.ArrowAxisClass(axis_artist, linepath, transform,
  118. line_mutation_scale=self.size)
  119. return axisline
  120. _style_list["->"] = SimpleArrow
  121. class FilledArrow(SimpleArrow):
  122. ArrowAxisClass = _FancyAxislineStyle.FilledArrow
  123. _style_list["-|>"] = FilledArrow