From: <md...@us...> - 2008-09-10 18:46:13
|
Revision: 6080 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6080&view=rev Author: mdboom Date: 2008-09-10 18:46:10 +0000 (Wed, 10 Sep 2008) Log Message: ----------- [ 2089958 ] Path simplification for vector output backends Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py trunk/matplotlib/lib/matplotlib/backends/backend_ps.py trunk/matplotlib/lib/matplotlib/backends/backend_svg.py trunk/matplotlib/lib/matplotlib/config/mplconfig.py trunk/matplotlib/lib/matplotlib/config/rcsetup.py trunk/matplotlib/lib/matplotlib/path.py trunk/matplotlib/lib/matplotlib/rcsetup.py trunk/matplotlib/matplotlibrc.template Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2008-09-10 15:28:55 UTC (rev 6079) +++ trunk/matplotlib/CHANGELOG 2008-09-10 18:46:10 UTC (rev 6080) @@ -1,3 +1,10 @@ +2008-09-10 [ 2089958 ] Path simplification for vector output backends + Leverage the simplification code exposed through + path_to_polygons to simplify certain well-behaved paths in + the vector backends (PDF, PS and SVG). "path.simplify" + must be set to True in matplotlibrc for this to work. - + MGD + 2008-09-10 Add "filled" kwarg to Path.intersects_path and Path.intersects_bbox. - MGD Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-09-10 15:28:55 UTC (rev 6079) +++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py 2008-09-10 18:46:10 UTC (rev 6080) @@ -331,6 +331,10 @@ def __init__(self, width, height, dpi, filename): self.width, self.height = width, height self.dpi = dpi + if rcParams['path.simplify']: + self.simplify = (width * dpi, height * dpi) + else: + self.simplify = None self.nextObject = 1 # next free object id self.xrefTable = [ [0, 65535, 'the zero object'] ] self.passed_in_file_object = False @@ -1092,12 +1096,12 @@ self.endStream() #@staticmethod - def pathOperations(path, transform): + def pathOperations(path, transform, simplify=None): tpath = transform.transform_path(path) cmds = [] last_points = None - for points, code in tpath.iter_segments(): + for points, code in tpath.iter_segments(simplify): if code == Path.MOVETO: cmds.extend(points) cmds.append(Op.moveto) @@ -1118,7 +1122,8 @@ pathOperations = staticmethod(pathOperations) def writePath(self, path, transform): - cmds = self.pathOperations(path, transform) + cmds = self.pathOperations( + path, transform, self.simplify) self.output(*cmds) def reserveObject(self, name=''): Modified: trunk/matplotlib/lib/matplotlib/backends/backend_ps.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2008-09-10 15:28:55 UTC (rev 6079) +++ trunk/matplotlib/lib/matplotlib/backends/backend_ps.py 2008-09-10 18:46:10 UTC (rev 6080) @@ -145,6 +145,10 @@ self.textcnt = 0 self.psfrag = [] self.imagedpi = imagedpi + if rcParams['path.simplify']: + self.simplify = (width * imagedpi, height * imagedpi) + else: + self.simplify = None # current renderer state (None=uninitialised) self.color = None @@ -444,12 +448,12 @@ # unflip im.flipud_out() - def _convert_path(self, path, transform): + def _convert_path(self, path, transform, simplify=None): path = transform.transform_path(path) ps = [] last_points = None - for points, code in path.iter_segments(): + for points, code in path.iter_segments(simplify): if code == Path.MOVETO: ps.append("%g %g m" % tuple(points)) elif code == Path.LINETO: @@ -463,7 +467,7 @@ elif code == Path.CLOSEPOLY: ps.append("cl") last_points = points - + ps = "\n".join(ps) return ps @@ -482,7 +486,7 @@ """ Draws a Path instance using the given affine transform. """ - ps = self._convert_path(path, transform) + ps = self._convert_path(path, transform, self.simplify) self._draw_ps(ps, gc, rgbFace) def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): Modified: trunk/matplotlib/lib/matplotlib/backends/backend_svg.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_svg.py 2008-09-10 15:28:55 UTC (rev 6079) +++ trunk/matplotlib/lib/matplotlib/backends/backend_svg.py 2008-09-10 18:46:10 UTC (rev 6080) @@ -42,6 +42,10 @@ self.width=width self.height=height self._svgwriter = svgwriter + if rcParams['path.simplify']: + self.simplify = (width, height) + else: + self.simplify = None self._groupd = {} if not rcParams['svg.image_inline']: @@ -165,14 +169,14 @@ .scale(1.0, -1.0) .translate(0.0, self.height)) - def _convert_path(self, path, transform): + def _convert_path(self, path, transform, simplify=None): tpath = transform.transform_path(path) path_data = [] appender = path_data.append path_commands = self._path_commands currpos = 0 - for points, code in tpath.iter_segments(): + for points, code in tpath.iter_segments(simplify): if code == Path.CLOSEPOLY: segment = 'z' else: @@ -187,7 +191,7 @@ def draw_path(self, gc, path, transform, rgbFace=None): trans_and_flip = self._make_flip_transform(transform) - path_data = self._convert_path(path, trans_and_flip) + path_data = self._convert_path(path, trans_and_flip, self.simplify) self._draw_svg_element('path', 'd="%s"' % path_data, gc, rgbFace) def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): Modified: trunk/matplotlib/lib/matplotlib/config/mplconfig.py =================================================================== --- trunk/matplotlib/lib/matplotlib/config/mplconfig.py 2008-09-10 15:28:55 UTC (rev 6079) +++ trunk/matplotlib/lib/matplotlib/config/mplconfig.py 2008-09-10 18:46:10 UTC (rev 6080) @@ -117,6 +117,9 @@ markersize = T.Float(6) antialiased = T.true + class path(TConfig): + simplify = T.false + class patch(TConfig): linewidth = T.Float(1.0) facecolor = T.Trait('blue', mplT.ColorHandler()) @@ -439,6 +442,8 @@ 'svg.image_noscale' : (self.tconfig.backend.svg, 'image_noscale'), 'svg.embed_char_paths' : (self.tconfig.backend.svg, 'embed_char_paths'), + # Path properties + 'path.simplify' : (self.tconfig.path, 'simplify') } def __setitem__(self, key, val): Modified: trunk/matplotlib/lib/matplotlib/config/rcsetup.py =================================================================== --- trunk/matplotlib/lib/matplotlib/config/rcsetup.py 2008-09-10 15:28:55 UTC (rev 6079) +++ trunk/matplotlib/lib/matplotlib/config/rcsetup.py 2008-09-10 18:46:10 UTC (rev 6080) @@ -476,6 +476,7 @@ 'svg.embed_char_paths' : [True, validate_bool], # True to save all characters as paths in the SVG 'plugins.directory' : ['.matplotlib_plugins', str], # where plugin directory is locate + 'path.simplify' : [False, validate_bool] } if __name__ == '__main__': Modified: trunk/matplotlib/lib/matplotlib/path.py =================================================================== --- trunk/matplotlib/lib/matplotlib/path.py 2008-09-10 15:28:55 UTC (rev 6079) +++ trunk/matplotlib/lib/matplotlib/path.py 2008-09-10 18:46:10 UTC (rev 6080) @@ -145,12 +145,24 @@ def __len__(self): return len(self.vertices) - def iter_segments(self): + def iter_segments(self, simplify=None): """ Iterates over all of the curve segments in the path. Each iteration returns a 2-tuple (*vertices*, *code*), where *vertices* is a sequence of 1 - 3 coordinate pairs, and *code* is one of the :class:`Path` codes. + + If *simplify* is provided, it must be a tuple (*width*, + *height*) defining the size of the figure, in native units + (e.g. pixels or points). Simplification implies both removing + adjacent line segments that are very close to parallel, and + removing line segments outside of the figure. The path will + be simplified *only* if :attr:`should_simplify` is True, which + is determined in the constructor by this criteria: + + - No *codes* array + - No nonfinite values + - More than 128 vertices """ vertices = self.vertices if not len(vertices): @@ -166,7 +178,13 @@ CLOSEPOLY = self.CLOSEPOLY STOP = self.STOP - if codes is None: + if simplify is not None and self.should_simplify: + polygons = self.to_polygons(None, *simplify) + for vertices in polygons: + yield vertices[0], MOVETO + for v in vertices[1:]: + yield v, LINETO + elif codes is None: next_code = MOVETO for v in vertices: if (~isfinite(v)).any(): Modified: trunk/matplotlib/lib/matplotlib/rcsetup.py =================================================================== --- trunk/matplotlib/lib/matplotlib/rcsetup.py 2008-09-10 15:28:55 UTC (rev 6079) +++ trunk/matplotlib/lib/matplotlib/rcsetup.py 2008-09-10 18:46:10 UTC (rev 6080) @@ -487,6 +487,7 @@ 'svg.embed_char_paths' : [True, validate_bool], # True to save all characters as paths in the SVG 'plugins.directory' : ['.matplotlib_plugins', str], # where plugin directory is locate + 'path.simplify' : [False, validate_bool] } if __name__ == '__main__': Modified: trunk/matplotlib/matplotlibrc.template =================================================================== --- trunk/matplotlib/matplotlibrc.template 2008-09-10 15:28:55 UTC (rev 6079) +++ trunk/matplotlib/matplotlibrc.template 2008-09-10 18:46:10 UTC (rev 6080) @@ -270,6 +270,8 @@ #contour.negative_linestyle : dashed # dashed | solid ### SAVING FIGURES +#path.simplify : False # When True, simplify paths in vector backends, such as PDF, PS and SVG + # the default savefig params can be different for the GUI backends. # Eg, you may want a higher resolution, or to make the figure # background white This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |