From: <md...@us...> - 2007-10-23 16:40:32
|
Revision: 3985 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3985&view=rev Author: mdboom Date: 2007-10-23 09:40:25 -0700 (Tue, 23 Oct 2007) Log Message: ----------- More progress on SVG. Refactored PS collection drawing to make it easier to reuse the (fairly complex) code. Modified Paths: -------------- branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_ps.py branches/transforms/lib/matplotlib/backends/backend_svg.py Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-10-23 14:30:57 UTC (rev 3984) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-10-23 16:40:25 UTC (rev 3985) @@ -55,13 +55,90 @@ offsetTrans, facecolors, edgecolors, linewidths, linestyles, antialiaseds): """ - MGDTODO: Document me. Explain that often the backend will not - want to override this. + This provides a fallback implementation of + draw_path_collection that makes multiple calls to draw_path. + Often, the backend will want to override this in order to + render each set of path data only once, and then reference + that path multiple times with the different offsets, colors, + styles etc. The methods _iter_collection_raw_paths and + _iter_collection are provided to help with (and standardize) + the implementation that in each backend. """ + path_ids = [] + for path, transform in self._iter_collection_raw_paths( + master_transform, paths, all_transforms): + path_ids.append((path, transform)) + + for xo, yo, path_id, gc, rgbFace in self._iter_collection( + path_ids, cliprect, clippath, clippath_trans, + offsets, offsetTrans, facecolors, edgecolors, + linewidths, linestyles, antialiaseds): + path, transform = path_id + transform = transform.frozen().translate(xo, yo) + self.draw_path(gc, path, transform, rgbFace) + + def _iter_collection_raw_paths(self, master_transform, paths, all_transforms): + """ + This is a helper method (along with _iter_collection) to make + it easier to write a space-efficent draw_path_collection + implementation in a backend. + + This method yields all of the base path/transform + combinations, given a master transform, a list of paths and + list of transforms. + + The arguments should be exactly what is passed in to + draw_path_collection. + + The backend should take each yielded path and transform and + create an object can be referenced (reused) later. + """ Npaths = len(paths) + Ntransforms = len(all_transforms) + N = max(Npaths, Ntransforms) + + if Npaths == 0: + return + + for i in xrange(N): + path = paths[i % Npaths] + transform = all_transforms[i % Ntransforms] + if transform is None: + transform = transforms.IdentityTransform() + transform += master_transform + yield path, transform + + def _iter_collection(self, path_ids, cliprect, clippath, clippath_trans, + offsets, offsetTrans, facecolors, edgecolors, + linewidths, linestyles, antialiaseds): + """ + This is a helper method (along with + _iter_collection_raw_paths) to make it easier to write a + space-efficent draw_path_collection implementation in a + backend. + + This method yields all of the path, offset and graphics + context combinations to draw the path collection. The caller + should already have looped over the results of + _iter_collection_raw_paths to draw this collection. + + The arguments should be the same as that passed into + draw_path_collection, with the exception of path_ids, which + is a list of arbitrary objects that the backend will use to + reference one of the paths created in the + _iter_collection_raw_paths stage. + + Each yielded result is of the form: + + xo, yo, path_id, gc, rgbFace + + where xo, yo is an offset; path_id is one of the elements of + path_ids; gc is a graphics context and rgbFace is a color to + use for filling the path. + """ + Npaths = len(path_ids) Noffsets = len(offsets) N = max(Npaths, Noffsets) - Ntransforms = min(len(all_transforms), N) Nfacecolors = len(facecolors) Nedgecolors = len(edgecolors) Nlinewidths = len(linewidths) @@ -71,16 +148,10 @@ if (Nfacecolors == 0 and Nedgecolors == 0) or Npaths == 0: return - ttransforms = [] - for i in range(Ntransforms): - transform = all_transforms[i] - if transform is None: - transform = transforms.IdentityTransform() - ttransforms.append((transform + master_transform).frozen()) - toffsets = offsetTrans.transform(offsets) gc = self.new_gc() + gc.set_clip_rectangle(cliprect) if clippath is not None: clippath = transforms.TransformedPath(clippath, clippath_trans) @@ -89,12 +160,9 @@ if Nfacecolors == 0: rgbFace = None - print linewidths, edgecolors - for i in xrange(N): - path = paths[i % Npaths] + path_id = path_ids[i % Npaths] xo, yo = toffsets[i % Noffsets] - transform = ttransforms[i % Ntransforms].frozen().translate(xo, yo) if Nfacecolors: rgbFace = facecolors[i % Nfacecolors] if Nedgecolors: @@ -103,8 +171,8 @@ gc.set_dashes(*linestyles[i % Nlinestyles]) gc.set_antialiased(antialiaseds[i % Naa]) - self.draw_path(gc, path, transform, rgbFace) - + yield xo, yo, path_id, gc, rgbFace + def get_image_magnification(self): """ Get the factor by which to magnify images passed to draw_image. Modified: branches/transforms/lib/matplotlib/backends/backend_ps.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-23 14:30:57 UTC (rev 3984) +++ branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-23 16:40:25 UTC (rev 3985) @@ -503,57 +503,22 @@ linestyles, antialiaseds): write = self._pswriter.write - Npaths = len(paths) - Noffsets = len(offsets) - N = max(Npaths, Noffsets) - Ntransforms = min(len(all_transforms), N) - Ntpaths = max(Npaths, Ntransforms) - Nfacecolors = len(facecolors) - Nedgecolors = len(edgecolors) - Nlinewidths = len(linewidths) - Nlinestyles = len(linestyles) - Naa = len(antialiaseds) - - if (Nfacecolors == 0 and Nedgecolors == 0) or Npaths == 0: - return - - for i in range(Ntpaths): - path = paths[i % Npaths] - transform = all_transforms[i % Ntransforms] - if transform is None: - transform = IdentityTransform() - transform += master_transform - + path_codes = [] + for i, (path, transform) in enumerate(self._iter_collection_raw_paths( + master_transform, paths, all_transforms)): ps_cmd = ['/p%x_%x {' % (self._path_collection_id, i), 'newpath', 'translate'] ps_cmd.append(self._convert_path(path, transform)) ps_cmd.extend(['} bind def\n']) write('\n'.join(ps_cmd)) + path_codes.append("p%x_%x" % (self._path_collection_id, i)) - toffsets = offsetTrans.transform(offsets) - - gc = self.new_gc() + for xo, yo, path_id, gc, rgbFace in self._iter_collection( + path_codes, cliprect, clippath, clippath_trans, + offsets, offsetTrans, facecolors, edgecolors, + linewidths, linestyles, antialiaseds): - gc.set_clip_rectangle(cliprect) - if clippath is not None: - clippath = transforms.TransformedPath(clippath, clippath_trans) - gc.set_clippath(clippath) - - if Nfacecolors == 0: - rgbFace = None - - for i in xrange(N): - path_id = i % Ntpaths - xo, yo = toffsets[i % Noffsets] - if Nfacecolors: - rgbFace = facecolors[i % Nfacecolors] - if Nedgecolors: - gc.set_foreground(edgecolors[i % Nedgecolors]) - gc.set_linewidth(linewidths[i % Nlinewidths]) - gc.set_dashes(*linestyles[i % Nlinestyles]) - gc.set_antialiased(antialiaseds[i % Naa]) - - ps = "%g %g p%x_%x" % (xo, yo, self._path_collection_id, path_id) + ps = "%g %g %s" % (xo, yo, path_id) self._draw_ps(ps, gc, rgbFace) self._path_collection_id += 1 @@ -786,7 +751,9 @@ cint = gc.get_capstyle() self.set_linecap(cint) self.set_linedash(*gc.get_dashes()) - + if self.linewidth > 0 and stroke: + self.set_color(*gc.get_rgb()[:3]) + cliprect = gc.get_clip_rectangle() if cliprect: x,y,w,h=cliprect.bounds Modified: branches/transforms/lib/matplotlib/backends/backend_svg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_svg.py 2007-10-23 14:30:57 UTC (rev 3984) +++ branches/transforms/lib/matplotlib/backends/backend_svg.py 2007-10-23 16:40:25 UTC (rev 3985) @@ -47,16 +47,16 @@ svgwriter.write(svgProlog%(width,height,width,height)) def _draw_svg_element(self, element, details, gc, rgbFace): - cliprect, clipid = self._get_gc_clip_svg(gc) + clipid = self._get_gc_clip_svg(gc) if clipid is None: clippath = '' else: clippath = 'clip-path="url(#%s)"' % clipid style = self._get_style(gc, rgbFace) - self._svgwriter.write ('%s<%s style="%s" %s %s/>\n' % ( - cliprect, element, style, clippath, details)) - + self._svgwriter.write ('<%s style="%s" %s %s/>\n' % ( + element, style, clippath, details)) + def _get_font(self, prop): key = hash(prop) font = self.fontd.get(key) @@ -108,36 +108,23 @@ cliprect = gc.get_clip_rectangle() clippath, clippath_trans = gc.get_clip_path() if clippath is not None: - pathkey = (hash(clippath), hash(clippath_trans)) - path = '' - if self._clipd.get(pathkey) is None: - self._clipd[pathkey] = clippath - path_data = self._convert_path(clippath, clippath_trans) - path = """\ -<defs> - <clipPath id="%(pathkey)s"> - <path d="%(path_data)s"/> - </clipPath> -</defs> -""" % locals() - return path, pathkey + path_data = self._convert_path(clippath, clippath_trans) + path = '<path d="%s"/>' % path_data elif cliprect is not None: - rectkey = hash(cliprect) - box = '' - if self._clipd.get(rectkey) is None: - self._clipd[rectkey] = cliprect - x, y, w, h = cliprect.bounds - y = self.height-(y+h) - box = """\ -<defs> - <clipPath id="%(rectkey)s"> - <rect x="%(x)s" y="%(y)s" width="%(w)s" height="%(h)s"/> - </clipPath> -</defs> -""" % locals() - return box, rectkey - - return '', None + x, y, w, h = cliprect.bounds + y = self.height-(y+h) + path = '<rect x="%(x)s" y="%(y)s" width="%(w)s" height="%(h)s"/>' % locals() + else: + return None + + id = self._clipd.get(path) + if id is None: + id = 'p%x' % len(self._clipd) + self._svgwriter.write('<defs>\n <clipPath id="%s">\n' % id) + self._svgwriter.write(path) + self._svgwriter.write('\n </clipPath>\n</defs>') + self._clipd[path] = id + return id def open_group(self, s): self._groupd[s] = self._groupd.get(s,0) + 1 @@ -193,17 +180,17 @@ def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): write = self._svgwriter.write - key = self._convert_path(marker_path, marker_trans + Affine2D().scale(0, -1.0)) + key = self._convert_path(marker_path, marker_trans + Affine2D().scale(1.0, -1.0)) name = self._markers.get(key) if name is None: - name = 'm_%x' % len(self._markers) + name = 'm%x' % len(self._markers) write('<defs><path id="%s" d="%s"/></defs>\n' % (name, key)) self._markers[key] = name trans_and_flip = self._make_flip_transform(trans) tpath = trans_and_flip.transform_path(path) for x, y in tpath.vertices: - details = 'xlink:href="#%s" transform="translate(%f, %f)"' % (name, x, y) + details = 'xlink:href="#%s" x="%f" y="%f"' % (name, x, y) self._draw_svg_element('use', details, gc, rgbFace) def draw_image(self, x, y, im, bbox): @@ -307,7 +294,7 @@ svg.append('<use xlink:href="#%s"' % charid) if currx != 0: - svg.append(' transform="translate(%s)"' % + svg.append(' x="%s"' % (currx * (self.FONT_SCALE / fontsize))) svg.append('/>\n') currx += (glyph.linearHoriAdvance / 65536.0) @@ -364,7 +351,7 @@ if step[0] != 4: currx, curry = step[-2], -step[-1] - char_num = 'c_%x' % len(self._char_defs) + char_num = 'c%x' % len(self._char_defs) path_element = '<path id="%s" d="%s"/>\n' % (char_num, ''.join(path_data)) self._char_defs[char_id] = (char_num, path_element) return char_num This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |