_enums.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. """
  2. Enums representing sets of strings that Matplotlib uses as input parameters.
  3. Matplotlib often uses simple data types like strings or tuples to define a
  4. concept; e.g. the line capstyle can be specified as one of 'butt', 'round',
  5. or 'projecting'. The classes in this module are used internally and serve to
  6. document these concepts formally.
  7. As an end-user you will not use these classes directly, but only the values
  8. they define.
  9. """
  10. from enum import Enum, auto
  11. from matplotlib import _docstring
  12. class _AutoStringNameEnum(Enum):
  13. """Automate the ``name = 'name'`` part of making a (str, Enum)."""
  14. def _generate_next_value_(name, start, count, last_values):
  15. return name
  16. def __hash__(self):
  17. return str(self).__hash__()
  18. class JoinStyle(str, _AutoStringNameEnum):
  19. """
  20. Define how the connection between two line segments is drawn.
  21. For a visual impression of each *JoinStyle*, `view these docs online
  22. <JoinStyle>`, or run `JoinStyle.demo`.
  23. Lines in Matplotlib are typically defined by a 1D `~.path.Path` and a
  24. finite ``linewidth``, where the underlying 1D `~.path.Path` represents the
  25. center of the stroked line.
  26. By default, `~.backend_bases.GraphicsContextBase` defines the boundaries of
  27. a stroked line to simply be every point within some radius,
  28. ``linewidth/2``, away from any point of the center line. However, this
  29. results in corners appearing "rounded", which may not be the desired
  30. behavior if you are drawing, for example, a polygon or pointed star.
  31. **Supported values:**
  32. .. rst-class:: value-list
  33. 'miter'
  34. the "arrow-tip" style. Each boundary of the filled-in area will
  35. extend in a straight line parallel to the tangent vector of the
  36. centerline at the point it meets the corner, until they meet in a
  37. sharp point.
  38. 'round'
  39. stokes every point within a radius of ``linewidth/2`` of the center
  40. lines.
  41. 'bevel'
  42. the "squared-off" style. It can be thought of as a rounded corner
  43. where the "circular" part of the corner has been cut off.
  44. .. note::
  45. Very long miter tips are cut off (to form a *bevel*) after a
  46. backend-dependent limit called the "miter limit", which specifies the
  47. maximum allowed ratio of miter length to line width. For example, the
  48. PDF backend uses the default value of 10 specified by the PDF standard,
  49. while the SVG backend does not even specify the miter limit, resulting
  50. in a default value of 4 per the SVG specification. Matplotlib does not
  51. currently allow the user to adjust this parameter.
  52. A more detailed description of the effect of a miter limit can be found
  53. in the `Mozilla Developer Docs
  54. <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-miterlimit>`_
  55. .. plot::
  56. :alt: Demo of possible JoinStyle's
  57. from matplotlib._enums import JoinStyle
  58. JoinStyle.demo()
  59. """
  60. miter = auto()
  61. round = auto()
  62. bevel = auto()
  63. @staticmethod
  64. def demo():
  65. """Demonstrate how each JoinStyle looks for various join angles."""
  66. import numpy as np
  67. import matplotlib.pyplot as plt
  68. def plot_angle(ax, x, y, angle, style):
  69. phi = np.radians(angle)
  70. xx = [x + .5, x, x + .5*np.cos(phi)]
  71. yy = [y, y, y + .5*np.sin(phi)]
  72. ax.plot(xx, yy, lw=12, color='tab:blue', solid_joinstyle=style)
  73. ax.plot(xx, yy, lw=1, color='black')
  74. ax.plot(xx[1], yy[1], 'o', color='tab:red', markersize=3)
  75. fig, ax = plt.subplots(figsize=(5, 4), constrained_layout=True)
  76. ax.set_title('Join style')
  77. for x, style in enumerate(['miter', 'round', 'bevel']):
  78. ax.text(x, 5, style)
  79. for y, angle in enumerate([20, 45, 60, 90, 120]):
  80. plot_angle(ax, x, y, angle, style)
  81. if x == 0:
  82. ax.text(-1.3, y, f'{angle} degrees')
  83. ax.set_xlim(-1.5, 2.75)
  84. ax.set_ylim(-.5, 5.5)
  85. ax.set_axis_off()
  86. fig.show()
  87. JoinStyle.input_description = "{" \
  88. + ", ".join([f"'{js.name}'" for js in JoinStyle]) \
  89. + "}"
  90. class CapStyle(str, _AutoStringNameEnum):
  91. r"""
  92. Define how the two endpoints (caps) of an unclosed line are drawn.
  93. How to draw the start and end points of lines that represent a closed curve
  94. (i.e. that end in a `~.path.Path.CLOSEPOLY`) is controlled by the line's
  95. `JoinStyle`. For all other lines, how the start and end points are drawn is
  96. controlled by the *CapStyle*.
  97. For a visual impression of each *CapStyle*, `view these docs online
  98. <CapStyle>` or run `CapStyle.demo`.
  99. By default, `~.backend_bases.GraphicsContextBase` draws a stroked line as
  100. squared off at its endpoints.
  101. **Supported values:**
  102. .. rst-class:: value-list
  103. 'butt'
  104. the line is squared off at its endpoint.
  105. 'projecting'
  106. the line is squared off as in *butt*, but the filled in area
  107. extends beyond the endpoint a distance of ``linewidth/2``.
  108. 'round'
  109. like *butt*, but a semicircular cap is added to the end of the
  110. line, of radius ``linewidth/2``.
  111. .. plot::
  112. :alt: Demo of possible CapStyle's
  113. from matplotlib._enums import CapStyle
  114. CapStyle.demo()
  115. """
  116. butt = auto()
  117. projecting = auto()
  118. round = auto()
  119. @staticmethod
  120. def demo():
  121. """Demonstrate how each CapStyle looks for a thick line segment."""
  122. import matplotlib.pyplot as plt
  123. fig = plt.figure(figsize=(4, 1.2))
  124. ax = fig.add_axes([0, 0, 1, 0.8])
  125. ax.set_title('Cap style')
  126. for x, style in enumerate(['butt', 'round', 'projecting']):
  127. ax.text(x+0.25, 0.85, style, ha='center')
  128. xx = [x, x+0.5]
  129. yy = [0, 0]
  130. ax.plot(xx, yy, lw=12, color='tab:blue', solid_capstyle=style)
  131. ax.plot(xx, yy, lw=1, color='black')
  132. ax.plot(xx, yy, 'o', color='tab:red', markersize=3)
  133. ax.set_ylim(-.5, 1.5)
  134. ax.set_axis_off()
  135. fig.show()
  136. CapStyle.input_description = "{" \
  137. + ", ".join([f"'{cs.name}'" for cs in CapStyle]) \
  138. + "}"
  139. _docstring.interpd.update({'JoinStyle': JoinStyle.input_description,
  140. 'CapStyle': CapStyle.input_description})