Repository navigation
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| """ | ||
| ========= | ||
| CapStyle | ||
| ========= | ||
|
|
||
| The `matplotlib._types.CapStyle` controls how Matplotlib draws the corners | ||
| where two different line segments meet. For more details, see the | ||
| `~matplotlib._types.CapStyle` docs. | ||
| """ | ||
|
|
||
| import matplotlib.pyplot as plt | ||
| from matplotlib._types import CapStyle | ||
|
|
||
| CapStyle.demo() | ||
| plt.show() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| """ | ||
| ========= | ||
| JoinStyle | ||
| ========= | ||
|
|
||
| The `matplotlib._types.JoinStyle` controls how Matplotlib draws the corners | ||
| where two different line segments meet. For more details, see the | ||
| `~matplotlib._types.JoinStyle` docs. | ||
| """ | ||
|
|
||
| import matplotlib.pyplot as plt | ||
| from matplotlib._types import JoinStyle | ||
|
|
||
| JoinStyle.demo() | ||
| plt.show() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,16 +1,28 @@ | ||
| """ | ||
| Style description information that is shared across unrelated classses. | ||
| Matplotlib API concepts that would not otherwise merit a dedicated class. | ||
|
|
||
| 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 | ||
| 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 | ||
|
Contributor
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. May be worth noting that this will become unneeded (it is the default behavior) in Py3.10 per https://bugs.python.org/issue42385. |
||
|
|
||
| def __hash__(self): | ||
| return str(self).__hash__() | ||
|
|
||
|
|
||
| def _deprecate_case_insensitive_join_cap(s): | ||
| s_low = s.lower() | ||
|
|
@@ -34,13 +46,7 @@ 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`: | ||
|
|
||
| .. plot:: | ||
| :alt: Demo of possible JoinStyle's | ||
|
|
||
| from matplotlib._types import JoinStyle | ||
| JoinStyle.demo() | ||
| <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 | ||
|
|
@@ -52,32 +58,42 @@ class JoinStyle(str, _AutoStringNameEnum): | |
| results in corners appearing "rounded", which may not be the desired | ||
| behavior if you are drawing, for example, a polygon or pointed star. | ||
|
|
||
| Matplotlib provides three options for drawing the corners between adjacent | ||
| segments. In short: | ||
| **Supported values:** | ||
|
|
||
| .. rst-class:: value-list | ||
|
|
||
| - *miter* is 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* is the "squared-off" style. It can be thought of as a rounded | ||
| corner where the "circular" part of the corner has been cut off. | ||
| '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:: | ||
|
|
||
| The *miter* option can be controlled further by specifying a "miter | ||
| limit", which specifies how long a miter tip can get before it is | ||
| automatically "bevel"ed off. Matplotlib does not currently expose a | ||
| ``miterlimit`` parameter to the user, and most backends simply use the | ||
| upstream default value. For example, the PDF backend assumes 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. | ||
| 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._types import JoinStyle | ||
| JoinStyle.demo() | ||
|
|
||
| """ | ||
|
|
||
| miter = auto() | ||
|
|
@@ -90,6 +106,7 @@ def __init__(self, s): | |
|
|
||
| @staticmethod | ||
| def demo(): | ||
| """Demonstrate how each JoinStyle looks for various join angles.""" | ||
| import numpy as np | ||
| import matplotlib.pyplot as plt | ||
|
|
||
|
|
@@ -101,7 +118,7 @@ def plot_angle(ax, x, y, angle, 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=(8, 6)) | ||
| 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) | ||
|
|
@@ -115,6 +132,11 @@ def plot_angle(ax, x, y, angle, style): | |
| fig.show() | ||
|
|
||
|
|
||
| JoinStyle.input_description = "{" \ | ||
| + ", ".join([f"'{js.name}'" for js in JoinStyle]) \ | ||
| + "}" | ||
|
|
||
|
|
||
| class CapStyle(str, _AutoStringNameEnum): | ||
|
Member
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'm not particularly happy with the overall appearance of the docs (https://48026-1385122-gh.circle-artifacts.com/0/doc/build/html/api/_types.html#matplotlib._types.CapStyle). It looks a bit cluttered:
Contributor
Author
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 agree that the output looks cluttered. I've:
Member
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. The above are good steps in the right direction, but I'm still somewhat worried that the values are difficult to find. They blend into the paragraphs of the bullet list. Visibility could be further enhanced with a definition list. E.g. Will result in resulting in: This is the lightweight version of making your own |
||
| r""" | ||
| Define how the two endpoints (caps) of an unclosed line are drawn. | ||
|
|
@@ -125,21 +147,27 @@ class CapStyle(str, _AutoStringNameEnum): | |
| controlled by the *CapStyle*. | ||
|
|
||
| For a visual impression of each *CapStyle*, `view these docs online | ||
| <CapStyle>` or run `CapStyle.demo`: | ||
| <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._types import CapStyle | ||
| CapStyle.demo() | ||
|
|
||
| Available options: | ||
|
|
||
| - *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``. | ||
| """ | ||
| butt = 'butt' | ||
| projecting = 'projecting' | ||
|
|
@@ -151,20 +179,30 @@ def __init__(self, s): | |
|
|
||
| @staticmethod | ||
| def demo(): | ||
| """Demonstrate how each CapStyle looks for a thick line segment.""" | ||
| import matplotlib.pyplot as plt | ||
|
|
||
| fig, ax = plt.subplots(figsize=(8, 2)) | ||
| 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, 1, style, ha='center') | ||
| 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.7, '(default)', ha='center') | ||
| 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}) | ||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok for now.
When we get more entries, every entry should probably get it's own sub-page. But since we might fiddle with the organization/representation anyway (c.f. sphinx-gallery), it's not worth to work on this right now.