|
| 1 | +""" |
| 2 | +Enums representing sets of strings that Matplotlib uses as input parameters. |
| 3 | +
|
| 4 | +Matplotlib often uses simple data types like strings or tuples to define a |
| 5 | +concept; e.g. the line capstyle can be specified as one of 'butt', 'round', |
| 6 | +or 'projecting'. The classes in this module are used internally and serve to |
| 7 | +document these concepts formally. |
| 8 | +
|
| 9 | +As an end-user you will not use these classes directly, but only the values |
| 10 | +they define. |
| 11 | +""" |
| 12 | + |
| 13 | +fromenumimportEnum,auto |
| 14 | +frommatplotlibimportcbook,docstring |
| 15 | + |
| 16 | + |
| 17 | +class_AutoStringNameEnum(Enum): |
| 18 | +"""Automate the ``name = 'name'`` part of making a (str, Enum).""" |
| 19 | + |
| 20 | +def_generate_next_value_(name,start,count,last_values): |
| 21 | +returnname |
| 22 | + |
| 23 | +def__hash__(self): |
| 24 | +returnstr(self).__hash__() |
| 25 | + |
| 26 | + |
| 27 | +def_deprecate_case_insensitive_join_cap(s): |
| 28 | +s_low=s.lower() |
| 29 | +ifs!=s_low: |
| 30 | +ifs_lowin ['miter','round','bevel']: |
| 31 | +cbook.warn_deprecated( |
| 32 | +"3.3",message="Case-insensitive capstyles are deprecated " |
| 33 | +"since %(since)s and support for them will be removed " |
| 34 | +"%(removal)s; please pass them in lowercase.") |
| 35 | +elifs_lowin ['butt','round','projecting']: |
| 36 | +cbook.warn_deprecated( |
| 37 | +"3.3",message="Case-insensitive joinstyles are deprecated " |
| 38 | +"since %(since)s and support for them will be removed " |
| 39 | +"%(removal)s; please pass them in lowercase.") |
| 40 | +# Else, error out at the check_in_list stage. |
| 41 | +returns_low |
| 42 | + |
| 43 | + |
| 44 | +classJoinStyle(str,_AutoStringNameEnum): |
| 45 | +""" |
| 46 | + Define how the connection between two line segments is drawn. |
| 47 | +
|
| 48 | + For a visual impression of each *JoinStyle*, `view these docs online |
| 49 | + <JoinStyle>`, or run `JoinStyle.demo`. |
| 50 | +
|
| 51 | + Lines in Matplotlib are typically defined by a 1D `~.path.Path` and a |
| 52 | + finite ``linewidth``, where the underlying 1D `~.path.Path` represents the |
| 53 | + center of the stroked line. |
| 54 | +
|
| 55 | + By default, `~.backend_bases.GraphicsContextBase` defines the boundaries of |
| 56 | + a stroked line to simply be every point within some radius, |
| 57 | + ``linewidth/2``, away from any point of the center line. However, this |
| 58 | + results in corners appearing "rounded", which may not be the desired |
| 59 | + behavior if you are drawing, for example, a polygon or pointed star. |
| 60 | +
|
| 61 | + **Supported values:** |
| 62 | +
|
| 63 | + .. rst-class:: value-list |
| 64 | +
|
| 65 | + 'miter' |
| 66 | + the "arrow-tip" style. Each boundary of the filled-in area will |
| 67 | + extend in a straight line parallel to the tangent vector of the |
| 68 | + centerline at the point it meets the corner, until they meet in a |
| 69 | + sharp point. |
| 70 | + 'round' |
| 71 | + stokes every point within a radius of ``linewidth/2`` of the center |
| 72 | + lines. |
| 73 | + 'bevel' |
| 74 | + the "squared-off" style. It can be thought of as a rounded corner |
| 75 | + where the "circular" part of the corner has been cut off. |
| 76 | +
|
| 77 | + .. note:: |
| 78 | +
|
| 79 | + Very long miter tips are cut off (to form a *bevel*) after a |
| 80 | + backend-dependent limit called the "miter limit", which specifies the |
| 81 | + maximum allowed ratio of miter length to line width. For example, the |
| 82 | + PDF backend uses the default value of 10 specified by the PDF standard, |
| 83 | + while the SVG backend does not even specify the miter limit, resulting |
| 84 | + in a default value of 4 per the SVG specification. Matplotlib does not |
| 85 | + currently allow the user to adjust this parameter. |
| 86 | +
|
| 87 | + A more detailed description of the effect of a miter limit can be found |
| 88 | + in the `Mozilla Developer Docs |
| 89 | + <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-miterlimit>`_ |
| 90 | +
|
| 91 | + .. plot:: |
| 92 | + :alt: Demo of possible JoinStyle's |
| 93 | +
|
| 94 | + from matplotlib._enums import JoinStyle |
| 95 | + JoinStyle.demo() |
| 96 | +
|
| 97 | + """ |
| 98 | + |
| 99 | +miter=auto() |
| 100 | +round=auto() |
| 101 | +bevel=auto() |
| 102 | + |
| 103 | +def__init__(self,s): |
| 104 | +s=_deprecate_case_insensitive_join_cap(s) |
| 105 | +Enum.__init__(self) |
| 106 | + |
| 107 | +@staticmethod |
| 108 | +defdemo(): |
| 109 | +"""Demonstrate how each JoinStyle looks for various join angles.""" |
| 110 | +importnumpyasnp |
| 111 | +importmatplotlib.pyplotasplt |
| 112 | + |
| 113 | +defplot_angle(ax,x,y,angle,style): |
| 114 | +phi=np.radians(angle) |
| 115 | +xx= [x+.5,x,x+.5*np.cos(phi)] |
| 116 | +yy= [y,y,y+.5*np.sin(phi)] |
| 117 | +ax.plot(xx,yy,lw=12,color='tab:blue',solid_joinstyle=style) |
| 118 | +ax.plot(xx,yy,lw=1,color='black') |
| 119 | +ax.plot(xx[1],yy[1],'o',color='tab:red',markersize=3) |
| 120 | + |
| 121 | +fig,ax=plt.subplots(figsize=(5,4),constrained_layout=True) |
| 122 | +ax.set_title('Join style') |
| 123 | +forx,styleinenumerate(['miter','round','bevel']): |
| 124 | +ax.text(x,5,style) |
| 125 | +fory,angleinenumerate([20,45,60,90,120]): |
| 126 | +plot_angle(ax,x,y,angle,style) |
| 127 | +ifx==0: |
| 128 | +ax.text(-1.3,y,f'{angle} degrees') |
| 129 | +ax.set_xlim(-1.5,2.75) |
| 130 | +ax.set_ylim(-.5,5.5) |
| 131 | +ax.set_axis_off() |
| 132 | +fig.show() |
| 133 | + |
| 134 | + |
| 135 | +JoinStyle.input_description="{" \ |
| 136 | ++", ".join([f"'{js.name}'"forjsinJoinStyle]) \ |
| 137 | ++"}" |
| 138 | + |
| 139 | + |
| 140 | +classCapStyle(str,_AutoStringNameEnum): |
| 141 | +r""" |
| 142 | + Define how the two endpoints (caps) of an unclosed line are drawn. |
| 143 | +
|
| 144 | + How to draw the start and end points of lines that represent a closed curve |
| 145 | + (i.e. that end in a `~.path.Path.CLOSEPOLY`) is controlled by the line's |
| 146 | + `JoinStyle`. For all other lines, how the start and end points are drawn is |
| 147 | + controlled by the *CapStyle*. |
| 148 | +
|
| 149 | + For a visual impression of each *CapStyle*, `view these docs online |
| 150 | + <CapStyle>` or run `CapStyle.demo`. |
| 151 | +
|
| 152 | + **Supported values:** |
| 153 | +
|
| 154 | + .. rst-class:: value-list |
| 155 | +
|
| 156 | + 'butt' |
| 157 | + the line is squared off at its endpoint. |
| 158 | + 'projecting' |
| 159 | + the line is squared off as in *butt*, but the filled in area |
| 160 | + extends beyond the endpoint a distance of ``linewidth/2``. |
| 161 | + 'round' |
| 162 | + like *butt*, but a semicircular cap is added to the end of the |
| 163 | + line, of radius ``linewidth/2``. |
| 164 | +
|
| 165 | + .. plot:: |
| 166 | + :alt: Demo of possible CapStyle's |
| 167 | +
|
| 168 | + from matplotlib._enums import CapStyle |
| 169 | + CapStyle.demo() |
| 170 | +
|
| 171 | + """ |
| 172 | +butt='butt' |
| 173 | +projecting='projecting' |
| 174 | +round='round' |
| 175 | + |
| 176 | +def__init__(self,s): |
| 177 | +s=_deprecate_case_insensitive_join_cap(s) |
| 178 | +Enum.__init__(self) |
| 179 | + |
| 180 | +@staticmethod |
| 181 | +defdemo(): |
| 182 | +"""Demonstrate how each CapStyle looks for a thick line segment.""" |
| 183 | +importmatplotlib.pyplotasplt |
| 184 | + |
| 185 | +fig=plt.figure(figsize=(4,1.2)) |
| 186 | +ax=fig.add_axes([0,0,1,0.8]) |
| 187 | +ax.set_title('Cap style') |
| 188 | + |
| 189 | +forx,styleinenumerate(['butt','round','projecting']): |
| 190 | +ax.text(x+0.25,0.85,style,ha='center') |
| 191 | +xx= [x,x+0.5] |
| 192 | +yy= [0,0] |
| 193 | +ax.plot(xx,yy,lw=12,color='tab:blue',solid_capstyle=style) |
| 194 | +ax.plot(xx,yy,lw=1,color='black') |
| 195 | +ax.plot(xx,yy,'o',color='tab:red',markersize=3) |
| 196 | +ax.text(2.25,0.55,'(default)',ha='center') |
| 197 | + |
| 198 | +ax.set_ylim(-.5,1.5) |
| 199 | +ax.set_axis_off() |
| 200 | +fig.show() |
| 201 | + |
| 202 | + |
| 203 | +CapStyle.input_description="{" \ |
| 204 | ++", ".join([f"'{cs.name}'"forcsinCapStyle]) \ |
| 205 | ++"}" |
| 206 | + |
| 207 | +docstring.interpd.update({'JoinStyle':JoinStyle.input_description, |
| 208 | +'CapStyle':CapStyle.input_description}) |