diff --git a/doc/api/next_api_changes/deprecations/28048-PR.rst b/doc/api/next_api_changes/deprecations/28048-PR.rst new file mode 100644 index 000000000000..4e90a3aced19 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/28048-PR.rst @@ -0,0 +1,4 @@ +``PdfFile.hatchPatterns`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is deprecated. diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 95ed49612b35..80e57311d6de 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -961,6 +961,10 @@ def get_hatch_linewidth(self): """Get the hatch linewidth.""" return self._hatch_linewidth + def set_hatch_linewidth(self, hatch_linewidth): + """Set the hatch linewidth.""" + self._hatch_linewidth = hatch_linewidth + def get_sketch_params(self): """ Return the sketch parameters for the artist. diff --git a/lib/matplotlib/backend_bases.pyi b/lib/matplotlib/backend_bases.pyi index 70be504666fc..12b4d06aa68c 100644 --- a/lib/matplotlib/backend_bases.pyi +++ b/lib/matplotlib/backend_bases.pyi @@ -167,6 +167,7 @@ class GraphicsContextBase: def get_hatch_color(self) -> ColorType: ... def set_hatch_color(self, hatch_color: ColorType) -> None: ... def get_hatch_linewidth(self) -> float: ... + def set_hatch_linewidth(self, hatch_linewidth: float) -> None: ... def get_sketch_params(self) -> tuple[float, float, float] | None: ... def set_sketch_params( self, diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index 44b85cd3136d..86cbbe4d9a41 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -732,7 +732,7 @@ def __init__(self, filename, metadata=None): self._soft_mask_states = {} self._soft_mask_seq = (Name(f'SM{i}') for i in itertools.count(1)) self._soft_mask_groups = [] - self.hatchPatterns = {} + self._hatch_patterns = {} self._hatch_pattern_seq = (Name(f'H{i}') for i in itertools.count(1)) self.gouraudTriangles = [] @@ -1535,26 +1535,29 @@ def _write_soft_mask_groups(self): def hatchPattern(self, hatch_style): # The colors may come in as numpy arrays, which aren't hashable - if hatch_style is not None: - edge, face, hatch = hatch_style - if edge is not None: - edge = tuple(edge) - if face is not None: - face = tuple(face) - hatch_style = (edge, face, hatch) - - pattern = self.hatchPatterns.get(hatch_style, None) + edge, face, hatch, lw = hatch_style + if edge is not None: + edge = tuple(edge) + if face is not None: + face = tuple(face) + hatch_style = (edge, face, hatch, lw) + + pattern = self._hatch_patterns.get(hatch_style, None) if pattern is not None: return pattern name = next(self._hatch_pattern_seq) - self.hatchPatterns[hatch_style] = name + self._hatch_patterns[hatch_style] = name return name + hatchPatterns = _api.deprecated("3.10")(property(lambda self: { + k: (e, f, h) for k, (e, f, h, l) in self._hatch_patterns.items() + })) + def writeHatches(self): hatchDict = dict() sidelen = 72.0 - for hatch_style, name in self.hatchPatterns.items(): + for hatch_style, name in self._hatch_patterns.items(): ob = self.reserveObject('hatch pattern') hatchDict[name] = ob res = {'Procsets': @@ -1569,7 +1572,7 @@ def writeHatches(self): # Change origin to match Agg at top-left. 'Matrix': [1, 0, 0, 1, 0, self.height * 72]}) - stroke_rgb, fill_rgb, hatch = hatch_style + stroke_rgb, fill_rgb, hatch, lw = hatch_style self.output(stroke_rgb[0], stroke_rgb[1], stroke_rgb[2], Op.setrgb_stroke) if fill_rgb is not None: @@ -1578,7 +1581,7 @@ def writeHatches(self): 0, 0, sidelen, sidelen, Op.rectangle, Op.fill) - self.output(mpl.rcParams['hatch.linewidth'], Op.setlinewidth) + self.output(lw, Op.setlinewidth) self.output(*self.pathOperations( Path.hatch(hatch), @@ -2509,14 +2512,14 @@ def alpha_cmd(self, alpha, forced, effective_alphas): name = self.file.alphaState(effective_alphas) return [name, Op.setgstate] - def hatch_cmd(self, hatch, hatch_color): + def hatch_cmd(self, hatch, hatch_color, hatch_linewidth): if not hatch: if self._fillcolor is not None: return self.fillcolor_cmd(self._fillcolor) else: return [Name('DeviceRGB'), Op.setcolorspace_nonstroke] else: - hatch_style = (hatch_color, self._fillcolor, hatch) + hatch_style = (hatch_color, self._fillcolor, hatch, hatch_linewidth) name = self.file.hatchPattern(hatch_style) return [Name('Pattern'), Op.setcolorspace_nonstroke, name, Op.setcolor_nonstroke] @@ -2581,8 +2584,8 @@ def clip_cmd(self, cliprect, clippath): (('_dashes',), dash_cmd), (('_rgb',), rgb_cmd), # must come after fillcolor and rgb - (('_hatch', '_hatch_color'), hatch_cmd), - ) + (('_hatch', '_hatch_color', '_hatch_linewidth'), hatch_cmd), + ) def delta(self, other): """ @@ -2610,11 +2613,11 @@ def delta(self, other): break # Need to update hatching if we also updated fillcolor - if params == ('_hatch', '_hatch_color') and fill_performed: + if cmd.__name__ == 'hatch_cmd' and fill_performed: different = True if different: - if params == ('_fillcolor',): + if cmd.__name__ == 'fillcolor_cmd': fill_performed = True theirs = [getattr(other, p) for p in params] cmds.extend(cmd(self, *theirs)) diff --git a/lib/matplotlib/backends/backend_ps.py b/lib/matplotlib/backends/backend_ps.py index 893c660c0b24..78473afa0f06 100644 --- a/lib/matplotlib/backends/backend_ps.py +++ b/lib/matplotlib/backends/backend_ps.py @@ -505,12 +505,11 @@ def set_font(self, fontname, fontsize, store=True): self.fontname = fontname self.fontsize = fontsize - def create_hatch(self, hatch): + def create_hatch(self, hatch, linewidth): sidelen = 72 if hatch in self._hatches: return self._hatches[hatch] name = 'H%d' % len(self._hatches) - linewidth = mpl.rcParams['hatch.linewidth'] pageheight = self.height * 72 self._pswriter.write(f"""\ << /PatternType 1 @@ -933,7 +932,7 @@ def _draw_ps(self, ps, gc, rgbFace, *, fill=True, stroke=True): write("grestore\n") if hatch: - hatch_name = self.create_hatch(hatch) + hatch_name = self.create_hatch(hatch, gc.get_hatch_linewidth()) write("gsave\n") write(_nums_to_str(*gc.get_hatch_color()[:3])) write(f" {hatch_name} setpattern fill grestore\n") diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index dbf056613696..2193dc6b6cdc 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -500,11 +500,12 @@ def _get_hatch(self, gc, rgbFace): edge = gc.get_hatch_color() if edge is not None: edge = tuple(edge) - dictkey = (gc.get_hatch(), rgbFace, edge) + lw = gc.get_hatch_linewidth() + dictkey = (gc.get_hatch(), rgbFace, edge, lw) oid = self._hatchd.get(dictkey) if oid is None: oid = self._make_id('h', dictkey) - self._hatchd[dictkey] = ((gc.get_hatch_path(), rgbFace, edge), oid) + self._hatchd[dictkey] = ((gc.get_hatch_path(), rgbFace, edge, lw), oid) else: _, oid = oid return oid @@ -515,7 +516,7 @@ def _write_hatches(self): HATCH_SIZE = 72 writer = self.writer writer.start('defs') - for (path, face, stroke), oid in self._hatchd.values(): + for (path, face, stroke, lw), oid in self._hatchd.values(): writer.start( 'pattern', id=oid, @@ -539,7 +540,7 @@ def _write_hatches(self): hatch_style = { 'fill': rgb2hex(stroke), 'stroke': rgb2hex(stroke), - 'stroke-width': str(mpl.rcParams['hatch.linewidth']), + 'stroke-width': str(lw), 'stroke-linecap': 'butt', 'stroke-linejoin': 'miter' } diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index e668308abc82..94aa6b315141 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -174,6 +174,7 @@ def __init__(self, *, self._edge_is_mapped = None self._mapped_colors = None # calculated in update_scalarmappable self._hatch_color = mcolors.to_rgba(mpl.rcParams['hatch.color']) + self._hatch_linewidth = mpl.rcParams['hatch.linewidth'] self.set_facecolor(facecolors) self.set_edgecolor(edgecolors) self.set_linewidth(linewidths) @@ -364,6 +365,7 @@ def draw(self, renderer): if self._hatch: gc.set_hatch(self._hatch) gc.set_hatch_color(self._hatch_color) + gc.set_hatch_linewidth(self._hatch_linewidth) if self.get_sketch_params() is not None: gc.set_sketch_params(*self.get_sketch_params()) @@ -542,6 +544,14 @@ def get_hatch(self): """Return the current hatching pattern.""" return self._hatch + def set_hatch_linewidth(self, lw): + """Set the hatch linewidth.""" + self._hatch_linewidth = lw + + def get_hatch_linewidth(self): + """Return the hatch linewidth.""" + return self._hatch_linewidth + def set_offsets(self, offsets): """ Set the offsets for the collection. diff --git a/lib/matplotlib/collections.pyi b/lib/matplotlib/collections.pyi index 06d8676867ee..7237b5846d10 100644 --- a/lib/matplotlib/collections.pyi +++ b/lib/matplotlib/collections.pyi @@ -48,6 +48,8 @@ class Collection(artist.Artist, cm.ScalarMappable): def get_urls(self) -> Sequence[str | None]: ... def set_hatch(self, hatch: str) -> None: ... def get_hatch(self) -> str: ... + def set_hatch_linewidth(self, lw: float) -> None: ... + def get_hatch_linewidth(self) -> float: ... def set_offsets(self, offsets: ArrayLike) -> None: ... def get_offsets(self) -> ArrayLike: ... def set_linewidth(self, lw: float | Sequence[float]) -> None: ... diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 2db678587ec7..e7e56c853849 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -72,6 +72,7 @@ def __init__(self, *, joinstyle = JoinStyle.miter self._hatch_color = colors.to_rgba(mpl.rcParams['hatch.color']) + self._hatch_linewidth = mpl.rcParams['hatch.linewidth'] self._fill = bool(fill) # needed for set_facecolor call if color is not None: if edgecolor is not None or facecolor is not None: @@ -571,6 +572,14 @@ def get_hatch(self): """Return the hatching pattern.""" return self._hatch + def set_hatch_linewidth(self, lw): + """Set the hatch linewidth.""" + self._hatch_linewidth = lw + + def get_hatch_linewidth(self): + """Return the hatch linewidth.""" + return self._hatch_linewidth + def _draw_paths_with_artist_properties( self, renderer, draw_path_args_list): """ @@ -605,6 +614,7 @@ def _draw_paths_with_artist_properties( if self._hatch: gc.set_hatch(self._hatch) gc.set_hatch_color(self._hatch_color) + gc.set_hatch_linewidth(self._hatch_linewidth) if self.get_sketch_params() is not None: gc.set_sketch_params(*self.get_sketch_params()) diff --git a/lib/matplotlib/patches.pyi b/lib/matplotlib/patches.pyi index f6c9ddf75839..0645479ee5e7 100644 --- a/lib/matplotlib/patches.pyi +++ b/lib/matplotlib/patches.pyi @@ -59,6 +59,8 @@ class Patch(artist.Artist): def set_joinstyle(self, s: JoinStyleType) -> None: ... def get_joinstyle(self) -> Literal["miter", "round", "bevel"]: ... def set_hatch(self, hatch: str) -> None: ... + def set_hatch_linewidth(self, lw: float) -> None: ... + def get_hatch_linewidth(self) -> float: ... def get_hatch(self) -> str: ... def get_path(self) -> Path: ... diff --git a/lib/matplotlib/tests/test_collections.py b/lib/matplotlib/tests/test_collections.py index 19af38f3b522..11934cfca2c3 100644 --- a/lib/matplotlib/tests/test_collections.py +++ b/lib/matplotlib/tests/test_collections.py @@ -1361,3 +1361,26 @@ def test_striped_lines(fig_test, fig_ref, gapcolor): for x, gcol, ls in zip(x, itertools.cycle(gapcolor), itertools.cycle(linestyles)): ax_ref.axvline(x, 0, 1, linewidth=20, linestyle=ls, gapcolor=gcol, alpha=0.5) + + +@check_figures_equal(extensions=['png', 'pdf', 'svg', 'eps']) +def test_hatch_linewidth(fig_test, fig_ref): + ax_test = fig_test.add_subplot() + ax_ref = fig_ref.add_subplot() + + lw = 2.0 + + polygons = [ + [(0.1, 0.1), (0.1, 0.4), (0.4, 0.4), (0.4, 0.1)], + [(0.6, 0.6), (0.6, 0.9), (0.9, 0.9), (0.9, 0.6)], + ] + ref = PolyCollection(polygons, hatch="x") + ref.set_hatch_linewidth(lw) + + with mpl.rc_context({"hatch.linewidth": lw}): + test = PolyCollection(polygons, hatch="x") + + ax_ref.add_collection(ref) + ax_test.add_collection(test) + + assert test.get_hatch_linewidth() == ref.get_hatch_linewidth() == lw diff --git a/lib/matplotlib/tests/test_patches.py b/lib/matplotlib/tests/test_patches.py index 3544ce8cb10c..edbafa074de5 100644 --- a/lib/matplotlib/tests/test_patches.py +++ b/lib/matplotlib/tests/test_patches.py @@ -960,3 +960,20 @@ def test_arrow_set_data(): ) arrow.set_data(x=.5, dx=3, dy=8, width=1.2) assert np.allclose(expected2, np.round(arrow.get_verts(), 2)) + + +@check_figures_equal(extensions=["png", "pdf", "svg", "eps"]) +def test_set_and_get_hatch_linewidth(fig_test, fig_ref): + ax_test = fig_test.add_subplot() + ax_ref = fig_ref.add_subplot() + + lw = 2.0 + + with plt.rc_context({"hatch.linewidth": lw}): + ax_ref.add_patch(mpatches.Rectangle((0, 0), 1, 1, hatch="x")) + + ax_test.add_patch(mpatches.Rectangle((0, 0), 1, 1, hatch="x")) + ax_test.patches[0].set_hatch_linewidth(lw) + + assert ax_ref.patches[0].get_hatch_linewidth() == lw + assert ax_test.patches[0].get_hatch_linewidth() == lw pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy