Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d2de8a2

Browse files
committed
REORG: JoinStyle and CapStyle classes
Breaking API, use these class instances everywhere that we used the strings internally before.
1 parent 1233840 commit d2de8a2

19 files changed

+359
-262
lines changed

doc/api/_types.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
**********************
2+
``matplotlib._types``
3+
**********************
4+
5+
.. automodule:: matplotlib._types
6+
:members:
7+
:undoc-members:
8+
:show-inheritance:
9+

doc/api/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ Matplotlib consists of the following submodules:
124124
transformations.rst
125125
tri_api.rst
126126
type1font.rst
127+
_types.rst
127128
units_api.rst
128129
widgets_api.rst
129130
_api_api.rst

examples/lines_bars_and_markers/joinstyle.py

Lines changed: 0 additions & 90 deletions
This file was deleted.

lib/matplotlib/_types.py

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
"""
2+
Style description information that is shared across unrelated classses.
3+
"""
4+
5+
from enum import Enum, auto
6+
from matplotlib import cbook
7+
8+
9+
class _AutoStringNameEnum(Enum):
10+
"""Automate the ``name = 'name'`` part of making a (str, Enum)."""
11+
def _generate_next_value_(name, start, count, last_values):
12+
return name
13+
14+
15+
def _deprecate_case_insensitive_join_cap(s):
16+
s_low = s.lower()
17+
if s != s_low:
18+
if s_low in ['miter', 'round', 'bevel']:
19+
cbook.warn_deprecated(
20+
"3.3", message="Case-insensitive capstyles are deprecated "
21+
"since %(since)s and support for them will be removed "
22+
"%(removal)s; please pass them in lowercase.")
23+
elif s_low in ['butt', 'round', 'projecting']:
24+
cbook.warn_deprecated(
25+
"3.3", message="Case-insensitive joinstyles are deprecated "
26+
"since %(since)s and support for them will be removed "
27+
"%(removal)s; please pass them in lowercase.")
28+
# Else, error out at the check_in_list stage.
29+
return s_low
30+
31+
32+
class JoinStyle(str, _AutoStringNameEnum):
33+
"""
34+
Define how the connection between two line segments is drawn.
35+
36+
For a visual impression of each *JoinStyle*, `view these docs online
37+
<JoinStyle>`, or run `JoinStyle.demo`:
38+
39+
.. plot::
40+
:alt: Demo of possible JoinStyle's
41+
42+
from matplotlib._types import JoinStyle
43+
JoinStyle.demo()
44+
45+
Lines in Matplotlib are typically defined by a 1D `~.path.Path` and a
46+
finite ``linewidth``, where the underlying 1D `~.path.Path` represents the
47+
center of the stroked line.
48+
49+
By default, `~.backend_bases.GraphicsContextBase` defines the boundaries of
50+
a stroked line to simply be every point within some radius,
51+
``linewidth/2``, away from any point of the center line. However, this
52+
results in corners appearing "rounded", which may not be the desired
53+
behavior if you are drawing, for example, a polygon or pointed star.
54+
55+
Matplotlib provides three options for drawing the corners between adjacent
56+
segments. In short:
57+
58+
- *miter* is the "arrow-tip" style. Each boundary of the filled-in area
59+
will extend in a straight line parallel to the tangent vector of the
60+
centerline at the point it meets the corner, until they meet in a
61+
sharp point.
62+
- *round* stokes every point within a radius of ``linewidth/2`` of the
63+
center lines.
64+
- *bevel* is the "squared-off" style. It can be thought of as a rounded
65+
corner where the "circular" part of the corner has been cut off.
66+
67+
.. note::
68+
69+
The *miter* option can be controlled further by specifying a "miter
70+
limit", which specifies how long a miter tip can get before it is
71+
automatically "bevel"ed off. Matplotlib does not currently expose a
72+
``miterlimit`` parameter to the user, and most backends simply use the
73+
upstream default value. For example, the PDF backend assumes the
74+
default value of 10 specified by the PDF standard, while the SVG
75+
backend does not even specify the miter limit, resulting in a default
76+
value of 4 per the SVG specification.
77+
78+
A more detailed description of the effect of a miter limit can be found
79+
in the `Mozilla Developer Docs
80+
<https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-miterlimit>`_
81+
"""
82+
83+
miter = auto()
84+
round = auto()
85+
bevel = auto()
86+
87+
def __init__(self, s):
88+
s = _deprecate_case_insensitive_join_cap(s)
89+
Enum.__init__(self)
90+
91+
@staticmethod
92+
def demo():
93+
import numpy as np
94+
import matplotlib.pyplot as plt
95+
96+
def plot_angle(ax, x, y, angle, style):
97+
phi = np.radians(angle)
98+
xx = [x + .5, x, x + .5*np.cos(phi)]
99+
yy = [y, y, y + .5*np.sin(phi)]
100+
ax.plot(xx, yy, lw=12, color='tab:blue', solid_joinstyle=style)
101+
ax.plot(xx, yy, lw=1, color='black')
102+
ax.plot(xx[1], yy[1], 'o', color='tab:red', markersize=3)
103+
104+
fig, ax = plt.subplots(figsize=(8, 6))
105+
ax.set_title('Join style')
106+
for x, style in enumerate(['miter', 'round', 'bevel']):
107+
ax.text(x, 5, style)
108+
for y, angle in enumerate([20, 45, 60, 90, 120]):
109+
plot_angle(ax, x, y, angle, style)
110+
if x == 0:
111+
ax.text(-1.3, y, f'{angle} degrees')
112+
ax.set_xlim(-1.5, 2.75)
113+
ax.set_ylim(-.5, 5.5)
114+
ax.set_axis_off()
115+
fig.show()
116+
117+
118+
class CapStyle(str, _AutoStringNameEnum):
119+
r"""
120+
Define how the two endpoints (caps) of an unclosed line are drawn.
121+
122+
How to draw the start and end points of lines that represent a closed curve
123+
(i.e. that end in a `~.path.Path.CLOSEPOLY`) is controlled by the line's
124+
`JoinStyle`. For all other lines, how the start and end points are drawn is
125+
controlled by the *CapStyle*.
126+
127+
For a visual impression of each *CapStyle*, `view these docs online
128+
<CapStyle>` or run `CapStyle.demo`:
129+
130+
.. plot::
131+
:alt: Demo of possible CapStyle's
132+
133+
from matplotlib._types import CapStyle
134+
CapStyle.demo()
135+
136+
Available options:
137+
138+
- *butt*: the line is squared off at its endpoint.
139+
- *projecting*: the line is squared off as in *butt*, but the filled in
140+
area extends beyond the endpoint a distance of ``linewidth/2``.
141+
- *round*: like *butt*, but a semicircular cap is added to the end of
142+
the line, of radius ``linewidth/2``.
143+
"""
144+
butt = 'butt'
145+
projecting = 'projecting'
146+
round = 'round'
147+
148+
def __init__(self, s):
149+
s = _deprecate_case_insensitive_join_cap(s)
150+
Enum.__init__(self)
151+
152+
@staticmethod
153+
def demo():
154+
import matplotlib.pyplot as plt
155+
156+
fig, ax = plt.subplots(figsize=(8, 2))
157+
ax.set_title('Cap style')
158+
159+
for x, style in enumerate(['butt', 'round', 'projecting']):
160+
ax.text(x+0.25, 1, style, ha='center')
161+
xx = [x, x+0.5]
162+
yy = [0, 0]
163+
ax.plot(xx, yy, lw=12, color='tab:blue', solid_capstyle=style)
164+
ax.plot(xx, yy, lw=1, color='black')
165+
ax.plot(xx, yy, 'o', color='tab:red', markersize=3)
166+
ax.text(2.25, 0.7, '(default)', ha='center')
167+
168+
ax.set_ylim(-.5, 1.5)
169+
ax.set_axis_off()
170+
fig.show()

lib/matplotlib/backend_bases.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@
5050
from matplotlib.backend_managers import ToolManager
5151
from matplotlib.cbook import _setattr_cm
5252
from matplotlib.path import Path
53-
from matplotlib.rcsetup import validate_joinstyle, validate_capstyle
5453
from matplotlib.transforms import Affine2D
54+
from matplotlib._types import JoinStyle, CapStyle
5555

5656

5757
_log = logging.getLogger(__name__)
@@ -765,11 +765,11 @@ def __init__(self):
765765
self._alpha = 1.0
766766
self._forced_alpha = False # if True, _alpha overrides A from RGBA
767767
self._antialiased = 1 # use 0, 1 not True, False for extension code
768-
self._capstyle = 'butt'
768+
self._capstyle = CapStyle('butt')
769769
self._cliprect = None
770770
self._clippath = None
771771
self._dashes = 0, None
772-
self._joinstyle = 'round'
772+
self._joinstyle = JoinStyle('round')
773773
self._linestyle = 'solid'
774774
self._linewidth = 1
775775
self._rgb = (0.0, 0.0, 0.0, 1.0)
@@ -820,9 +820,7 @@ def get_antialiased(self):
820820
return self._antialiased
821821

822822
def get_capstyle(self):
823-
"""
824-
Return the capstyle as a string in ('butt', 'round', 'projecting').
825-
"""
823+
"""Return the `.CapStyle`."""
826824
return self._capstyle
827825

828826
def get_clip_rectangle(self):
@@ -867,7 +865,7 @@ def get_forced_alpha(self):
867865
return self._forced_alpha
868866

869867
def get_joinstyle(self):
870-
"""Return the line join style as one of ('miter', 'round', 'bevel')."""
868+
"""Return the `.JoinStyle`."""
871869
return self._joinstyle
872870

873871
def get_linewidth(self):
@@ -920,9 +918,14 @@ def set_antialiased(self, b):
920918
self._antialiased = int(bool(b))
921919

922920
def set_capstyle(self, cs):
923-
"""Set the capstyle to be one of ('butt', 'round', 'projecting')."""
924-
validate_capstyle(cs)
925-
self._capstyle = cs
921+
"""
922+
Set how to draw endpoints of lines.
923+
924+
Parameters
925+
----------
926+
cs : `.CapStyle` or {'butt', 'round', 'projecting'}
927+
"""
928+
self._capstyle = CapStyle(cs)
926929

927930
def set_clip_rectangle(self, rectangle):
928931
"""Set the clip rectangle to a `.Bbox` or None."""
@@ -980,9 +983,14 @@ def set_foreground(self, fg, isRGBA=False):
980983
self._rgb = colors.to_rgba(fg)
981984

982985
def set_joinstyle(self, js):
983-
"""Set the join style to be one of ('miter', 'round', 'bevel')."""
984-
validate_joinstyle(js)
985-
self._joinstyle = js
986+
"""
987+
Set how to draw connections between line segments.
988+
989+
Parameters
990+
----------
991+
js : `.JoinStyle` or {'miter', 'round', 'bevel'}.
992+
"""
993+
self._joinstyle = JoinStyle(js)
986994

987995
def set_linewidth(self, w):
988996
"""Set the linewidth in points."""

0 commit comments

Comments
 (0)