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 55c4380

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

File tree

1 file changed

+178
-36
lines changed
Filter options

1 file changed

+178
-36
lines changed

‎lib/matplotlib/hatch.py

Copy file name to clipboardExpand all lines: lib/matplotlib/hatch.py
+178-36Lines changed: 178 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import numpy as np
44

5-
from matplotlib import cbook
5+
from matplotlib import _api
66
from matplotlib.path import Path
77

88

@@ -186,46 +186,188 @@ def __init__(self, hatch, density):
186186
]
187187

188188

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-
)
189+
class Hatch:
190+
r"""
191+
Pattern to be tiled within a filled area.
192+
193+
For a visual example of the available *Hatch* patterns, `view these docs
194+
online <Hatch>` or run `Hatch.demo`.
195+
196+
When making plots that contain multiple filled shapes, like :doc:`bar
197+
charts </gallery/lines_bars_and_markers/bar_stacked>` or filled
198+
:doc:`countour plots </images_contours_and_fields/contourf_hatching>`, it
199+
is common to use :doc:`color </tutorials/colors/colors>` to distinguish
200+
between areas. However, if color is not available, such as when printing in
201+
black and white, Matplotlib also supports hatching (i.e. filling each
202+
area with a unique repeating pattern or lines or shapes) in order to make
203+
it easy to refer to a specific filled bar, shape, or similar.
204+
205+
.. warning::
206+
Hatching is currently only supported in the Agg, PostScript, PDF, and
207+
SVG backends.
208+
209+
**Hatching patterns**
210+
211+
There hatching primitives built into Matplotlib are:
212+
213+
.. rst-class:: value-list
214+
215+
'-'
216+
Horizontal lines.
217+
'|'
218+
Vertical lines.
219+
'+'
220+
Crossed lines. ``'+'`` is equivalent to ``'-|'``.
221+
'\'
222+
Diagonal lines running northwest to southeast.
223+
'/'
224+
Diagonal lines running southwest to northeast.
225+
'x'
226+
Crossed diagonal lines. Equivalent to ``r'\/'``.
227+
'X'
228+
Synonym for ``'x'``.
229+
'.'
230+
Dots (i.e. very small, filled circles).
231+
'o'
232+
Small, unfilled circles.
233+
'O'
234+
Large, unfilled circles.
235+
'*'
236+
Filled star shape.
237+
238+
Hatching primitives can be combined to make more complicated patterns. For
239+
example, a hatch pattern of '*/|' would fill the area with vertical and
240+
diagonal lines as well as stars.
241+
242+
**Hatching Density**
243+
244+
By default, the hatching pattern is tiled so that there are **6** lines per
245+
inch (in display space), but this can be tuned (in integer increments)
246+
using the *density* kwarg to *Hatch*.
247+
248+
For convenience, the same symbol can also be repeated to request a higher
249+
hatching density. For example, ``'||-'`` will have twice as many vertical
250+
lines as ``'|-'``. Notice that since ``'|-'`` can also be written as
251+
``'+'``, we can also write ``'||-'`` as ``'|+'``.
252+
253+
Examples
254+
--------
255+
For more examples of how to use hatching, see `the hatching demo
256+
</gallery/shapes_and_collections/hatch_demo>` and `the contourf hatching
257+
demo </gallery/images_contours_and_fields/contourf_hatching>`.
258+
259+
.. plot::
260+
:alt: Demo showing each hatching primitive at its default density.
261+
262+
from matplotlib.hatch import Hatch
263+
Hatch.demo()
264+
"""
265+
266+
_valid_hatch_patterns = set(r'-|+/\xX.oO*')
267+
268+
def __init__(self, pattern_spec, density=6):
269+
self.density = density
270+
self._pattern_spec = pattern_spec
271+
self.patterns = self._validate_hatch_pattern(pattern_spec)
272+
self._build_path()
273+
274+
@classmethod
275+
def from_path(cls, path):
276+
hatch = cls(None, 0)
277+
hatch.path = path
203278

279+
def _build_path(self):
280+
num_vertices = sum([pattern.num_vertices for pattern in self.patterns])
204281

282+
if num_vertices == 0:
283+
return Path(np.empty((0, 2)))
284+
285+
vertices = np.empty((num_vertices, 2))
286+
codes = np.empty(num_vertices, Path.code_type)
287+
288+
cursor = 0
289+
for pattern in self.patterns:
290+
if pattern.num_vertices != 0:
291+
vertices_chunk = vertices[cursor:cursor + pattern.num_vertices]
292+
codes_chunk = codes[cursor:cursor + pattern.num_vertices]
293+
pattern.set_vertices_and_codes(vertices_chunk, codes_chunk)
294+
cursor += pattern.num_vertices
295+
296+
self.path = Path(vertices, codes)
297+
298+
def _validate_hatch_pattern(self, patterns):
299+
if patterns is None:
300+
return []
301+
elif isinstance(patterns, str):
302+
invalids = set(patterns).difference(Hatch._valid_hatch_patterns)
303+
if invalids:
304+
Hatch._warn_invalid_hatch(invalids)
305+
return [hatch_type(patterns, self.density)
306+
for hatch_type in _hatch_types]
307+
elif np.all([isinstance(p, HatchPatternBase) for p in patterns]):
308+
return patterns
309+
else:
310+
raise ValueError(f"Cannot construct hatch pattern from {patterns}")
311+
312+
def _warn_invalid_hatch(invalids):
313+
valid = ''.join(sorted(Hatch._valid_hatch_patterns))
314+
invalids = ''.join(sorted(invalids))
315+
_api.warn_deprecated(
316+
'3.4',
317+
message=f'hatch must consist of a string of "{valid}" or None, '
318+
f'but found the following invalid values "{invalids}". '
319+
'Passing invalid values is deprecated since %(since)s and '
320+
'will become an error %(removal)s.'
321+
)
322+
323+
@staticmethod
324+
def demo(density=6):
325+
import matplotlib.pyplot as plt
326+
from matplotlib.patches import Rectangle
327+
fig = plt.figure()
328+
ax = fig.add_axes([0, 0, 1, 1])
329+
ax.set_axis_off()
330+
num_patches = len(Hatch._valid_hatch_patterns)
331+
332+
spacing = 0.1 # percent of width
333+
boxes_per_row = 4
334+
num_rows = np.ceil(num_patches / boxes_per_row)
335+
inter_box_dist_y = 1/num_rows
336+
posts = np.linspace(0, 1, boxes_per_row + 1)
337+
inter_box_dist_x = posts[1] - posts[0]
338+
font_size = 12
339+
fig_size = (4, 4)
340+
text_pad = 0.2 # fraction of text height
341+
text_height = (1 + text_pad)*(
342+
fig.dpi_scale_trans + ax.transAxes.inverted()
343+
).transform([1, 1])[1]
344+
# half of text pad
345+
bottom_padding = text_height*(1 - (1/(1+text_pad)))/2
346+
347+
for i, hatch in enumerate(Hatch._valid_hatch_patterns):
348+
row = int(i/boxes_per_row)
349+
col = i - row*boxes_per_row
350+
ax.add_patch(Rectangle(
351+
xy=[(col + spacing/2) * inter_box_dist_x,
352+
bottom_padding + row*inter_box_dist_y],
353+
width=inter_box_dist_x*(1 - spacing),
354+
height=inter_box_dist_y*(1 - text_height),
355+
transform=ax.transAxes,
356+
hatch=hatch,
357+
label="'" + hatch + "'"
358+
))
359+
ax.text((col + 1/2) * inter_box_dist_x,
360+
bottom_padding + (-text_height*(1/(1+text_pad)) + row
361+
+ 1)*inter_box_dist_y,
362+
"'" + hatch + "'", horizontalalignment='center',
363+
fontsize=font_size)
364+
365+
366+
@_api.deprecated("3.4")
205367
def get_path(hatchpattern, density=6):
206368
"""
207369
Given a hatch specifier, *hatchpattern*, generates Path to render
208370
the hatch in a unit square. *density* is the number of lines per
209371
unit square.
210372
"""
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
230-
231-
return Path(vertices, codes)
373+
return Hatch(hatchpattern).path

0 commit comments

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