Skip to content

Several hatching improvements #7421

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

Merged
merged 5 commits into from
Nov 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/users/dflt_style_changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
16 changes: 8 additions & 8 deletions lib/matplotlib/backends/backend_pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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],
Expand All @@ -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)
Expand Down
17 changes: 10 additions & 7 deletions lib/matplotlib/backends/backend_ps.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Copy link
Contributor

@mkvoya mkvoya Jan 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyone knows whether it is okay to write "fill" here? I deleted the "fill" and the hatch works on v3.0.2. The issue is described in #8289.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or shell we use the shfill command?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the difference between fill and shfill?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tacaswell sorry, I just skimmed the spec of EPS and found that shfill (shading fill, which "paints the shape and color shading described by a shading dictionary, subject to the current clipping path") seems not related.

But I do have tried multiple manual fixes on the generated eps file and had the following findings:

  1. Simply removing the "fill" can solve the issue in Hatching in EPS figures doesn't show up in Preview on MacOS X with Matplotlib 2.0 #8289. But when we draw with "*", the stars are not filled with colors, which breaks Rasterizing patch changes filling of hatches in pdf backend #6228.
  2. Surrounding the fill with gsave and grestore, also fixes Hatching in EPS figures doesn't show up in Preview on MacOS X with Matplotlib 2.0 #8289, but the result of Rasterizing patch changes filling of hatches in pdf backend #6228 is as follow.

image

I'm not familiar with the eps format, but hope the information is helpful.

stroke
} bind
>>
matrix
0.0 %(pageheight)f translate
makepattern
/%(name)s exch def
""" % locals())
Expand Down Expand Up @@ -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())
Expand All @@ -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")
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified lib/matplotlib/tests/baseline_images/test_artist/hatching.pdf
Binary file not shown.
Binary file modified lib/matplotlib/tests/baseline_images/test_artist/hatching.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion src/_backend_agg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
6 changes: 3 additions & 3 deletions src/_backend_agg.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down