diff --git a/doc/users/dflt_style_changes.rst b/doc/users/dflt_style_changes.rst index 8d6b31331d55..c2490073114a 100644 --- a/doc/users/dflt_style_changes.rst +++ b/doc/users/dflt_style_changes.rst @@ -625,6 +625,11 @@ The behavior of the PS and Agg backends was DPI dependent, thus:: There is no API level control of the hatch color or linewidth. +Hatching patterns are now rendered at a consistent density, regardless of DPI. +Formerly, high DPI figures would be more dense than the default, and low DPI +figures would be less dense. This old behavior cannot be directly restored, +but the density may be increased by repeating the hatch specifier. + .. _default_changes_font: diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index 2d8d4310f1b5..015f71a659c8 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -1141,12 +1141,12 @@ def alphaState(self, alpha): def hatchPattern(self, hatch_style): # The colors may come in as numpy arrays, which aren't hashable if hatch_style is not None: - face, edge, hatch = hatch_style - if face is not None: - face = tuple(face) + edge, face, hatch = hatch_style if edge is not None: edge = tuple(edge) - hatch_style = (face, edge, hatch) + if face is not None: + face = tuple(face) + hatch_style = (edge, face, hatch) pattern = self.hatchPatterns.get(hatch_style, None) if pattern is not None: @@ -1171,7 +1171,9 @@ def writeHatches(self): 'PatternType': 1, 'PaintType': 1, 'TilingType': 1, 'BBox': [0, 0, sidelen, sidelen], 'XStep': sidelen, 'YStep': sidelen, - 'Resources': res}) + 'Resources': res, + # Change origin to match Agg at top-left. + 'Matrix': [1, 0, 0, 1, 0, self.height * 72]}) stroke_rgb, fill_rgb, path = hatch_style self.output(stroke_rgb[0], stroke_rgb[1], stroke_rgb[2], @@ -1184,13 +1186,11 @@ def writeHatches(self): self.output(rcParams['hatch.linewidth'], Op.setlinewidth) - # TODO: We could make this dpi-dependent, but that would be - # an API change self.output(*self.pathOperations( Path.hatch(path), Affine2D().scale(sidelen), simplify=False)) - self.output(Op.stroke) + self.output(Op.fill_stroke) self.endStream() self.writeObject(self.hatchObject, hatchDict) diff --git a/lib/matplotlib/backends/backend_ps.py b/lib/matplotlib/backends/backend_ps.py index 69eaf37c8356..f6f3c58b1310 100644 --- a/lib/matplotlib/backends/backend_ps.py +++ b/lib/matplotlib/backends/backend_ps.py @@ -305,6 +305,7 @@ def create_hatch(self, hatch): return self._hatches[hatch] name = 'H%d' % len(self._hatches) linewidth = rcParams['hatch.linewidth'] + pageheight = self.height * 72 self._pswriter.write("""\ << /PatternType 1 /PaintType 2 @@ -318,13 +319,15 @@ def create_hatch(self, hatch): %(linewidth)f setlinewidth """ % locals()) self._pswriter.write( - self._convert_path(Path.hatch(hatch), Affine2D().scale(72.0), + self._convert_path(Path.hatch(hatch), Affine2D().scale(sidelen), simplify=False)) self._pswriter.write("""\ - stroke + fill + stroke } bind >> matrix + 0.0 %(pageheight)f translate makepattern /%(name)s exch def """ % locals()) @@ -861,6 +864,7 @@ def _draw_ps(self, ps, gc, rgbFace, fill=True, stroke=True, command=None): stroke = stroke and mightstroke fill = (fill and rgbFace is not None and (len(rgbFace) <= 3 or rgbFace[3] != 0.0)) + hatch = gc.get_hatch() if mightstroke: self.set_linewidth(gc.get_linewidth()) @@ -886,19 +890,18 @@ def _draw_ps(self, ps, gc, rgbFace, fill=True, stroke=True, command=None): write("\n") if fill: - if stroke: + if stroke or hatch: write("gsave\n") self.set_color(store=0, *rgbFace[:3]) write("fill\n") - if stroke: + if stroke or hatch: write("grestore\n") - hatch = gc.get_hatch() if hatch: hatch_name = self.create_hatch(hatch) write("gsave\n") - write("[/Pattern [/DeviceRGB]] setcolorspace %f %f %f " % gc.get_hatch_color()[:3]) - write("%s setcolor fill grestore\n" % hatch_name) + write("%f %f %f " % gc.get_hatch_color()[:3]) + write("%s setpattern fill grestore\n" % hatch_name) if stroke: write("stroke\n") diff --git a/lib/matplotlib/tests/baseline_images/test_artist/clip_path_clipping.png b/lib/matplotlib/tests/baseline_images/test_artist/clip_path_clipping.png index 7436839cc4bb..2af7a6b99227 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_artist/clip_path_clipping.png and b/lib/matplotlib/tests/baseline_images/test_artist/clip_path_clipping.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_artist/hatching.pdf b/lib/matplotlib/tests/baseline_images/test_artist/hatching.pdf index 2c749aa6e915..7a256313ab1c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_artist/hatching.pdf and b/lib/matplotlib/tests/baseline_images/test_artist/hatching.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_artist/hatching.png b/lib/matplotlib/tests/baseline_images/test_artist/hatching.png index 4bd9d99a06e2..d2bda07f0a11 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_artist/hatching.png and b/lib/matplotlib/tests/baseline_images/test_artist/hatching.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/contour_hatching.png b/lib/matplotlib/tests/baseline_images/test_axes/contour_hatching.png index 84c426efc84a..2090e4d208a3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/contour_hatching.png and b/lib/matplotlib/tests/baseline_images/test_axes/contour_hatching.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate.png b/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate.png index a324554de74c..7d705b038b43 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate.png and b/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/double_cbar.png b/lib/matplotlib/tests/baseline_images/test_colorbar/double_cbar.png index fdf399c1a92d..2ddb219eda3a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_colorbar/double_cbar.png and b/lib/matplotlib/tests/baseline_images/test_colorbar/double_cbar.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_cycles/fill_cycle_basic.png b/lib/matplotlib/tests/baseline_images/test_cycles/fill_cycle_basic.png index 7b6e14949e23..512d46de668e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_cycles/fill_cycle_basic.png and b/lib/matplotlib/tests/baseline_images/test_cycles/fill_cycle_basic.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_cycles/fill_cycle_ignore.png b/lib/matplotlib/tests/baseline_images/test_cycles/fill_cycle_ignore.png index a6b3fc0d80e7..46f6f82eeca2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_cycles/fill_cycle_ignore.png and b/lib/matplotlib/tests/baseline_images/test_cycles/fill_cycle_ignore.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.png b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.png index 8f892e935651..f9323ad2387c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.png and b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/hatch_simplify.png b/lib/matplotlib/tests/baseline_images/test_simplification/hatch_simplify.png index b95fb059f7fb..5851ff556394 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/hatch_simplify.png and b/lib/matplotlib/tests/baseline_images/test_simplification/hatch_simplify.png differ diff --git a/src/_backend_agg.cpp b/src/_backend_agg.cpp index e4721565f52f..f44879d796ce 100644 --- a/src/_backend_agg.cpp +++ b/src/_backend_agg.cpp @@ -58,11 +58,14 @@ RendererAgg::RendererAgg(unsigned int width, unsigned int height, double dpi) rendererBase.clear(_fill_color); rendererAA.attach(rendererBase); rendererBin.attach(rendererBase); - hatchRenderingBuffer.attach(hatchBuffer, HATCH_SIZE, HATCH_SIZE, HATCH_SIZE * 4); + hatch_size = int(dpi); + hatchBuffer = new agg::int8u[hatch_size * hatch_size * 4]; + hatchRenderingBuffer.attach(hatchBuffer, hatch_size, hatch_size, hatch_size * 4); } RendererAgg::~RendererAgg() { + delete[] hatchBuffer; delete[] alphaBuffer; delete[] pixBuffer; } diff --git a/src/_backend_agg.h b/src/_backend_agg.h index 243094a7aae4..0265647cb463 100644 --- a/src/_backend_agg.h +++ b/src/_backend_agg.h @@ -239,8 +239,8 @@ class RendererAgg void *lastclippath; agg::trans_affine lastclippath_transform; - static const size_t HATCH_SIZE = 72; - agg::int8u hatchBuffer[HATCH_SIZE * HATCH_SIZE * 4]; + size_t hatch_size; + agg::int8u *hatchBuffer; agg::rendering_buffer hatchRenderingBuffer; agg::rgba _fill_color; @@ -359,7 +359,7 @@ RendererAgg::_draw_path(path_t &path, bool has_clippath, const facepair_t &face, agg::trans_affine hatch_trans; hatch_trans *= agg::trans_affine_scaling(1.0, -1.0); hatch_trans *= agg::trans_affine_translation(0.0, 1.0); - hatch_trans *= agg::trans_affine_scaling(HATCH_SIZE, HATCH_SIZE); + hatch_trans *= agg::trans_affine_scaling(hatch_size, hatch_size); hatch_path_trans_t hatch_path_trans(hatch_path, hatch_trans); hatch_path_curve_t hatch_path_curve(hatch_path_trans); hatch_path_stroke_t hatch_path_stroke(hatch_path_curve);