Skip to content


Subversion checkout URL

You can clone with
Download ZIP


backend_pgf: clip paths within the backend (fixes #1857) #1858

merged 1 commit into from

4 participants


Because LaTeX doesn't handle very large numbers (#1857), this PR moves some of the clipping operations from the pgf-code into backend_pgf.


Weird, python 2.6 and 3.x tests are passing on Travis, 2.7 is not (although it passes on my machine with 2.7). It also won't show me the log-file to see what's wrong :/


It looks like the Travis failure was a networking error when trying to install PIL, so in other words a false result. Looks like a reasonable fix to me.

Should this perhaps go on 1.2.x since it's a bugfix? Also, it could use a test -- I don't know if it needs to be an image comparison test, but something to just make sure the really large number doesn't show up in the output should be sufficient.


I just added a test that triggers #1857 and now passes with clipping added to draw_path.

Also, apparently some restructuring has been applied to master and a failed LaTeX call now results in an error looking up subprocess.CalledProcessError. I forwarded the missing Exception in matplotlib.compat.subprocess.

If this is fine with you we can apply this to master and I'll prepare another PR for 1.2 without the subprocess fix.

@pelson pelson merged commit 6e94330 into matplotlib:master

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 31, 2013
  1. @pwuertz
This page is out of date. Refresh to see the latest.
21 lib/matplotlib/backends/
@@ -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()
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)
- 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,
fill=rgbFace is not None)
writeln(self.fh, r"}")
@@ -441,7 +441,7 @@ def draw_path(self, gc, path, transform, rgbFace=None):
# draw the path
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,
fill=rgbFace is not None)
writeln(self.fh, r"\end{pgfscope}")
@@ -452,7 +452,7 @@ def draw_path(self, gc, path, transform, rgbFace=None):
# combine clip and path for clipping
- self._print_pgf_path(path, transform)
+ self._print_pgf_path(gc, path, transform)
writeln(self.fh, r"\pgfusepath{clip}")
# build pattern definition
@@ -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"\pgfusepath{clip}")
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)
writeln(self.fh, r"\end{pgfscope}")
writeln(self.fh, r"}")
@@ -495,7 +495,7 @@ def _print_pgf_clip(self, gc):
# check for clip path
clippath, clippath_trans = gc.get_clip_path()
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}")
def _print_pgf_path_styles(self, gc, rgbFace):
@@ -543,10 +543,17 @@ def _print_pgf_path_styles(self, gc, rgbFace):
dash_str += r"}{%fpt}" % dash_offset
writeln(self.fh, dash_str)
- def _print_pgf_path(self, path, transform):
+ def _print_pgf_path(self, gc, path, transform):
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
- for points, code in path.iter_segments(transform):
+ for points, code in path.iter_segments(transform, clip=clip):
if code == Path.MOVETO:
x, y = tuple(points)
writeln(self.fh, r"\pgfpathmoveto{\pgfqpoint{%fin}{%fin}}" %
2  lib/matplotlib/compat/
@@ -75,3 +75,5 @@ def _check_output(*popenargs, **kwargs):
check_output = subprocess.check_output
check_output = _check_output
+CalledProcessError = subprocess.CalledProcessError
15 lib/matplotlib/tests/
@@ -130,6 +130,21 @@ def test_rcupdate():
compare_figure('pgf_rcupdate%d.pdf' % (i+1))
+# test backend-side clipping, since large numbers are not supported by TeX
+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__':
import nose
nose.runmodule(argv=['-s','--with-doctest'], exit=False)
Something went wrong with that request. Please try again.