Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork7.9k
REORG: JoinStyle and CapStyle classes#18544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
********************** | ||
``matplotlib._enums`` | ||
********************** | ||
.. automodule:: matplotlib._enums | ||
:no-members: | ||
.. autoclass:: JoinStyle | ||
:members: demo | ||
:exclude-members: bevel, miter, round, input_description | ||
.. autoclass:: CapStyle | ||
:members: demo | ||
:exclude-members: butt, round, projecting, input_description | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
""" | ||
========= | ||
CapStyle | ||
========= | ||
The `matplotlib._enums.CapStyle` controls how Matplotlib draws the corners | ||
where two different line segments meet. For more details, see the | ||
`~matplotlib._enums.CapStyle` docs. | ||
""" | ||
import matplotlib.pyplot as plt | ||
from matplotlib._enums import CapStyle | ||
CapStyle.demo() | ||
plt.show() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,90 +1,15 @@ | ||
""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Why was this example deleted? If you moved the docs to a class defn, fine, but leave the stub here with a link to the docs? Maybe w/ a small minimal example? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. I didn't feel like it made sense to have the exact same example in two different places. My goal with these API docs was to be a strictly-better drop-in replacement for this example. Is the concern here that the code that makes (what is now) the Is the concern discoverability? I know that we have issues with Google sending people to old versions of the docs, but presumably the hope is that the new page quickly gets indexed as the go-to place for JoinStyle. In which case the relevant example figure will still be there. If the concern is that people looking for that specific example will be confused as to where it went, then my impression of what's the best way to leave a "stub" behind is, instead of leaving an actual stub page with a link, we should really just use something likethe reredirects package to simply have an HTTP 301 response whenever someone tries to visit that page. As a side-effect this will also help with Google search indexing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Something like the redirects package looks very interesting, though version 0.0.0 is a negative. But the other concern is that the example will no longer will show up in the example gallery... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Haha fair, didn't realize the version number was so sketch, but frankly I can white room that package in a couple hours if we wanted to have our own implementation. Gitlab reports that the whole "package" is only 62 lines of Python code. Was mostly linking it as a proof-of-principle that this is not impossible to do inside of Sphinx. This may be totally off-base, but I struggle to imagine the user that scrolls through the examples gallery and is enticed to click on the JoinStyle demo in particular. Unless you know what it is already? But people that already know the name for something typically find examples by getting directly linked in via Google... If I'm outvoted on that point, I guess we would just add two stub examples, one which just calls There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. If you are browsing the examples, and come across it you learn something new. If you don't know what a join style is, you can never google it. People needsome way to know about the features in the library, and the example pages are basically it. If you just want to have it call and link the class demo, thats perhaps fine. Then the plot shows up, and the user is linked to complete docs. But I think leaving it in as an example in the gallery is useful. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. I think adding redirects is not the issue, but collating through the hundreds of old versions is a chore. As for examples, I thought there was some talk of putting a smaller set of examples for all plot types, and maybe we could do the same for all these new style classes? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. ^ that would be great. However I don't think we should delete existing examples until that is created? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. 👍 for leaving stub examples and linking to the class. and later collecting these examples in a dedicated section. (This is for discoverability rather than for keeping links alive). | ||
========= | ||
JoinStyle | ||
========= | ||
The `matplotlib._enums.JoinStyle` controls how Matplotlib draws the corners | ||
where two different line segments meet. For more details, see the | ||
`~matplotlib._enums.JoinStyle` docs. | ||
""" | ||
import matplotlib.pyplot as plt | ||
from matplotlib._enums import JoinStyle | ||
JoinStyle.demo() | ||
plt.show() | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
""" | ||
Enums representing sets of strings that Matplotlib uses as input parameters. | ||
Matplotlib often uses simple data types like strings or tuples to define a | ||
concept; e.g. the line capstyle can be specified as one of 'butt', 'round', | ||
or 'projecting'. The classes in this module are used internally and serve to | ||
document these concepts formally. | ||
As an end-user you will not use these classes directly, but only the values | ||
they define. | ||
""" | ||
from enum import Enum, auto | ||
from matplotlib import cbook, docstring | ||
class _AutoStringNameEnum(Enum): | ||
"""Automate the ``name = 'name'`` part of making a (str, Enum).""" | ||
def _generate_next_value_(name, start, count, last_values): | ||
return name | ||
def __hash__(self): | ||
return str(self).__hash__() | ||
def _deprecate_case_insensitive_join_cap(s): | ||
s_low = s.lower() | ||
if s != s_low: | ||
if s_low in ['miter', 'round', 'bevel']: | ||
cbook.warn_deprecated( | ||
"3.3", message="Case-insensitive capstyles are deprecated " | ||
"since %(since)s and support for them will be removed " | ||
"%(removal)s; please pass them in lowercase.") | ||
elif s_low in ['butt', 'round', 'projecting']: | ||
cbook.warn_deprecated( | ||
"3.3", message="Case-insensitive joinstyles are deprecated " | ||
"since %(since)s and support for them will be removed " | ||
"%(removal)s; please pass them in lowercase.") | ||
# Else, error out at the check_in_list stage. | ||
return s_low | ||
class JoinStyle(str, _AutoStringNameEnum): | ||
""" | ||
Define how the connection between two line segments is drawn. | ||
For a visual impression of each *JoinStyle*, `view these docs online | ||
<JoinStyle>`, or run `JoinStyle.demo`. | ||
Lines in Matplotlib are typically defined by a 1D `~.path.Path` and a | ||
finite ``linewidth``, where the underlying 1D `~.path.Path` represents the | ||
center of the stroked line. | ||
By default, `~.backend_bases.GraphicsContextBase` defines the boundaries of | ||
a stroked line to simply be every point within some radius, | ||
``linewidth/2``, away from any point of the center line. However, this | ||
results in corners appearing "rounded", which may not be the desired | ||
behavior if you are drawing, for example, a polygon or pointed star. | ||
**Supported values:** | ||
.. rst-class:: value-list | ||
'miter' | ||
the "arrow-tip" style. Each boundary of the filled-in area will | ||
extend in a straight line parallel to the tangent vector of the | ||
centerline at the point it meets the corner, until they meet in a | ||
sharp point. | ||
'round' | ||
stokes every point within a radius of ``linewidth/2`` of the center | ||
lines. | ||
'bevel' | ||
the "squared-off" style. It can be thought of as a rounded corner | ||
where the "circular" part of the corner has been cut off. | ||
.. note:: | ||
Very long miter tips are cut off (to form a *bevel*) after a | ||
backend-dependent limit called the "miter limit", which specifies the | ||
maximum allowed ratio of miter length to line width. For example, the | ||
PDF backend uses the default value of 10 specified by the PDF standard, | ||
while the SVG backend does not even specify the miter limit, resulting | ||
in a default value of 4 per the SVG specification. Matplotlib does not | ||
currently allow the user to adjust this parameter. | ||
A more detailed description of the effect of a miter limit can be found | ||
in the `Mozilla Developer Docs | ||
<https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-miterlimit>`_ | ||
.. plot:: | ||
:alt: Demo of possible JoinStyle's | ||
from matplotlib._enums import JoinStyle | ||
JoinStyle.demo() | ||
""" | ||
miter = auto() | ||
round = auto() | ||
bevel = auto() | ||
def __init__(self, s): | ||
s = _deprecate_case_insensitive_join_cap(s) | ||
Enum.__init__(self) | ||
@staticmethod | ||
def demo(): | ||
"""Demonstrate how each JoinStyle looks for various join angles.""" | ||
import numpy as np | ||
import matplotlib.pyplot as plt | ||
def plot_angle(ax, x, y, angle, style): | ||
phi = np.radians(angle) | ||
xx = [x + .5, x, x + .5*np.cos(phi)] | ||
yy = [y, y, y + .5*np.sin(phi)] | ||
ax.plot(xx, yy, lw=12, color='tab:blue', solid_joinstyle=style) | ||
ax.plot(xx, yy, lw=1, color='black') | ||
ax.plot(xx[1], yy[1], 'o', color='tab:red', markersize=3) | ||
fig, ax = plt.subplots(figsize=(5, 4), constrained_layout=True) | ||
ax.set_title('Join style') | ||
for x, style in enumerate(['miter', 'round', 'bevel']): | ||
ax.text(x, 5, style) | ||
for y, angle in enumerate([20, 45, 60, 90, 120]): | ||
plot_angle(ax, x, y, angle, style) | ||
if x == 0: | ||
ax.text(-1.3, y, f'{angle} degrees') | ||
ax.set_xlim(-1.5, 2.75) | ||
ax.set_ylim(-.5, 5.5) | ||
ax.set_axis_off() | ||
fig.show() | ||
JoinStyle.input_description = "{" \ | ||
+ ", ".join([f"'{js.name}'" for js in JoinStyle]) \ | ||
+ "}" | ||
class CapStyle(str, _AutoStringNameEnum): | ||
r""" | ||
Define how the two endpoints (caps) of an unclosed line are drawn. | ||
How to draw the start and end points of lines that represent a closed curve | ||
(i.e. that end in a `~.path.Path.CLOSEPOLY`) is controlled by the line's | ||
`JoinStyle`. For all other lines, how the start and end points are drawn is | ||
controlled by the *CapStyle*. | ||
For a visual impression of each *CapStyle*, `view these docs online | ||
<CapStyle>` or run `CapStyle.demo`. | ||
**Supported values:** | ||
.. rst-class:: value-list | ||
'butt' | ||
the line is squared off at its endpoint. | ||
'projecting' | ||
the line is squared off as in *butt*, but the filled in area | ||
extends beyond the endpoint a distance of ``linewidth/2``. | ||
'round' | ||
like *butt*, but a semicircular cap is added to the end of the | ||
line, of radius ``linewidth/2``. | ||
.. plot:: | ||
:alt: Demo of possible CapStyle's | ||
from matplotlib._enums import CapStyle | ||
CapStyle.demo() | ||
""" | ||
butt = 'butt' | ||
projecting = 'projecting' | ||
round = 'round' | ||
def __init__(self, s): | ||
s = _deprecate_case_insensitive_join_cap(s) | ||
Enum.__init__(self) | ||
@staticmethod | ||
def demo(): | ||
"""Demonstrate how each CapStyle looks for a thick line segment.""" | ||
import matplotlib.pyplot as plt | ||
fig = plt.figure(figsize=(4, 1.2)) | ||
ax = fig.add_axes([0, 0, 1, 0.8]) | ||
ax.set_title('Cap style') | ||
for x, style in enumerate(['butt', 'round', 'projecting']): | ||
ax.text(x+0.25, 0.85, style, ha='center') | ||
xx = [x, x+0.5] | ||
yy = [0, 0] | ||
ax.plot(xx, yy, lw=12, color='tab:blue', solid_capstyle=style) | ||
ax.plot(xx, yy, lw=1, color='black') | ||
ax.plot(xx, yy, 'o', color='tab:red', markersize=3) | ||
ax.text(2.25, 0.55, '(default)', ha='center') | ||
ax.set_ylim(-.5, 1.5) | ||
ax.set_axis_off() | ||
fig.show() | ||
CapStyle.input_description = "{" \ | ||
+ ", ".join([f"'{cs.name}'" for cs in CapStyle]) \ | ||
+ "}" | ||
docstring.interpd.update({'JoinStyle': JoinStyle.input_description, | ||
'CapStyle': CapStyle.input_description}) |
Uh oh!
There was an error while loading.Please reload this page.