Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d03a0a9

Browse filesBrowse files
committed
GSOD: hatch class
1 parent c858831 commit d03a0a9
Copy full SHA for d03a0a9

File tree

8 files changed

+254
-122
lines changed
Filter options

8 files changed

+254
-122
lines changed

‎doc/api/hatch_api.rst

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

‎doc/api/index.rst

Copy file name to clipboardExpand all lines: doc/api/index.rst
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ Matplotlib consists of the following submodules:
9393
font_manager_api.rst
9494
fontconfig_pattern_api.rst
9595
gridspec_api.rst
96+
hatch_api.rst
9697
image_api.rst
9798
legend_api.rst
9899
legend_handler_api.rst

‎lib/matplotlib/backend_bases.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backend_bases.py
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1025,7 +1025,7 @@ def get_hatch(self):
10251025
"""Get the current hatch style."""
10261026
return self._hatch
10271027

1028-
def get_hatch_path(self, density=6.0):
1028+
def get_hatch_path(self, density=None):
10291029
"""Return a `.Path` for the current hatch."""
10301030
hatch = self.get_hatch()
10311031
if hatch is None:

‎lib/matplotlib/collections.py

Copy file name to clipboardExpand all lines: lib/matplotlib/collections.py
+13-35Lines changed: 13 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515

1616
import matplotlib as mpl
1717
from . import (_api, _path, artist, cbook, cm, colors as mcolors, docstring,
18-
hatch as mhatch, lines as mlines, path as mpath, transforms)
18+
lines as mlines, path as mpath, transforms)
19+
from .hatch import Hatch
1920
from ._types import JoinStyle, CapStyle
2021
import warnings
2122

@@ -139,10 +140,9 @@ def __init__(self,
139140
Forwarded to `.ScalarMappable`. The default of
140141
``None`` will result in :rc:`image.cmap` being used.
141142
hatch : str, optional
142-
Hatching pattern to use in filled paths, if any. Valid strings are
143-
['/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*']. See
144-
:doc:`/gallery/shapes_and_collections/hatch_style_reference` for
145-
the meaning of each hatch type.
143+
Hatching pattern to use in filled paths, if any. Primitives
144+
available are %(Hatch)s. See `~.hatch.Hatch` for how to construct
145+
more complex hatch patterns.
146146
pickradius : float, default: 5.0
147147
If ``pickradius <= 0``, then `.Collection.contains` will return
148148
``True`` whenever the test point is inside of one of the polygons
@@ -492,44 +492,22 @@ def get_urls(self):
492492

493493
def set_hatch(self, hatch):
494494
r"""
495-
Set the hatching pattern
496-
497-
*hatch* can be one of::
498-
499-
/ - diagonal hatching
500-
\ - back diagonal
501-
| - vertical
502-
- - horizontal
503-
+ - crossed
504-
x - crossed diagonal
505-
o - small circle
506-
O - large circle
507-
. - dots
508-
* - stars
509-
510-
Letters can be combined, in which case all the specified
511-
hatchings are done. If same letter repeats, it increases the
512-
density of hatching of that pattern.
513-
514-
Hatching is supported in the PostScript, PDF, SVG and Agg
515-
backends only.
516-
517-
Unlike other properties such as linewidth and colors, hatching
518-
can only be specified for the collection as a whole, not separately
519-
for each member.
495+
Set the hatching pattern.
520496
521497
Parameters
522498
----------
523-
hatch : {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
499+
hatch : `.Hatch`-like or str
500+
The built-in hatching patterns are %(Hatch)s. Multiple hatch types
501+
can be combined (e.g. ``'|-'`` is equivalent to ``'+'``) and
502+
repeating a character increases the density of that pattern. For
503+
more advanced usage, see the `.Hatch` docs.
524504
"""
525-
# Use validate_hatch(list) after deprecation.
526-
mhatch._validate_hatch_pattern(hatch)
527-
self._hatch = hatch
505+
self._hatch = Hatch(hatch)
528506
self.stale = True
529507

530508
def get_hatch(self):
531509
"""Return the current hatching pattern."""
532-
return self._hatch
510+
return self._hatch._pattern_spec
533511

534512
def set_offsets(self, offsets):
535513
"""

‎lib/matplotlib/hatch.py

Copy file name to clipboardExpand all lines: lib/matplotlib/hatch.py
+197-35Lines changed: 197 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"""Contains classes for generating hatch patterns."""
2+
from collections.abc import Iterable
23

34
import numpy as np
45

5-
from matplotlib import cbook
6+
from matplotlib import _api, docstring
67
from matplotlib.path import Path
78

89

@@ -186,46 +187,207 @@ def __init__(self, hatch, density):
186187
]
187188

188189

189-
def _validate_hatch_pattern(hatch):
190-
valid_hatch_patterns = set(r'-+|/\xXoO.*')
191-
if hatch is not None:
192-
invalids = set(hatch).difference(valid_hatch_patterns)
193-
if invalids:
194-
valid = ''.join(sorted(valid_hatch_patterns))
195-
invalids = ''.join(sorted(invalids))
196-
cbook.warn_deprecated(
197-
'3.4',
198-
message=f'hatch must consist of a string of "{valid}" or '
199-
'None, but found the following invalid values '
200-
f'"{invalids}". Passing invalid values is deprecated '
201-
'since %(since)s and will become an error %(removal)s.'
202-
)
190+
class Hatch:
191+
r"""
192+
Pattern to be tiled within a filled area.
193+
194+
For a visual example of the available *Hatch* patterns, `view these docs
195+
online <Hatch>` or run `Hatch.demo`.
196+
197+
When making plots that contain multiple filled shapes, like :doc:`bar
198+
charts </gallery/lines_bars_and_markers/bar_stacked>` or filled
199+
:doc:`countour plots </images_contours_and_fields/contourf_hatching>`, it
200+
is common to use :doc:`color </tutorials/colors/colors>` to distinguish
201+
between areas. However, if color is not available, such as when printing in
202+
black and white, Matplotlib also supports hatching (i.e. filling each
203+
area with a unique repeating pattern or lines or shapes) in order to make
204+
it easy to refer to a specific filled bar, shape, or similar.
205+
206+
.. warning::
207+
Hatching is currently only supported in the Agg, PostScript, PDF, and
208+
SVG backends.
209+
210+
**Hatching patterns**
211+
212+
There hatching primitives built into Matplotlib are:
213+
214+
.. rst-class:: value-list
215+
216+
'-'
217+
Horizontal lines.
218+
'|'
219+
Vertical lines.
220+
'+'
221+
Crossed lines. ``'+'`` is equivalent to ``'-|'``.
222+
'\'
223+
Diagonal lines running northwest to southeast.
224+
'/'
225+
Diagonal lines running southwest to northeast.
226+
'x'
227+
Crossed diagonal lines. Equivalent to ``r'\/'``.
228+
'X'
229+
Synonym for ``'x'``.
230+
'.'
231+
Dots (i.e. very small, filled circles).
232+
'o'
233+
Small, unfilled circles.
234+
'O'
235+
Large, unfilled circles.
236+
'*'
237+
Filled star shape.
238+
239+
Hatching primitives can be combined to make more complicated patterns. For
240+
example, a hatch pattern of ``'*/|'`` would fill the area with vertical and
241+
diagonal lines as well as stars.
242+
243+
**Hatching Density**
244+
245+
By default, the hatching pattern is tiled so that there are **6** lines per
246+
inch (in display space), but this can be tuned (in integer increments)
247+
using the *density* kwarg to *Hatch*.
248+
249+
For convenience, the same symbol can also be repeated to request a higher
250+
hatching density. For example, ``'||-'`` will have twice as many vertical
251+
lines as ``'|-'``. Notice that since ``'|-'`` can also be written as
252+
``'+'``, we can also write ``'||-'`` as ``'|+'``.
253+
254+
Examples
255+
--------
256+
For more examples of how to use hatching, see `the hatching demo
257+
</gallery/shapes_and_collections/hatch_demo>` and `the contourf hatching
258+
demo </gallery/images_contours_and_fields/contourf_hatching>`.
259+
260+
.. plot::
261+
:alt: Demo showing each hatching primitive at its default density.
262+
263+
from matplotlib.hatch import Hatch
264+
Hatch.demo()
265+
"""
266+
267+
_default_density = 6
268+
_valid_hatch_patterns = set(r'-|+/\xX.oO*')
269+
270+
def __init__(self, pattern_spec, density=None):
271+
self.density = Hatch._default_density if density is None else density
272+
self._pattern_spec = pattern_spec
273+
self.patterns = self._validate_hatch_pattern(pattern_spec)
274+
self._build_path()
275+
276+
@classmethod
277+
def from_path(cls, path):
278+
hatch = cls(None, 0)
279+
hatch.path = path
280+
281+
def _build_path(self):
282+
# the API of HatchPatternBase was architected before Hatch, so instead
283+
# of simply returning Path's that we can concatenate using
284+
# Path.make_compound_path, we must pre-allocate the vertices array for
285+
# the final path up front. (The performance gain from this
286+
# preallocation is untested).
287+
num_vertices = sum([pattern.num_vertices for pattern in self.patterns])
288+
289+
if num_vertices == 0:
290+
self.path = Path(np.empty((0, 2)))
203291

292+
vertices = np.empty((num_vertices, 2))
293+
codes = np.empty(num_vertices, Path.code_type)
204294

295+
cursor = 0
296+
for pattern in self.patterns:
297+
if pattern.num_vertices != 0:
298+
vertices_chunk = vertices[cursor:cursor + pattern.num_vertices]
299+
codes_chunk = codes[cursor:cursor + pattern.num_vertices]
300+
pattern.set_vertices_and_codes(vertices_chunk, codes_chunk)
301+
cursor += pattern.num_vertices
302+
303+
self.path = Path(vertices, codes)
304+
305+
def _validate_hatch_pattern(self, patterns):
306+
if isinstance(patterns, Hatch):
307+
patterns = patterns._pattern_spec
308+
if patterns is None or patterns is []:
309+
return []
310+
elif isinstance(patterns, str):
311+
invalids = set(patterns).difference(Hatch._valid_hatch_patterns)
312+
if invalids:
313+
Hatch._warn_invalid_hatch(invalids)
314+
return [hatch_type(patterns, self.density)
315+
for hatch_type in _hatch_types]
316+
elif isinstance(patterns, Iterable) and np.all([
317+
isinstance(p, HatchPatternBase) for p in patterns]):
318+
return patterns
319+
else:
320+
raise ValueError(f"Cannot construct hatch pattern from {patterns}")
321+
322+
def _warn_invalid_hatch(invalids):
323+
valid = ''.join(sorted(Hatch._valid_hatch_patterns))
324+
invalids = ''.join(sorted(invalids))
325+
_api.warn_deprecated(
326+
'3.4',
327+
message=f'hatch must consist of a string of "{valid}" or None, '
328+
f'but found the following invalid values "{invalids}". '
329+
'Passing invalid values is deprecated since %(since)s and '
330+
'will become an error %(removal)s.'
331+
)
332+
333+
@staticmethod
334+
def demo(density=6):
335+
import matplotlib.pyplot as plt
336+
from matplotlib.patches import Rectangle
337+
fig = plt.figure()
338+
ax = fig.add_axes([0, 0, 1, 1])
339+
ax.set_axis_off()
340+
num_patches = len(Hatch._valid_hatch_patterns)
341+
342+
spacing = 0.1 # percent of width
343+
boxes_per_row = 4
344+
num_rows = np.ceil(num_patches / boxes_per_row)
345+
inter_box_dist_y = 1/num_rows
346+
posts = np.linspace(0, 1, boxes_per_row + 1)
347+
inter_box_dist_x = posts[1] - posts[0]
348+
font_size = 12
349+
fig_size = (4, 4)
350+
text_pad = 0.2 # fraction of text height
351+
text_height = (1 + text_pad)*(
352+
fig.dpi_scale_trans + ax.transAxes.inverted()
353+
).transform([1, 1])[1]
354+
# half of text pad
355+
bottom_padding = text_height*(1 - (1/(1+text_pad)))/2
356+
357+
for i, hatch in enumerate(Hatch._valid_hatch_patterns):
358+
row = int(i/boxes_per_row)
359+
col = i - row*boxes_per_row
360+
ax.add_patch(Rectangle(
361+
xy=[(col + spacing/2) * inter_box_dist_x,
362+
bottom_padding + row*inter_box_dist_y],
363+
width=inter_box_dist_x*(1 - spacing),
364+
height=inter_box_dist_y*(1 - text_height),
365+
transform=ax.transAxes,
366+
hatch=hatch,
367+
label="'" + hatch + "'"
368+
))
369+
ax.text((col + 1/2) * inter_box_dist_x,
370+
bottom_padding + (-text_height*(1/(1+text_pad)) + row
371+
+ 1)*inter_box_dist_y,
372+
"'" + hatch + "'", horizontalalignment='center',
373+
fontsize=font_size)
374+
375+
376+
Hatch.input_description = "{" \
377+
+ ", ".join([f"'{p}'" for p in Hatch._valid_hatch_patterns]) \
378+
+ "}"
379+
380+
381+
docstring.interpd.update({'Hatch': Hatch.input_description})
382+
383+
384+
@_api.deprecated("3.4")
205385
def get_path(hatchpattern, density=6):
206386
"""
207387
Given a hatch specifier, *hatchpattern*, generates Path to render
208388
the hatch in a unit square. *density* is the number of lines per
209389
unit square.
210390
"""
211-
density = int(density)
212-
213-
patterns = [hatch_type(hatchpattern, density)
214-
for hatch_type in _hatch_types]
215-
num_vertices = sum([pattern.num_vertices for pattern in patterns])
216-
217-
if num_vertices == 0:
218-
return Path(np.empty((0, 2)))
219-
220-
vertices = np.empty((num_vertices, 2))
221-
codes = np.empty(num_vertices, Path.code_type)
222-
223-
cursor = 0
224-
for pattern in patterns:
225-
if pattern.num_vertices != 0:
226-
vertices_chunk = vertices[cursor:cursor + pattern.num_vertices]
227-
codes_chunk = codes[cursor:cursor + pattern.num_vertices]
228-
pattern.set_vertices_and_codes(vertices_chunk, codes_chunk)
229-
cursor += pattern.num_vertices
391+
return Hatch(hatchpattern).path
230392

231-
return Path(vertices, codes)
393+
docstring

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.