Skip to content

Commit

Permalink
backend_pgf: clip paths within the backend (fixes #1857)
Browse files Browse the repository at this point in the history
  • Loading branch information
pwuertz committed Mar 31, 2013
1 parent cf6b26f commit 70f2296
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 7 deletions.
21 changes: 14 additions & 7 deletions lib/matplotlib/backends/backend_pgf.py
Expand Up @@ -421,7 +421,7 @@ def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None)
bl, tr = marker_path.get_extents(marker_trans).get_points() bl, tr = marker_path.get_extents(marker_trans).get_points()
coords = bl[0] * f, bl[1] * f, tr[0] * f, tr[1] * f coords = bl[0] * f, bl[1] * f, tr[0] * f, tr[1] * f
writeln(self.fh, r"\pgfsys@defobject{currentmarker}{\pgfqpoint{%fin}{%fin}}{\pgfqpoint{%fin}{%fin}}{" % coords) writeln(self.fh, r"\pgfsys@defobject{currentmarker}{\pgfqpoint{%fin}{%fin}}{\pgfqpoint{%fin}{%fin}}{" % coords)
self._print_pgf_path(marker_path, marker_trans) self._print_pgf_path(None, marker_path, marker_trans)
self._pgf_path_draw(stroke=gc.get_linewidth() != 0.0, self._pgf_path_draw(stroke=gc.get_linewidth() != 0.0,
fill=rgbFace is not None) fill=rgbFace is not None)
writeln(self.fh, r"}") writeln(self.fh, r"}")
Expand All @@ -441,7 +441,7 @@ def draw_path(self, gc, path, transform, rgbFace=None):
# draw the path # draw the path
self._print_pgf_clip(gc) self._print_pgf_clip(gc)
self._print_pgf_path_styles(gc, rgbFace) self._print_pgf_path_styles(gc, rgbFace)
self._print_pgf_path(path, transform) self._print_pgf_path(gc, path, transform)
self._pgf_path_draw(stroke=gc.get_linewidth() != 0.0, self._pgf_path_draw(stroke=gc.get_linewidth() != 0.0,
fill=rgbFace is not None) fill=rgbFace is not None)
writeln(self.fh, r"\end{pgfscope}") writeln(self.fh, r"\end{pgfscope}")
Expand All @@ -452,7 +452,7 @@ def draw_path(self, gc, path, transform, rgbFace=None):


# combine clip and path for clipping # combine clip and path for clipping
self._print_pgf_clip(gc) self._print_pgf_clip(gc)
self._print_pgf_path(path, transform) self._print_pgf_path(gc, path, transform)
writeln(self.fh, r"\pgfusepath{clip}") writeln(self.fh, r"\pgfusepath{clip}")


# build pattern definition # build pattern definition
Expand All @@ -461,7 +461,7 @@ def draw_path(self, gc, path, transform, rgbFace=None):
writeln(self.fh, r"\pgfpathrectangle{\pgfqpoint{0in}{0in}}{\pgfqpoint{1in}{1in}}") writeln(self.fh, r"\pgfpathrectangle{\pgfqpoint{0in}{0in}}{\pgfqpoint{1in}{1in}}")
writeln(self.fh, r"\pgfusepath{clip}") writeln(self.fh, r"\pgfusepath{clip}")
scale = mpl.transforms.Affine2D().scale(self.dpi) scale = mpl.transforms.Affine2D().scale(self.dpi)
self._print_pgf_path(gc.get_hatch_path(), scale) self._print_pgf_path(None, gc.get_hatch_path(), scale)
self._pgf_path_draw(stroke=True) self._pgf_path_draw(stroke=True)
writeln(self.fh, r"\end{pgfscope}") writeln(self.fh, r"\end{pgfscope}")
writeln(self.fh, r"}") writeln(self.fh, r"}")
Expand Down Expand Up @@ -495,7 +495,7 @@ def _print_pgf_clip(self, gc):
# check for clip path # check for clip path
clippath, clippath_trans = gc.get_clip_path() clippath, clippath_trans = gc.get_clip_path()
if clippath is not None: if clippath is not None:
self._print_pgf_path(clippath, clippath_trans) self._print_pgf_path(gc, clippath, clippath_trans)
writeln(self.fh, r"\pgfusepath{clip}") writeln(self.fh, r"\pgfusepath{clip}")


def _print_pgf_path_styles(self, gc, rgbFace): def _print_pgf_path_styles(self, gc, rgbFace):
Expand Down Expand Up @@ -543,10 +543,17 @@ def _print_pgf_path_styles(self, gc, rgbFace):
dash_str += r"}{%fpt}" % dash_offset dash_str += r"}{%fpt}" % dash_offset
writeln(self.fh, dash_str) writeln(self.fh, dash_str)


def _print_pgf_path(self, path, transform): def _print_pgf_path(self, gc, path, transform):
f = 1. / self.dpi f = 1. / self.dpi
# check for clip box
bbox = gc.get_clip_rectangle() if gc else None
if bbox:
p1, p2 = bbox.get_points()
clip = (p1[0], p1[1], p2[0], p2[1])
else:
clip = None
# build path # build path
for points, code in path.iter_segments(transform): for points, code in path.iter_segments(transform, clip=clip):
if code == Path.MOVETO: if code == Path.MOVETO:
x, y = tuple(points) x, y = tuple(points)
writeln(self.fh, r"\pgfpathmoveto{\pgfqpoint{%fin}{%fin}}" % writeln(self.fh, r"\pgfpathmoveto{\pgfqpoint{%fin}{%fin}}" %
Expand Down
2 changes: 2 additions & 0 deletions lib/matplotlib/compat/subprocess.py
Expand Up @@ -75,3 +75,5 @@ def _check_output(*popenargs, **kwargs):
check_output = subprocess.check_output check_output = subprocess.check_output
else: else:
check_output = _check_output check_output = _check_output

CalledProcessError = subprocess.CalledProcessError

This comment has been minimized.

Copy link
@daradib

daradib Mar 3, 2014

Contributor

I think this breaks #1825 because the subprocess module is empty on Google App Engine.

15 changes: 15 additions & 0 deletions lib/matplotlib/tests/test_backend_pgf.py
Expand Up @@ -130,6 +130,21 @@ def test_rcupdate():
create_figure() create_figure()
compare_figure('pgf_rcupdate%d.pdf' % (i+1)) compare_figure('pgf_rcupdate%d.pdf' % (i+1))



# test backend-side clipping, since large numbers are not supported by TeX
@switch_backend('pgf')
def test_pathclip():
if not check_for('xelatex'):
raise SkipTest('xelatex + pgf is required')

plt.figure()
plt.plot([0., 1e100], [0., 1e100])
plt.xlim(0, 1)
plt.ylim(0, 1)
# this test passes if compiling/saving to pdf works (no image comparison)
plt.savefig(os.path.join(result_dir, "pgf_pathclip.pdf"))


if __name__ == '__main__': if __name__ == '__main__':
import nose import nose
nose.runmodule(argv=['-s','--with-doctest'], exit=False) nose.runmodule(argv=['-s','--with-doctest'], exit=False)

0 comments on commit 70f2296

Please sign in to comment.