From: <md...@us...> - 2007-09-07 15:23:34
|
Revision: 3810 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3810&view=rev Author: mdboom Date: 2007-09-07 08:23:32 -0700 (Fri, 07 Sep 2007) Log Message: ----------- Merged revisions 3806-3809 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3807 | mdboom | 2007-09-07 10:34:51 -0400 (Fri, 07 Sep 2007) | 2 lines Backout stylesheet optimization. Breaks on inkscape and Adobe SVG viewer. ........ r3808 | mdboom | 2007-09-07 10:55:55 -0400 (Fri, 07 Sep 2007) | 3 lines Fix embedded glyph rendering bug revealed by Inkscape and Safari (but not Firefox) ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/backends/backend_svg.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3805 + /trunk/matplotlib:1-3809 Modified: branches/transforms/lib/matplotlib/backends/backend_svg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_svg.py 2007-09-07 15:02:52 UTC (rev 3809) +++ branches/transforms/lib/matplotlib/backends/backend_svg.py 2007-09-07 15:23:32 UTC (rev 3810) @@ -41,7 +41,6 @@ self._char_defs = {} self.mathtext_parser = MathTextParser('SVG') self.fontd = {} - self._styles = {} svgwriter.write(svgProlog%(width,height,width,height)) def _draw_svg_element(self, element, details, gc, rgbFace): @@ -51,10 +50,9 @@ else: clippath = 'clip-path="url(#%s)"' % clipid - style = self._map_style(self._get_style(gc, rgbFace)) - self._svgwriter.write ('%s<%s class="%s" %s %s/>\n' % ( - cliprect, - element, style, clippath, details)) + style = self._get_style(gc, rgbFace) + self._svgwriter.write ('%s<%s style="%s" %s %s/>\n' % ( + cliprect, element, style, clippath, details)) def _get_font(self, prop): key = hash(prop) @@ -82,13 +80,13 @@ if seq is None: dashes = '' else: - dashes = 'stroke-dasharray: %s; stroke-dashoffset: %f;' % ( - ','.join(['%f'%val for val in seq]), offset) + dashes = 'stroke-dasharray: %s; stroke-dashoffset: %s;' % ( + ','.join(['%s'%val for val in seq]), offset) linewidth = gc.get_linewidth() if linewidth: - return 'fill: %s; stroke: %s; stroke-width: %f; ' \ - 'stroke-linejoin: %s; stroke-linecap: %s; %s opacity: %f' % ( + return 'fill: %s; stroke: %s; stroke-width: %s; ' \ + 'stroke-linejoin: %s; stroke-linecap: %s; %s opacity: %s' % ( fill, rgb2hex(gc.get_rgb()), linewidth, @@ -98,16 +96,11 @@ gc.get_alpha(), ) else: - return 'fill: %s; opacity: %f' % (\ + return 'fill: %s; opacity: %s' % (\ fill, gc.get_alpha(), ) - def _map_style(self, style): - return self._styles.setdefault( - style, - "_%x" % len(self._styles)) - def _get_gc_clip_svg(self, gc): cliprect = gc.get_clip_rectangle() if cliprect is None: @@ -119,12 +112,12 @@ self._clipd[key] = cliprect x, y, w, h = cliprect y = self.height-(y+h) - style = self._map_style("stroke: gray; fill: none;") + style = "stroke: gray; fill: none;" box = """\ <defs> <clipPath id="%(key)s"> - <rect x="%(x)f" y="%(y)f" width="%(w)f" height="%(h)f" - class="%(style)s"/> + <rect x="%(x)s" y="%(y)s" width="%(w)s" height="%(h)s" + style="%(style)s"/> </clipPath> </defs> """ % locals() @@ -144,7 +137,7 @@ """ Ignores angles for now """ - details = 'cx="%f" cy="%f" rx="%f" ry="%f" transform="rotate(%f %f %f)"' % \ + details = 'cx="%s" cy="%s" rx="%s" ry="%s" transform="rotate(%1.1f %s %s)"' % \ (x, self.height-y, width/2.0, height/2.0, -rotation, x, self.height-y) self._draw_svg_element('ellipse', details, gc, rgbFace) @@ -163,7 +156,7 @@ trans[4] += trans[0] trans[5] += trans[3] trans[5] = -trans[5] - transstr = 'transform="matrix(%f %f %f %f %f %f)" '%tuple(trans) + transstr = 'transform="matrix(%s %s %s %s %s %s)" '%tuple(trans) assert trans[1] == 0 assert trans[2] == 0 numrows,numcols = im.get_size() @@ -207,12 +200,12 @@ hrefstr = filename self._svgwriter.write ( - '<image x="%f" y="%f" width="%f" height="%f" ' + '<image x="%s" y="%s" width="%s" height="%s" ' 'xlink:href="%s" %s/>\n'%(x/trans[0], (self.height-y)/trans[3]-h, w, h, hrefstr, transstr) ) def draw_line(self, gc, x1, y1, x2, y2): - details = 'd="M %f,%f L %f,%f"' % (x1, self.height-y1, + details = 'd="M%s,%sL%s,%s"' % (x1, self.height-y1, x2, self.height-y2) self._draw_svg_element('path', details, gc, None) @@ -222,11 +215,11 @@ raise ValueError('x and y must be the same length') y = self.height - y - details = ['d="M %f,%f' % (x[0], y[0])] + details = ['d="M%s,%s' % (x[0], y[0])] xys = zip(x[1:], y[1:]) - details.extend(['L %f,%f' % tup for tup in xys]) + details.extend(['L%s,%s' % tup for tup in xys]) details.append('"') - details = ' '.join(details) + details = ''.join(details) self._draw_svg_element('path', details, gc, None) def draw_point(self, gc, x, y): @@ -234,12 +227,12 @@ self.draw_arc(gc, gc.get_rgb(), x, y, 1, 0, 0, 0, 0) def draw_polygon(self, gc, rgbFace, points): - details = 'points = "%s"' % ' '.join(['%f,%f'%(x,self.height-y) + details = 'points = "%s"' % ' '.join(['%s,%s'%(x,self.height-y) for x, y in points]) self._draw_svg_element('polygon', details, gc, rgbFace) def draw_rectangle(self, gc, rgbFace, x, y, width, height): - details = 'width="%f" height="%f" x="%f" y="%f"' % (width, height, x, + details = 'width="%s" height="%s" x="%s" y="%s"' % (width, height, x, self.height-y-height) self._draw_svg_element('rect', details, gc, rgbFace) @@ -260,12 +253,11 @@ if rcParams['svg.embed_char_paths']: svg = ['<g transform="'] - if angle!=0: - # Inkscape doesn't support rotate(angle x y) - svg.append('translate(%f,%f) rotate(%1.1f) ' % (x,y,-angle)) - else: - svg.append('translate(%f,%f)' % (x,y)) - svg.append(' scale(%f)">\n' % (fontsize / self.FONT_SCALE)) + if angle != 0: + svg.append('translate(%s,%s)rotate(%1.1f)' % (x,y,-angle)) + elif x != 0 or y != 0: + svg.append('translate(%s,%s)' % (x, y)) + svg.append('scale(%s)">\n' % (fontsize / self.FONT_SCALE)) cmap = font.get_charmap() lastgind = None @@ -286,21 +278,24 @@ lastgind = gind currx += kern/64.0 - svg.append('<use xlink:href="#%s" transform="translate(%s)"/>\n' - % (charid, currx * (self.FONT_SCALE / fontsize))) - + svg.append('<use xlink:href="#%s"' % charid) + if currx != 0: + svg.append(' transform="translate(%s)"' % + (currx * (self.FONT_SCALE / fontsize))) + svg.append('/>\n') currx += (glyph.linearHoriAdvance / 65536.0) svg.append('</g>\n') svg = ''.join(svg) else: style = 'font-size: %f; font-family: %s; font-style: %s; fill: %s;'%(fontsize, fontfamily,fontstyle, color) - style_number = self._map_style(style) if angle!=0: - transform = 'transform="translate(%f,%f) rotate(%1.1f) translate(%f,%f)"' % (x,y,-angle,-x,-y) # Inkscape doesn't support rotate(angle x y) - else: transform = '' + transform = 'transform="translate(%s,%s) rotate(%1.1f) translate(%s,%s)"' % (x,y,-angle,-x,-y) + # Inkscape doesn't support rotate(angle x y) + else: + transform = '' svg = """\ -<text class="%(style_number)s" x="%(x)f" y="%(y)f" %(transform)s>%(thetext)s</text> +<text style="%(style)s" x="%(x)s" y="%(y)s" %(transform)s>%(thetext)s</text> """ % locals() self._svgwriter.write (svg) @@ -313,16 +308,17 @@ font.set_size(self.FONT_SCALE, 72) ps_name = font.get_sfnt()[(1,0,0,6)] char_id = urllib.quote('%s-%d' % (ps_name, ord(char))) - if char_id in self._char_defs: - return char_id + char_num, path = self._char_defs.get(char_id, (None, None)) + if char_num is not None: + return char_num path_data = [] glyph = font.load_char(ord(char), flags=LOAD_NO_HINTING) currx, curry = 0.0, 0.0 for step in glyph.path: if step[0] == 0: # MOVE_TO - path_data.append("m%s %s" % - (step[1] - currx, -step[2] - curry)) + path_data.append("M%s %s" % + (step[1], -step[2])) elif step[0] == 1: # LINE_TO path_data.append("l%s %s" % (step[1] - currx, -step[2] - curry)) @@ -336,15 +332,16 @@ step[3] - currx, -step[4] - curry, step[5] - currx, -step[6] - curry)) elif step[0] == 4: # ENDPOLY - path_data.append("Z") + path_data.append("z") + currx, curry = 0.0, 0.0 if step[0] != 4: currx, curry = step[-2], -step[-1] - path_element = '<path id="%s" d="%s"/>\n' % (char_id, " ".join(path_data)) + 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 - self._char_defs[char_id] = path_element - return char_id - def _draw_mathtext(self, gc, x, y, s, prop, angle): """ Draw math text using matplotlib.mathtext @@ -358,25 +355,24 @@ self.open_group("mathtext") style = "fill: %s" % color - style_number = self._map_style(style) if rcParams['svg.embed_char_paths']: - svg = ['<g class="%s" transform="' % style_number] + svg = ['<g style="%s" transform="' % style] if angle != 0: - svg.append('translate(%f,%f) rotate(%1.1f)' + svg.append('translate(%s,%s)rotate(%1.1f)' % (x,y,-angle) ) else: - svg.append('translate(%f,%f)' % (x, y)) + svg.append('translate(%s,%s)' % (x, y)) svg.append('">\n') for font, fontsize, thetext, new_x, new_y_mtc, metrics in svg_glyphs: charid = self._add_char_def(font, thetext) - svg.append('<use xlink:href="#%s" transform="translate(%s, %s) scale(%s)"/>\n' % + svg.append('<use xlink:href="#%s" transform="translate(%s,%s)scale(%s)"/>\n' % (charid, new_x, -new_y_mtc, fontsize / self.FONT_SCALE)) svg.append('</g>\n') else: # not rcParams['svg.embed_char_paths'] - svg = ['<text class="%s" x="%f" y="%f"' % (style_number, x, y)] + svg = ['<text style="%s" x="%f" y="%f"' % (style, x, y)] if angle != 0: svg.append(' transform="translate(%f,%f) rotate(%1.1f) translate(%f,%f)"' @@ -388,19 +384,18 @@ for font, fontsize, thetext, new_x, new_y_mtc, metrics in svg_glyphs: new_y = - new_y_mtc style = "font-size: %f; font-family: %s" % (fontsize, font.family_name) - style_number = self._map_style(style) - svg.append('<tspan class="%s"' % style_number) + svg.append('<tspan style="%s"' % style) xadvance = metrics.advance - svg.append(' textLength="%f"' % xadvance) + svg.append(' textLength="%s"' % xadvance) dx = new_x - curr_x if dx != 0.0: - svg.append(' dx="%f"' % dx) + svg.append(' dx="%s"' % dx) dy = new_y - curr_y if dy != 0.0: - svg.append(' dy="%f"' % dy) + svg.append(' dy="%s"' % dy) thetext = escape_xml_text(thetext) @@ -412,13 +407,13 @@ svg.append('</text>\n') if len(svg_rects): - style_number = self._map_style("fill: black; stroke: none") - svg.append('<g class="%s" transform="' % style_number) + style = "fill: black; stroke: none" + svg.append('<g style="%s" transform="' % style) if angle != 0: - svg.append('translate(%f,%f) rotate(%1.1f)' + svg.append('translate(%s,%s) rotate(%1.1f)' % (x,y,-angle) ) else: - svg.append('translate(%f,%f)' % (x, y)) + svg.append('translate(%s,%s)' % (x, y)) svg.append('">\n') for x, y, width, height in svg_rects: @@ -432,16 +427,9 @@ write = self._svgwriter.write if len(self._char_defs): write('<defs id="fontpaths">\n') - for path in self._char_defs.values(): + for char_num, path in self._char_defs.values(): write(path) write('</defs>\n') - if len(self._styles): - write('<style type="text/css">\n') - styles = self._styles.items() - styles.sort() - for style, number in styles: - write('.%s { %s }\n' % (number, style)) - write('</style>\n') write('</svg>\n') def flipy(self): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-07 18:53:59
|
Revision: 3813 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3813&view=rev Author: mdboom Date: 2007-09-07 11:53:51 -0700 (Fri, 07 Sep 2007) Log Message: ----------- Merged revisions 3810-3812 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3811 | mdboom | 2007-09-07 14:07:43 -0400 (Fri, 07 Sep 2007) | 2 lines Note that .bmp is no longer an alias for .raw ........ r3812 | mdboom | 2007-09-07 14:08:43 -0400 (Fri, 07 Sep 2007) | 2 lines Turn svg.embed_char_paths on by default. ........ Modified Paths: -------------- branches/transforms/CHANGELOG branches/transforms/lib/matplotlib/config/mplconfig.py branches/transforms/lib/matplotlib/config/rcsetup.py branches/transforms/lib/matplotlib/rcsetup.py branches/transforms/matplotlibrc.template Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3809 + /trunk/matplotlib:1-3812 Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-09-07 18:08:43 UTC (rev 3812) +++ branches/transforms/CHANGELOG 2007-09-07 18:53:51 UTC (rev 3813) @@ -1,3 +1,5 @@ +2007-09-06 .bmp file format is now longer an alias for .raw + 2007-09-07 Added clip path support to pdf backend. - JKS 2007-09-06 Fixed a bug in the embedding of Type 1 fonts in PDF. Modified: branches/transforms/lib/matplotlib/config/mplconfig.py =================================================================== --- branches/transforms/lib/matplotlib/config/mplconfig.py 2007-09-07 18:08:43 UTC (rev 3812) +++ branches/transforms/lib/matplotlib/config/mplconfig.py 2007-09-07 18:53:51 UTC (rev 3813) @@ -101,7 +101,7 @@ class svg(TConfig): image_inline = T.true image_noscale = T.false - embed_chars = T.false + embed_chars = T.true class lines(TConfig): linewidth = T.Float(1.0) Modified: branches/transforms/lib/matplotlib/config/rcsetup.py =================================================================== --- branches/transforms/lib/matplotlib/config/rcsetup.py 2007-09-07 18:08:43 UTC (rev 3812) +++ branches/transforms/lib/matplotlib/config/rcsetup.py 2007-09-07 18:53:51 UTC (rev 3813) @@ -466,7 +466,7 @@ 'pdf.fonttype' : [3, validate_fonttype], # 3 (Type3) or 42 (Truetype) 'svg.image_inline' : [True, validate_bool], # write raster image data directly into the svg file 'svg.image_noscale' : [False, validate_bool], # suppress scaling of raster data embedded in SVG - 'svg.embed_char_paths' : [False, validate_bool], # True to save all characters as paths in the SVG + '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 } Modified: branches/transforms/lib/matplotlib/rcsetup.py =================================================================== --- branches/transforms/lib/matplotlib/rcsetup.py 2007-09-07 18:08:43 UTC (rev 3812) +++ branches/transforms/lib/matplotlib/rcsetup.py 2007-09-07 18:53:51 UTC (rev 3813) @@ -466,7 +466,7 @@ 'pdf.fonttype' : [3, validate_fonttype], # 3 (Type3) or 42 (Truetype) 'svg.image_inline' : [True, validate_bool], # write raster image data directly into the svg file 'svg.image_noscale' : [False, validate_bool], # suppress scaling of raster data embedded in SVG - 'svg.embed_char_paths' : [False, validate_bool], # True to save all characters as paths in the SVG + '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 } Modified: branches/transforms/matplotlibrc.template =================================================================== --- branches/transforms/matplotlibrc.template 2007-09-07 18:08:43 UTC (rev 3812) +++ branches/transforms/matplotlibrc.template 2007-09-07 18:53:51 UTC (rev 3813) @@ -292,7 +292,7 @@ # svg backend params #svg.image_inline : True # write raster image data directly into the svg file #svg.image_noscale : False # suppress scaling of raster data embedded in SVG -#svg.embed_chars : False # embed character outlines in the SVG file +#svg.embed_chars : True # embed character outlines in the SVG file # Set the verbose flags. This controls how much information # matplotlib gives you at runtime and where it goes. The verbosity This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-10 17:45:18
|
Revision: 3824 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3824&view=rev Author: mdboom Date: 2007-09-10 10:45:15 -0700 (Mon, 10 Sep 2007) Log Message: ----------- Merged revisions 3813-3823 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3814 | jouni | 2007-09-07 15:45:48 -0400 (Fri, 07 Sep 2007) | 3 lines In backend_pdf usetex, gather consecutive characters with same x coordinate and same font into strings. ........ r3815 | mdboom | 2007-09-07 16:28:01 -0400 (Fri, 07 Sep 2007) | 3 lines Support characters composed of multiple characters. Only one supported at the moment is AA (angstrom). ........ r3816 | jouni | 2007-09-07 16:43:20 -0400 (Fri, 07 Sep 2007) | 2 lines Return widths of glyphs to caller ........ r3817 | efiring | 2007-09-08 19:53:06 -0400 (Sat, 08 Sep 2007) | 2 lines Delete gd and paint backends. ........ r3818 | efiring | 2007-09-08 20:41:17 -0400 (Sat, 08 Sep 2007) | 2 lines Removed matplotlibrc; it is generated by setup.py. ........ r3819 | efiring | 2007-09-09 18:41:36 -0400 (Sun, 09 Sep 2007) | 2 lines Factored plotting part of pylab.py into pyplot.py ........ r3820 | efiring | 2007-09-09 21:42:39 -0400 (Sun, 09 Sep 2007) | 2 lines Numpification and cleanup of examples ........ r3821 | efiring | 2007-09-10 02:55:10 -0400 (Mon, 10 Sep 2007) | 2 lines Removed obsolete and broken methods from Axes and PolarAxes ........ Modified Paths: -------------- branches/transforms/API_CHANGES branches/transforms/CHANGELOG branches/transforms/boilerplate.py branches/transforms/examples/animation_blit.py branches/transforms/examples/animation_blit_fltk.py branches/transforms/examples/animation_blit_qt.py branches/transforms/examples/animation_blit_qt4.py branches/transforms/examples/animation_blit_tk.py branches/transforms/examples/animation_blit_wx.py branches/transforms/examples/backend_driver.py branches/transforms/examples/clippedline.py branches/transforms/examples/collections_demo.py branches/transforms/examples/color_by_yvalue.py branches/transforms/examples/contourf_demo.py branches/transforms/examples/data_helper.py branches/transforms/examples/dynamic_demo_wx.py branches/transforms/examples/dynamic_image_wxagg.py branches/transforms/examples/dynamic_image_wxagg2.py branches/transforms/examples/embedding_in_gtk.py branches/transforms/examples/embedding_in_gtk2.py branches/transforms/examples/embedding_in_gtk3.py branches/transforms/examples/embedding_in_qt.py branches/transforms/examples/embedding_in_qt4.py branches/transforms/examples/embedding_in_tk.py branches/transforms/examples/embedding_in_tk2.py branches/transforms/examples/embedding_in_wx.py branches/transforms/examples/embedding_in_wx2.py branches/transforms/examples/embedding_in_wx3.py branches/transforms/examples/embedding_in_wx4.py branches/transforms/examples/gtk_spreadsheet.py branches/transforms/examples/histogram_demo_canvasagg.py branches/transforms/examples/image_masked.py branches/transforms/examples/mathtext_wx.py branches/transforms/examples/mpl_with_glade.py branches/transforms/examples/multi_image.py branches/transforms/examples/pcolor_nonuniform.py branches/transforms/examples/polar_bar.py branches/transforms/examples/polar_demo.py branches/transforms/examples/polar_legend.py branches/transforms/examples/poly_editor.py branches/transforms/examples/printing_in_wx.py branches/transforms/examples/pythonic_matplotlib.py branches/transforms/examples/rc_traits.py branches/transforms/examples/scatter_masked.py branches/transforms/examples/strip_chart_demo.py branches/transforms/examples/tex_demo.py branches/transforms/examples/tex_unicode_demo.py branches/transforms/examples/vline_demo.py branches/transforms/examples/webapp_demo.py branches/transforms/examples/wxcursor_demo.py branches/transforms/lib/matplotlib/__init__.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/backends/__init__.py branches/transforms/lib/matplotlib/backends/backend_pdf.py branches/transforms/lib/matplotlib/config/mplconfig.py branches/transforms/lib/matplotlib/config/rcsetup.py branches/transforms/lib/matplotlib/dviread.py branches/transforms/lib/matplotlib/mathtext.py branches/transforms/lib/matplotlib/mlab.py branches/transforms/lib/matplotlib/mpl-data/matplotlib.conf branches/transforms/lib/matplotlib/pylab.py branches/transforms/setupext.py Added Paths: ----------- branches/transforms/lib/matplotlib/pyplot.py Removed Paths: ------------- branches/transforms/examples/anim_tk.py branches/transforms/examples/gdtest.py branches/transforms/examples/image_demo_na.py branches/transforms/lib/matplotlib/backends/backend_gd.py branches/transforms/lib/matplotlib/backends/backend_paint.py branches/transforms/lib/matplotlib/mpl-data/matplotlibrc Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3812 + /trunk/matplotlib:1-3823 Modified: branches/transforms/API_CHANGES =================================================================== --- branches/transforms/API_CHANGES 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/API_CHANGES 2007-09-10 17:45:15 UTC (rev 3824) @@ -1,3 +1,5 @@ + The gd and paint backends have been deleted. + The errorbar method and function now accept additional kwargs so that upper and lower limits can be indicated by capping the bar with a caret instead of a straight line segment. Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/CHANGELOG 2007-09-10 17:45:15 UTC (rev 3824) @@ -1,3 +1,16 @@ +2007-09-09 Split out the plotting part of pylab and put it in + pyplot.py; removed numerix from the remaining pylab.py, + which imports everything from pyplot.py. The intention + is that apart from cleanups, the result of importing + from pylab is nearly unchanged, but there is the + new alternative of importing from pyplot to get + the state-engine graphics without all the numeric + functions. + Numpified examples; deleted two that were obsolete; + modified some to use pyplot. - EF + +2007-09-08 Eliminated gd and paint backends - EF + 2007-09-06 .bmp file format is now longer an alias for .raw 2007-09-07 Added clip path support to pdf backend. - JKS @@ -6,17 +19,17 @@ Now it doesn't crash Preview.app. - JKS 2007-09-06 Refactored image saving code so that all GUI backends can - save most image types. See FILETYPES for a matrix of - backends and their supported file types. - Backend canvases should no longer write their own print_figure() - method -- instead they should write a print_xxx method for - each filetype they can output and add an entry to their - class-scoped filetypes dictionary. - MGD + save most image types. See FILETYPES for a matrix of + backends and their supported file types. + Backend canvases should no longer write their own print_figure() + method -- instead they should write a print_xxx method for + each filetype they can output and add an entry to their + class-scoped filetypes dictionary. - MGD 2007-09-05 Fixed Qt version reporting in setupext.py - DSD 2007-09-04 Embedding Type 1 fonts in PDF, and thus usetex support - via dviread, sort of works. To test, enable it by + via dviread, sort of works. To test, enable it by renaming _draw_tex to draw_tex. - JKS 2007-09-03 Added ability of errorbar show limits via caret or Modified: branches/transforms/boilerplate.py =================================================================== --- branches/transforms/boilerplate.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/boilerplate.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -29,7 +29,7 @@ return ret if Axes.%(func)s.__doc__ is not None: %(func)s.__doc__ = dedent(Axes.%(func)s.__doc__) + \"\"\" -Addition kwargs: hold = [True|False] overrides default hold state\"\"\" +Additional kwargs: hold = [True|False] overrides default hold state\"\"\" """ _fmtmisc = """\ @@ -74,6 +74,8 @@ 'plot', 'plot_date', 'psd', + 'quiver', + 'quiverkey', 'scatter', 'semilogx', 'semilogy', @@ -82,8 +84,6 @@ 'stem', 'step', 'vlines', - 'quiver', - 'quiverkey', 'xcorr', ) @@ -104,7 +104,6 @@ 'pcolormesh' : 'gci._current = ret', 'imshow' : 'gci._current = ret', 'spy' : 'gci._current = ret', - 'quiver2' : 'gci._current = ret', 'quiver' : 'gci._current = ret', 'specgram' : 'gci._current = ret[-1]', @@ -129,11 +128,13 @@ # This function was autogenerated by boilerplate.py. Do not edit as # changes will be lost def %(name)s(): - 'set the default colormap to %(name)s and apply to current image if any. See help(colormaps) for more information' + ''' + set the default colormap to %(name)s and apply to current image if any. + See help(colormaps) for more information + ''' rc('image', cmap='%(name)s') im = gci() - if im is not None: im.set_cmap(cm.%(name)s) draw_if_interactive() Deleted: branches/transforms/examples/anim_tk.py =================================================================== --- branches/transforms/examples/anim_tk.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/anim_tk.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -1,49 +0,0 @@ -# deprecated - this example is no longer needed. Follow the model of -# anim.py to use interaction = True to avoid all the cruft of timers, -# callbacks and the likes used here - -#!/usr/bin/env python2.3 - -import matplotlib -matplotlib.use('TkAgg') -import pylab - -#import Tkinter as Tk -import matplotlib.numerix as numerix -fig = pylab.figure(1) -ind = numerix.arange(60) - - - -x_tmp=[] -for i in range(100): - x_tmp.append(numerix.sin((ind+i)*numerix.pi/15.0)) - -X=numerix.array(x_tmp) - - -lines = pylab.plot(X[:,0],'o') - -manager = pylab.get_current_fig_manager() - -def updatefig(*args): - updatefig.count += 1 - lines[0].set_ydata(X[:,updatefig.count%60]) - manager.canvas.draw() - return updatefig.count -updatefig.count=-1 - -def run(*args): - print 'called run' - - import time - tstart = time.time() - while 1: - cnt = updatefig() - if cnt==100: break - print 'elapsed', 100.0/(time.time() - tstart) - -import Tkinter as Tk -manager.window.after(10, run) -manager.show() -Tk.mainloop() Modified: branches/transforms/examples/animation_blit.py =================================================================== --- branches/transforms/examples/animation_blit.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/animation_blit.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -10,7 +10,7 @@ import matplotlib matplotlib.use('GTKAgg') -import matplotlib.numerix as nx +import numpy as npy import pylab as p @@ -21,8 +21,8 @@ p.grid() # to ensure proper background restore # create the initial line -x = nx.arange(0,2*nx.pi,0.01) -line, = p.plot(x, nx.sin(x), animated=True, lw=2) +x = npy.arange(0,2*npy.pi,0.01) +line, = p.plot(x, npy.sin(x), animated=True, lw=2) # for profiling tstart = time.time() @@ -34,7 +34,7 @@ # restore the clean slate background canvas.restore_region(update_line.background) # update the data - line.set_ydata(nx.sin(x+update_line.cnt/10.0)) + line.set_ydata(npy.sin(x+update_line.cnt/10.0)) # just draw the animated artist try: ax.draw_artist(line) Modified: branches/transforms/examples/animation_blit_fltk.py =================================================================== --- branches/transforms/examples/animation_blit_fltk.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/animation_blit_fltk.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -3,7 +3,7 @@ import matplotlib matplotlib.use('FltkAgg') import pylab as p -import matplotlib.numerix as nx +import numpy as nx import time Modified: branches/transforms/examples/animation_blit_qt.py =================================================================== --- branches/transforms/examples/animation_blit_qt.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/animation_blit_qt.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -15,7 +15,7 @@ ITERS = 1000 import pylab as p -import matplotlib.numerix as nx +import numpy as npy import time class BlitQT(QObject): @@ -27,8 +27,8 @@ self.cnt = 0 # create the initial line - self.x = nx.arange(0,2*nx.pi,0.01) - self.line, = p.plot(self.x, nx.sin(self.x), animated=True, lw=2) + self.x = npy.arange(0,2*npy.pi,0.01) + self.line, = p.plot(self.x, npy.sin(self.x), animated=True, lw=2) self.background = None @@ -39,7 +39,7 @@ # restore the clean slate background self.canvas.restore_region(self.background) # update the data - self.line.set_ydata(nx.sin(self.x+self.cnt/10.0)) + self.line.set_ydata(npy.sin(self.x+self.cnt/10.0)) # just draw the animated artist self.ax.draw_artist(self.line) # just redraw the axes rectangle Modified: branches/transforms/examples/animation_blit_qt4.py =================================================================== --- branches/transforms/examples/animation_blit_qt4.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/animation_blit_qt4.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -10,7 +10,7 @@ ITERS = 1000 import pylab as p -import matplotlib.numerix as nx +import numpy as npy import time class BlitQT(QtCore.QObject): @@ -22,8 +22,8 @@ self.cnt = 0 # create the initial line - self.x = nx.arange(0,2*nx.pi,0.01) - self.line, = p.plot(self.x, nx.sin(self.x), animated=True, lw=2) + self.x = npy.arange(0,2*npy.pi,0.01) + self.line, = p.plot(self.x, npy.sin(self.x), animated=True, lw=2) self.background = None @@ -34,7 +34,7 @@ # restore the clean slate background self.canvas.restore_region(self.background) # update the data - self.line.set_ydata(nx.sin(self.x+self.cnt/10.0)) + self.line.set_ydata(npy.sin(self.x+self.cnt/10.0)) # just draw the animated artist self.ax.draw_artist(self.line) # just redraw the axes rectangle Modified: branches/transforms/examples/animation_blit_tk.py =================================================================== --- branches/transforms/examples/animation_blit_tk.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/animation_blit_tk.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -6,7 +6,7 @@ import sys import pylab as p -import matplotlib.numerix as nx +import numpy as npy import time ax = p.subplot(111) @@ -14,8 +14,8 @@ # create the initial line -x = nx.arange(0,2*nx.pi,0.01) -line, = p.plot(x, nx.sin(x), animated=True, lw=2) +x = npy.arange(0,2*npy.pi,0.01) +line, = p.plot(x, npy.sin(x), animated=True, lw=2) def run(*args): background = canvas.copy_from_bbox(ax.bbox) @@ -26,7 +26,7 @@ # restore the clean slate background canvas.restore_region(background) # update the data - line.set_ydata(nx.sin(x+run.cnt/10.0)) + line.set_ydata(npy.sin(x+run.cnt/10.0)) # just draw the animated artist ax.draw_artist(line) # just redraw the axes rectangle Modified: branches/transforms/examples/animation_blit_wx.py =================================================================== --- branches/transforms/examples/animation_blit_wx.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/animation_blit_wx.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -12,7 +12,7 @@ import wx import sys import pylab as p -import matplotlib.numerix as nx +import numpy as npy import time @@ -30,8 +30,8 @@ p.grid() # to ensure proper background restore # create the initial line -x = nx.arange(0,2*nx.pi,0.01) -line, = p.plot(x, nx.sin(x), animated=True, lw=2) +x = npy.arange(0,2*npy.pi,0.01) +line, = p.plot(x, npy.sin(x), animated=True, lw=2) # for profiling tstart = time.time() @@ -46,7 +46,7 @@ # restore the clean slate background canvas.restore_region(update_line.background) # update the data - line.set_ydata(nx.sin(x+update_line.cnt/10.0)) + line.set_ydata(npy.sin(x+update_line.cnt/10.0)) # just draw the animated artist ax.draw_artist(line) # just redraw the axes rectangle Modified: branches/transforms/examples/backend_driver.py =================================================================== --- branches/transforms/examples/backend_driver.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/backend_driver.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -42,7 +42,6 @@ 'histogram_demo.py', 'image_demo.py', 'image_demo2.py', - 'image_demo_na.py', 'image_masked.py', 'image_origin.py', 'invert_axes.py', @@ -158,7 +157,7 @@ if __name__ == '__main__': times = {} - default_backends = ['Agg', 'PS', 'SVG', 'Template'] + default_backends = ['Agg', 'PS', 'SVG', 'PDF', 'Template'] if sys.platform == 'win32': python = r'c:\Python24\python.exe' else: Modified: branches/transforms/examples/clippedline.py =================================================================== --- branches/transforms/examples/clippedline.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/clippedline.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -4,7 +4,7 @@ """ from matplotlib.lines import Line2D -import matplotlib.numerix as nx +import numpy as npy from pylab import figure, show class ClippedLine(Line2D): @@ -19,13 +19,13 @@ def set_data(self, *args, **kwargs): Line2D.set_data(self, *args, **kwargs) - self.xorig = nx.array(self._x) - self.yorig = nx.array(self._y) + self.xorig = npy.array(self._x) + self.yorig = npy.array(self._y) def draw(self, renderer): xlim = self.ax.get_xlim() - ind0, ind1 = nx.searchsorted(self.xorig, xlim) + ind0, ind1 = npy.searchsorted(self.xorig, xlim) self._x = self.xorig[ind0:ind1] self._y = self.yorig[ind0:ind1] N = len(self._x) @@ -43,8 +43,8 @@ fig = figure() ax = fig.add_subplot(111, autoscale_on=False) -t = nx.arange(0.0, 100.0, 0.01) -s = nx.sin(2*nx.pi*t) +t = npy.arange(0.0, 100.0, 0.01) +s = npy.sin(2*npy.pi*t) line = ClippedLine(ax, t, s, color='g', ls='-', lw=2) ax.add_line(line) ax.set_xlim(10,30) Modified: branches/transforms/examples/collections_demo.py =================================================================== --- branches/transforms/examples/collections_demo.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/collections_demo.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -17,10 +17,10 @@ ''' -import pylab as P +import matplotlib.pyplot as P from matplotlib import collections, axes, transforms from matplotlib.colors import colorConverter -import matplotlib.numerix as N +import numpy as N nverts = 50 npts = 100 @@ -33,8 +33,8 @@ spiral = zip(xx,yy) # Make some offsets -xo = P.randn(npts) -yo = P.randn(npts) +xo = N.random.randn(npts) +yo = N.random.randn(npts) xyo = zip(xo, yo) # Make a list of colors cycling through the rgbcmyk series. @@ -90,7 +90,7 @@ a = fig.add_subplot(2,2,3) col = collections.RegularPolyCollection(fig.dpi, 7, - sizes = P.fabs(xx)*10, offsets=xyo, + sizes = N.fabs(xx)*10, offsets=xyo, transOffset=a.transData) a.add_collection(col, autolim=True) trans = transforms.scale_transform(fig.dpi/transforms.Value(72.), @@ -111,12 +111,12 @@ ncurves = 20 offs = (0.1, 0.0) -yy = P.linspace(0, 2*N.pi, nverts) -ym = P.amax(yy) +yy = N.linspace(0, 2*N.pi, nverts) +ym = N.amax(yy) xx = (0.2 + (ym-yy)/ym)**2 * N.cos(yy-0.4) * 0.5 segs = [] for i in range(ncurves): - xxx = xx + 0.02*P.randn(nverts) + xxx = xx + 0.02*N.random.randn(nverts) curve = zip(xxx, yy*100) segs.append(curve) Modified: branches/transforms/examples/color_by_yvalue.py =================================================================== --- branches/transforms/examples/color_by_yvalue.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/color_by_yvalue.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -1,7 +1,7 @@ # use masked arrays to plot a line with different colors by y-value -import matplotlib.numerix.ma as ma -from matplotlib.numerix import logical_or -from pylab import plot, show, arange, sin, pi +import matplotlib.numerix.npyma as ma +from numpy import logical_or, arange, sin, pi +from matplotlib.pyplot import plot, show t = arange(0.0, 2.0, 0.01) s = sin(2*pi*t) Modified: branches/transforms/examples/contourf_demo.py =================================================================== --- branches/transforms/examples/contourf_demo.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/contourf_demo.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -1,6 +1,6 @@ #!/usr/bin/env python from pylab import * -import matplotlib.numerix.ma as ma +import matplotlib.numerix.npyma as ma origin = 'lower' #origin = 'upper' Modified: branches/transforms/examples/data_helper.py =================================================================== --- branches/transforms/examples/data_helper.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/data_helper.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -1,7 +1,8 @@ #!/usr/bin/env python # Some functions to load a return data for the plot demos -from matplotlib.numerix import fromstring, argsort, take, array, resize +from numpy import fromstring, argsort, take, array, resize + def get_two_stock_data(): """ load stock time and price data for two stocks The return values Modified: branches/transforms/examples/dynamic_demo_wx.py =================================================================== --- branches/transforms/examples/dynamic_demo_wx.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/dynamic_demo_wx.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -63,7 +63,7 @@ from matplotlib.figure import Figure from matplotlib.axes import Subplot -import matplotlib.numerix as numpy +import numpy from wx import * Modified: branches/transforms/examples/dynamic_image_wxagg.py =================================================================== --- branches/transforms/examples/dynamic_image_wxagg.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/dynamic_image_wxagg.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -12,26 +12,13 @@ import matplotlib matplotlib.use('WXAgg') -# jdh: you need to control Numeric vs numarray with numerix, otherwise -# matplotlib may be using numeric under the hood and while you are -# using numarray and this isn't efficient. Also, if you use -# numerix=numarray, it is important to compile matplotlib for numarray -# by setting NUMERIX = 'numarray' in setup.py before building from matplotlib import rcParams -##rcParams['numerix'] = 'numarray' - - -# jdh: you can import cm directly, you don't need to go via -# pylab import matplotlib.cm as cm from matplotlib.backends.backend_wxagg import Toolbar, FigureCanvasWxAgg -# jdh: you don't need a figure manager in the GUI - this class was -# designed for the pylab interface - from matplotlib.figure import Figure -import matplotlib.numerix as numerix +import numpy as npy import wx @@ -75,12 +62,12 @@ # jdh you can add a subplot directly from the fig rather than # the fig manager a = self.fig.add_subplot(111) - self.x = numerix.arange(120.0)*2*numerix.pi/120.0 + self.x = npy.arange(120.0)*2*npy.pi/120.0 self.x.resize((100,120)) - self.y = numerix.arange(100.0)*2*numerix.pi/100.0 + self.y = npy.arange(100.0)*2*npy.pi/100.0 self.y.resize((120,100)) - self.y = numerix.transpose(self.y) - z = numerix.sin(self.x) + numerix.cos(self.y) + self.y = npy.transpose(self.y) + z = npy.sin(self.x) + npy.cos(self.y) self.im = a.imshow( z, cmap=cm.jet)#, interpolation='nearest') def GetToolBar(self): @@ -89,9 +76,9 @@ return self.toolbar def onTimer(self, evt): - self.x += numerix.pi/15 - self.y += numerix.pi/20 - z = numerix.sin(self.x) + numerix.cos(self.y) + self.x += npy.pi/15 + self.y += npy.pi/20 + z = npy.sin(self.x) + npy.cos(self.y) self.im.set_array(z) self.canvas.draw() #self.canvas.gui_repaint() # jdh wxagg_draw calls this already Modified: branches/transforms/examples/dynamic_image_wxagg2.py =================================================================== --- branches/transforms/examples/dynamic_image_wxagg2.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/dynamic_image_wxagg2.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -12,24 +12,14 @@ import matplotlib matplotlib.use('WXAgg') -# jdh: you need to control Numeric vs numarray with numerix, otherwise -# matplotlib may be using numeric under the hood and while you are -# using numarray and this isn't efficient. Also, if you use -# numerix=numarray, it is important to compile matplotlib for numarray -# by setting NUMERIX = 'numarray' in setup.py before building from matplotlib import rcParams import numpy as npy -# jdh: you can import cm directly, you don't need to go via -# pylab import matplotlib.cm as cm from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg from matplotlib.backends.backend_wx import NavigationToolbar2Wx -# jdh: you don't need a figure manager in the GUI - this class was -# designed for the pylab interface - from matplotlib.figure import Figure from wx import * Modified: branches/transforms/examples/embedding_in_gtk.py =================================================================== --- branches/transforms/examples/embedding_in_gtk.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/embedding_in_gtk.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -8,7 +8,7 @@ from matplotlib.axes import Subplot from matplotlib.figure import Figure -from matplotlib.numerix import arange, sin, pi +from numpy import arange, sin, pi # uncomment to select /GTK/GTKAgg/GTKCairo from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas Modified: branches/transforms/examples/embedding_in_gtk2.py =================================================================== --- branches/transforms/examples/embedding_in_gtk2.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/embedding_in_gtk2.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -7,7 +7,7 @@ from matplotlib.axes import Subplot from matplotlib.figure import Figure -from matplotlib.numerix import arange, sin, pi +from numpy import arange, sin, pi # uncomment to select /GTK/GTKAgg/GTKCairo from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas Modified: branches/transforms/examples/embedding_in_gtk3.py =================================================================== --- branches/transforms/examples/embedding_in_gtk3.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/embedding_in_gtk3.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -7,7 +7,7 @@ from matplotlib.axes import Subplot from matplotlib.figure import Figure -from matplotlib.numerix import arange, sin, pi +from numpy import arange, sin, pi # uncomment to select /GTK/GTKAgg/GTKCairo #from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas Modified: branches/transforms/examples/embedding_in_qt.py =================================================================== --- branches/transforms/examples/embedding_in_qt.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/embedding_in_qt.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -11,7 +11,7 @@ import sys, os, random from qt import * -from matplotlib.numerix import arange, sin, pi +from numpy import arange, sin, pi from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure Modified: branches/transforms/examples/embedding_in_qt4.py =================================================================== --- branches/transforms/examples/embedding_in_qt4.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/embedding_in_qt4.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -12,7 +12,7 @@ import sys, os, random from PyQt4 import QtGui, QtCore -from matplotlib.numerix import arange, sin, pi +from numpy import arange, sin, pi from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure Modified: branches/transforms/examples/embedding_in_tk.py =================================================================== --- branches/transforms/examples/embedding_in_tk.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/embedding_in_tk.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -2,7 +2,7 @@ import matplotlib matplotlib.use('TkAgg') -from matplotlib.numerix import arange, sin, pi +from numpy import arange, sin, pi from matplotlib.axes import Subplot from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg from matplotlib.figure import Figure Modified: branches/transforms/examples/embedding_in_tk2.py =================================================================== --- branches/transforms/examples/embedding_in_tk2.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/embedding_in_tk2.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -2,7 +2,7 @@ import matplotlib matplotlib.use('TkAgg') -from matplotlib.numerix import arange, sin, pi +from numpy import arange, sin, pi from matplotlib.axes import Subplot from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg from matplotlib.figure import Figure Modified: branches/transforms/examples/embedding_in_wx.py =================================================================== --- branches/transforms/examples/embedding_in_wx.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/embedding_in_wx.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -44,7 +44,7 @@ from matplotlib.figure import Figure from matplotlib.axes import Subplot -import matplotlib.numerix as numpy +import numpy from wx import * Modified: branches/transforms/examples/embedding_in_wx2.py =================================================================== --- branches/transforms/examples/embedding_in_wx2.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/embedding_in_wx2.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -4,7 +4,7 @@ toolbar - comment out the setA_toolbar line for no toolbar """ -from matplotlib.numerix import arange, sin, pi +from numpy import arange, sin, pi import matplotlib Modified: branches/transforms/examples/embedding_in_wx3.py =================================================================== --- branches/transforms/examples/embedding_in_wx3.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/embedding_in_wx3.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -25,8 +25,6 @@ from matplotlib.backends.backend_wxagg import Toolbar, FigureCanvasWxAgg from matplotlib.figure import Figure import numpy as npy -import matplotlib.numerix.mlab as mlab -from matplotlib.mlab import meshgrid from wx import * from wx.xrc import * @@ -61,11 +59,11 @@ x = npy.arange(120.0)*2*npy.pi/60.0 y = npy.arange(100.0)*2*npy.pi/50.0 - self.x, self.y = meshgrid(x, y) + self.x, self.y = npy.meshgrid(x, y) z = npy.sin(self.x) + npy.cos(self.y) self.im = a.imshow( z, cmap=cm.jet)#, interpolation='nearest') - zmax = mlab.max(mlab.max(z))-ERR_TOL + zmax = npy.amax(z) - ERR_TOL ymax_i, xmax_i = npy.nonzero(z >= zmax) if self.im.origin == 'upper': ymax_i = z.shape[0]-ymax_i @@ -84,7 +82,7 @@ z = npy.sin(self.x) + npy.cos(self.y) self.im.set_array(z) - zmax = mlab.max(mlab.max(z))-ERR_TOL + zmax = npy.amax(z) - ERR_TOL ymax_i, xmax_i = npy.nonzero(z >= zmax) if self.im.origin == 'upper': ymax_i = z.shape[0]-ymax_i Modified: branches/transforms/examples/embedding_in_wx4.py =================================================================== --- branches/transforms/examples/embedding_in_wx4.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/embedding_in_wx4.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -4,7 +4,7 @@ toolbar """ -from matplotlib.numerix import arange, sin, pi +from numpy import arange, sin, pi import matplotlib @@ -19,7 +19,7 @@ from matplotlib.backends.backend_wx import _load_bitmap from matplotlib.figure import Figure -from matplotlib.numerix.mlab import rand +from numpy.random import rand from wx import * Deleted: branches/transforms/examples/gdtest.py =================================================================== --- branches/transforms/examples/gdtest.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/gdtest.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -1,34 +0,0 @@ -#!/usr/bin/env python -import matplotlib -matplotlib.use('GD') -from pylab import * - -def f(t): - s1 = cos(2*pi*t) - e1 = exp(-t) - return multiply(s1,e1) - -t1 = arange(0.0, 5.0, .1) -t2 = arange(0.0, 5.0, 0.02) -t3 = arange(0.0, 2.0, 0.01) - - -if 1: - subplot(211) - l = plot(t1, f(t1), 'k-^') - setp(l, 'markerfacecolor', 'r') - xlim(0,5) - title('A tale of 2 subplots', fontsize=12) - ylabel('Signal 1', fontsize=10) - - subplot(212) - l = plot(t1, f(t1), 'k->') - xlim(0,5) - ylabel('Signal 2', fontsize=10) - xlabel('time (s)', fontsize=10, fontname='Courier') - -ax = gca() - - -#savefig('gdtest', dpi=150) -show() Modified: branches/transforms/examples/gtk_spreadsheet.py =================================================================== --- branches/transforms/examples/gtk_spreadsheet.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/gtk_spreadsheet.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -14,15 +14,13 @@ matplotlib.use('GTKAgg') # or 'GTK' from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas -#from matplotlib.numerix import rand -from matplotlib.numerix.random_array import random +from numpy.random import random from matplotlib.figure import Figure class DataManager(gtk.Window): numRows, numCols = 20,10 - #data = rand(numRows, numCols) data = random((numRows, numCols)) def __init__(self): Modified: branches/transforms/examples/histogram_demo_canvasagg.py =================================================================== --- branches/transforms/examples/histogram_demo_canvasagg.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/histogram_demo_canvasagg.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -13,7 +13,8 @@ from matplotlib.figure import Figure from matplotlib.axes import Subplot from matplotlib.mlab import normpdf -from matplotlib.numerix.mlab import randn +from numpy.random import randn +import numpy fig = Figure(figsize=(5,4), dpi=100) ax = fig.add_subplot(111) @@ -42,14 +43,14 @@ s = canvas.tostring_rgb() # save this and convert to bitmap as needed -# get the figure dimensions for creating bitmaps or numeric arrays, +# get the figure dimensions for creating bitmaps or numpy arrays, # etc. l,b,w,h = fig.bbox.get_bounds() w, h = int(w), int(h) if 0: - # convert to a Numeric array - X = fromstring(s, UInt8) + # convert to a numpy array + X = numpy.fromstring(s, numpy.uint8) X.shape = h, w, 3 if 0: Deleted: branches/transforms/examples/image_demo_na.py =================================================================== --- branches/transforms/examples/image_demo_na.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/image_demo_na.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -1,40 +0,0 @@ -#!/usr/bin/env python -from matplotlib import rcParams -rcParams['numerix'] = 'numarray' - -from pylab import * - - -def bivariate_normal(X, Y, sigmax=1.0, sigmay=1.0, - mux=0.0, muy=0.0, sigmaxy=0.0): - """ - Bivariate gaussan distribution for equal shape X, Y - - http://mathworld.wolfram.com/BivariateNormalDistribution.html - """ - Xmu = X-mux - Ymu = Y-muy - - rho = sigmaxy/(sigmax*sigmay) - z = (1.0/sigmax**2)*Xmu**2 + (1.0/sigmay)*Ymu**2 - (2*rho/(sigmax*sigmay))*Xmu*Ymu - return 1.0/(2*pi*sigmax*sigmay*(1-rho**2)) * exp( -1/(2*(1-rho**2))*z) - - -delta = 0.025 -x = arange(-3.0, 3.0, delta) -y = arange(-3.0, 3.0, delta) -X,Y = meshgrid(x, y) -Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) -Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1) - -# difference of Gaussians -im = imshow(Z2-Z1) - -# set the interpolation method: 'nearest', 'bilinear', 'bicubic' and much more -im.set_interpolation('bilinear') - - -axis('off') -#savefig('test') -show() - Modified: branches/transforms/examples/image_masked.py =================================================================== --- branches/transforms/examples/image_masked.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/image_masked.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -4,7 +4,7 @@ ''' from pylab import * -import matplotlib.numerix.ma as ma +import matplotlib.numerix.npyma as ma import matplotlib.colors as colors delta = 0.025 Modified: branches/transforms/examples/mathtext_wx.py =================================================================== --- branches/transforms/examples/mathtext_wx.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/mathtext_wx.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -5,7 +5,7 @@ import matplotlib matplotlib.use("WxAgg") -from matplotlib.numerix import arange, sin, pi, cos, log +from numpy import arange, sin, pi, cos, log from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas from matplotlib.backends.backend_wx import NavigationToolbar2Wx from matplotlib.figure import Figure @@ -42,14 +42,14 @@ self.figure = Figure() self.axes = self.figure.add_subplot(111) self.change_plot(0) - + self.canvas = FigureCanvas(self, -1, self.figure) self.sizer = wx.BoxSizer(wx.VERTICAL) self.add_buttonbar() self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.add_toolbar() # comment this out for no toolbar - + menuBar = wx.MenuBar() # File Menu @@ -104,21 +104,21 @@ def OnChangePlot(self, event): self.change_plot(event.GetId() - 1000) - + def change_plot(self, plot_number): t = arange(1.0,3.0,0.01) s = functions[plot_number][1](t) self.axes.clear() self.axes.plot(t, s) self.Refresh() - + class MyApp(wx.App): def OnInit(self): frame = CanvasFrame(None, "wxPython mathtext demo app") self.SetTopWindow(frame) frame.Show(True) return True - + app = MyApp() app.MainLoop() Modified: branches/transforms/examples/mpl_with_glade.py =================================================================== --- branches/transforms/examples/mpl_with_glade.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/mpl_with_glade.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -8,7 +8,7 @@ from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar from matplotlib.widgets import SpanSelector -from matplotlib.numerix import arange, sin, pi +from numpy import arange, sin, pi import gtk import gtk.glade Modified: branches/transforms/examples/multi_image.py =================================================================== --- branches/transforms/examples/multi_image.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/multi_image.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -5,19 +5,20 @@ It also illustrates colorbar tick labelling with a multiplier. ''' -import pylab +from matplotlib.pyplot import figure, show, sci from matplotlib import cm, colors from matplotlib.font_manager import FontProperties -from matplotlib.numerix.mlab import amin, amax +from numpy import amin, amax, ravel +from numpy.random import rand Nr = 3 Nc = 2 -fig = pylab.gcf() +fig = figure() cmap = cm.cool figtitle = 'Multiple images' -t = pylab.gcf().text(0.5, 0.95, figtitle, +t = fig.text(0.5, 0.95, figtitle, horizontalalignment='center', fontproperties=FontProperties(size=16)) @@ -37,8 +38,8 @@ a.set_xticklabels([]) # Make some fake data with a range that varies # somewhat from one plot to the next. - data =((1+i+j)/10.0)*pylab.rand(10,20)*1e-6 - dd = pylab.ravel(data) + data =((1+i+j)/10.0)*rand(10,20)*1e-6 + dd = ravel(data) # Manually find the min and max of all colors for # use in setting the color scale. vmin = min(vmin, amin(dd)) @@ -60,12 +61,13 @@ # We need the following only if we want to run this # script interactively and be able to change the colormap. -pylab.sci(images[0]) -pylab.show() +sci(images[0]) +show() + Modified: branches/transforms/examples/pcolor_nonuniform.py =================================================================== --- branches/transforms/examples/pcolor_nonuniform.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/pcolor_nonuniform.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -1,11 +1,11 @@ -from pylab import figure, show -import matplotlib.numerix as nx +from matplotlib.pyplot import figure, show +import numpy as npy from matplotlib.image import NonUniformImage -x = nx.arange(-4, 4, 0.005) -y = nx.arange(-4, 4, 0.005) +x = npy.arange(-4, 4, 0.005) +y = npy.arange(-4, 4, 0.005) print 'Size %d points' % (len(x) * len(y)) -z = nx.sqrt(x[nx.NewAxis,:]**2 + y[:,nx.NewAxis]**2) +z = npy.sqrt(x[npy.newaxis,:]**2 + y[:,npy.newaxis]**2) fig = figure() ax = fig.add_subplot(111) Modified: branches/transforms/examples/polar_bar.py =================================================================== --- branches/transforms/examples/polar_bar.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/polar_bar.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -1,9 +1,8 @@ #!/usr/bin/env python -import matplotlib.numerix as nx -from matplotlib.mlab import linspace +import numpy as npy import matplotlib.cm as cm -from pylab import figure, show, rc +from matplotlib.pyplot import figure, show, rc # force square figure and square axes looks better for polar, IMO @@ -11,9 +10,9 @@ ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True) N = 20 -theta = nx.arange(0.0, 2*nx.pi, 2*nx.pi/N) -radii = 10*nx.mlab.rand(N) -width = nx.pi/4*nx.mlab.rand(N) +theta = npy.arange(0.0, 2*npy.pi, 2*npy.pi/N) +radii = 10*npy.random.rand(N) +width = npy.pi/4*npy.random.rand(N) bars = ax.bar(theta, radii, width=width, bottom=0.1) for r,bar in zip(radii, bars): bar.set_facecolor( cm.jet(r/10.)) Modified: branches/transforms/examples/polar_demo.py =================================================================== --- branches/transforms/examples/polar_demo.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/polar_demo.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -39,8 +39,8 @@ # See the pylab rgrids and thetagrids functions for # information on how to customize the grid locations and labels -import matplotlib.numerix as nx -from pylab import figure, show, rc +import numpy as npy +from matplotlib.pyplot import figure, show, rc # radar green, solid grid lines rc('grid', color='#316931', linewidth=1, linestyle='-') @@ -51,8 +51,8 @@ fig = figure(figsize=(8,8)) ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True, axisbg='#d5de9c') -r = nx.arange(0, 3.0, 0.01) -theta = 2*nx.pi*r +r = npy.arange(0, 3.0, 0.01) +theta = 2*npy.pi*r ax.plot(theta, r, color='#ee8d18', lw=3) ax.set_rmax(2.0) Modified: branches/transforms/examples/polar_legend.py =================================================================== --- branches/transforms/examples/polar_legend.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/polar_legend.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -1,7 +1,7 @@ #!/usr/bin/env python -import matplotlib.numerix as nx -from pylab import figure, show, rc +import numpy as npy +from matplotlib.pyplot import figure, show, rc # radar green, solid grid lines rc('grid', color='#316931', linewidth=1, linestyle='-') @@ -12,8 +12,8 @@ fig = figure(figsize=(8,8)) ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True, axisbg='#d5de9c') -r = nx.arange(0, 3.0, 0.01) -theta = 2*nx.pi*r +r = npy.arange(0, 3.0, 0.01) +theta = 2*npy.pi*r ax.plot(theta, r, color='#ee8d18', lw=3, label='a line') ax.plot(0.5*theta, r, color='blue', ls='--', lw=3, label='another line') ax.legend() Modified: branches/transforms/examples/poly_editor.py =================================================================== --- branches/transforms/examples/poly_editor.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/poly_editor.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -5,8 +5,7 @@ """ from matplotlib.artist import Artist from matplotlib.patches import Polygon, CirclePolygon -from matplotlib.numerix import sqrt, nonzero, equal, asarray, dot, Float -from matplotlib.numerix.mlab import amin +from numpy import sqrt, nonzero, equal, asarray, dot, amin from matplotlib.mlab import dist_point_to_segment Modified: branches/transforms/examples/printing_in_wx.py =================================================================== --- branches/transforms/examples/printing_in_wx.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/printing_in_wx.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -39,7 +39,7 @@ from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigCanvas from matplotlib.figure import Figure -import matplotlib.numerix as numpy +import numpy class PlotFrame(wx.Frame): help_msg=""" Menus for Modified: branches/transforms/examples/pythonic_matplotlib.py =================================================================== --- branches/transforms/examples/pythonic_matplotlib.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/pythonic_matplotlib.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -54,7 +54,7 @@ from pylab import figure, close, axes, subplot, show -from matplotlib.numerix import arange, sin, pi +from numpy import arange, sin, pi t = arange(0.0, 1.0, 0.01) Modified: branches/transforms/examples/rc_traits.py =================================================================== --- branches/transforms/examples/rc_traits.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/rc_traits.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -128,8 +128,8 @@ antialiased = flexible_true_trait timezones = 'UTC', 'US/Central', 'ES/Eastern' # fixme: and many more -backends = ('GTKAgg', 'Cairo', 'FltkAgg', 'GD', 'GDK', 'GTK', 'Agg', - 'GTKCairo', 'Paint', 'PS', 'SVG', 'Template', 'TkAgg', +backends = ('GTKAgg', 'Cairo', 'FltkAgg', 'GDK', 'GTK', 'Agg', + 'GTKCairo', 'PS', 'SVG', 'Template', 'TkAgg', 'WX') class RC(traits.HasTraits): Modified: branches/transforms/examples/scatter_masked.py =================================================================== --- branches/transforms/examples/scatter_masked.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/scatter_masked.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -1,6 +1,6 @@ #!/usr/bin/env python from pylab import * -import matplotlib.numerix.ma as ma +import matplotlib.numerix.npyma as ma N = 100 r0 = 0.6 Modified: branches/transforms/examples/strip_chart_demo.py =================================================================== --- branches/transforms/examples/strip_chart_demo.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/strip_chart_demo.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -12,7 +12,7 @@ import gobject, gtk import matplotlib matplotlib.use('GTKAgg') -import matplotlib.numerix as nx +import numpy as npy from matplotlib.lines import Line2D @@ -36,9 +36,9 @@ def emitter(self, p=0.01): 'return a random value with probability p, else 0' - v = nx.mlab.rand(1) + v = npy.random.rand(1) if v>p: return 0. - else: return nx.mlab.rand(1) + else: return npy.random.rand(1) def update(self, *args): if self.background is None: return True Modified: branches/transforms/examples/tex_demo.py =================================================================== --- branches/transforms/examples/tex_demo.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/tex_demo.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -11,8 +11,8 @@ """ from matplotlib import rc -from matplotlib.numerix import arange, cos, pi -from pylab import figure, axes, plot, xlabel, ylabel, title, \ +from numpy import arange, cos, pi +from matplotlib.pyplot import figure, axes, plot, xlabel, ylabel, title, \ grid, savefig, show Modified: branches/transforms/examples/tex_unicode_demo.py =================================================================== --- branches/transforms/examples/tex_unicode_demo.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/tex_unicode_demo.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -7,8 +7,8 @@ from matplotlib import rcParams rcParams['text.usetex']=True rcParams['text.latex.unicode']=True -from matplotlib.numerix import arange, cos, pi -from pylab import figure, axes, plot, xlabel, ylabel, title, \ +from numpy import arange, cos, pi +from matplotlib.pyplot import figure, axes, plot, xlabel, ylabel, title, \ grid, savefig, show figure(1) Modified: branches/transforms/examples/vline_demo.py =================================================================== --- branches/transforms/examples/vline_demo.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/vline_demo.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -1,17 +1,17 @@ #!/usr/bin/env python -from pylab import * -from matplotlib.numerix import sin, exp, multiply, absolute, pi -from matplotlib.numerix.random_array import normal +from matplotlib.pyplot import * +from numpy import sin, exp, absolute, pi, arange +from numpy.random import normal def f(t): s1 = sin(2*pi*t) e1 = exp(-t) - return absolute(multiply(s1,e1))+.05 + return absolute((s1*e1))+.05 t = arange(0.0, 5.0, 0.1) s = f(t) -nse = multiply(normal(0.0, 0.3, t.shape), s) +nse = normal(0.0, 0.3, t.shape) * s plot(t, s+nse, 'b^') vlines(t, [0], s) Modified: branches/transforms/examples/webapp_demo.py =================================================================== --- branches/transforms/examples/webapp_demo.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/webapp_demo.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -21,7 +21,7 @@ from matplotlib.backends.backend_agg import FigureCanvasAgg from matplotlib.figure import Figure from matplotlib.cbook import iterable -import matplotlib.numerix as nx +import numpy as npy def make_fig(): """ @@ -40,9 +40,9 @@ line, = ax.plot([1,2,3], 'ro--', markersize=12, markerfacecolor='g') # make a translucent scatter collection - x = nx.mlab.rand(100) - y = nx.mlab.rand(100) - area = nx.pi*(10 * nx.mlab.rand(100))**2 # 0 to 10 point radiuses + x = npy.random.rand(100) + y = npy.random.rand(100) + area = npy.pi*(10 * npy.random.rand(100))**2 # 0 to 10 point radiuses c = ax.scatter(x,y,area) c.set_alpha(0.5) Modified: branches/transforms/examples/wxcursor_demo.py =================================================================== --- branches/transforms/examples/wxcursor_demo.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/examples/wxcursor_demo.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -6,7 +6,7 @@ from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas from matplotlib.backends.backend_wx import NavigationToolbar2Wx from matplotlib.figure import Figure -from matplotlib.numerix import arange, sin, pi +from numpy import arange, sin, pi import wx Modified: branches/transforms/lib/matplotlib/__init__.py =================================================================== --- branches/transforms/lib/matplotlib/__init__.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/lib/matplotlib/__init__.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -530,16 +530,16 @@ class RcParams(dict): - + """A dictionary object including validation - + validating functions are defined and associated with rc parameters in rcsetup.py """ - + validate = dict([ (key, converter) for key, (default, converter) in \ defaultParams.iteritems() ]) - + def __setitem__(self, key, val): try: if key in _deprecated_map.keys(): @@ -620,7 +620,7 @@ ret['datapath'] = get_data_path() verbose.report('loaded rc file %s'%fname) - + return ret Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/lib/matplotlib/axes.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -1867,31 +1867,6 @@ c =mcolors.colorConverter.to_rgba(c) self._cursorProps = lw, c - - def panx(self, numsteps): - 'Pan the x axis numsteps (plus pan right, minus pan left)' - self.xaxis.pan(numsteps) - xmin, xmax = self.viewLim.intervalx().get_bounds() - self._send_xlim_event() - - def pany(self, numsteps): - 'Pan the x axis numsteps (plus pan up, minus pan down)' - self.yaxis.pan(numsteps) - self._send_ylim_event() - - def zoomx(self, numsteps): - 'Zoom in on the x xaxis numsteps (plus for zoom in, minus for zoom out)' - self.xaxis.zoom(numsteps) - xmin, xmax = self.viewLim.intervalx().get_bounds() - self._send_xlim_event() - - def zoomy(self, numsteps): - 'Zoom in on the x xaxis numsteps (plus for zoom in, minus for zoom out)' - self.yaxis.zoom(numsteps) - self._send_ylim_event() - - - def connect(self, s, func): """ Register observers to be notified when certain events occur. Register @@ -1913,6 +1888,7 @@ def disconnect(self, cid): 'disconnect from the Axes event.' raise DeprecationWarning('use the callbacks CallbackRegistry instance instead') + def get_children(self): 'return a list of child artists' children = [] @@ -5683,38 +5659,14 @@ 'ylabel not implemented' raise NotImplementedError('ylabel not defined for polar axes (yet)') + def set_xlim(self, xmin=None, xmax=None, emit=True, **kwargs): + 'xlim not implemented' + raise NotImplementedError('xlim not meaningful for polar axes') - def set_xlim(self, xmin=None, xmax=None, emit=True): - """ - set the xlimits - ACCEPTS: len(2) sequence of floats - """ - if xmax is None and iterable(xmin): - xmin,xmax = xmin + def set_ylim(self, ymin=None, ymax=None, emit=True, **kwargs): + 'ylim not implemented' + raise NotImplementedError('ylim not meaningful for polar axes') - old_xmin,old_xmax = self.get_xlim() - if xmin is None: xmin = old_xmin - if xmax is None: xmax = old_xmax - - self.viewLim.intervalx().set_bounds(xmin, xmax) - if emit: self._send_xlim_event() - - - def set_ylim(self, ymin=None, ymax=None, emit=True): - """ - set the ylimits - ACCEPTS: len(2) sequence of floats - """ - if ymax is None and iterable(ymin): - ymin,ymax = ymin - - old_ymin,old_ymax = self.get_ylim() - if ymin is None: ymin = old_ymin - if ymax is None: ymax = old_ymax - - self.viewLim.intervaly().set_bounds(ymin, ymax) - if emit: self._send_ylim_event() - def get_xscale(self): 'return the xaxis scale string' return 'polar' @@ -5765,10 +5717,9 @@ """ # this is some discarded code I was using to find the minimum positive # data point for some log scaling fixes. I realized there was a -# cleaner way to do it, but am ke -eping this around as an example for +# cleaner way to do it, but am keeping this around as an example for # how to get the data out of the axes. Might want to make something -# like this a method one day, or better yet make get_verts and Artist +# like this a method one day, or better yet make get_verts an Artist # method minx, maxx = self.get_xlim() Modified: branches/transforms/lib/matplotlib/backends/__init__.py =================================================================== --- branches/transforms/lib/matplotlib/backends/__init__.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/lib/matplotlib/backends/__init__.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -7,7 +7,7 @@ interactive_bk = ['GTK', 'GTKAgg', 'GTKCairo', 'FltkAgg', 'QtAgg', 'Qt4Agg', 'TkAgg', 'WX', 'WXAgg', 'CocoaAgg', 'Aqt'] -non_interactive_bk = ['Agg2', 'Agg', 'Cairo', 'EMF', 'GD', 'GDK', 'Paint', +non_interactive_bk = ['Agg2', 'Agg', 'Cairo', 'EMF', 'GDK', 'Pdf', 'PS', 'SVG', 'Template'] all_backends = interactive_bk + non_interactive_bk Deleted: branches/transforms/lib/matplotlib/backends/backend_gd.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_gd.py 2007-09-10 17:40:47 UTC (rev 3823) +++ branches/transforms/lib/matplotlib/backends/backend_gd.py 2007-09-10 17:45:15 UTC (rev 3824) @@ -1,374 +0,0 @@ -""" -A gd backend http://newcenturycomputers.net/projects/gdmodule.html -""" - - -from __future__ import division -import sys, os, math, warnings - -import numpy as npy - -try: - import gd -except ImportError: - print >>sys.stderr, 'You must first install the gd module http://newcenturycomputers.net/projects/gdmodule.html' - sys.exit() - -from matplotlib.backend_bases import RendererBase, \ - GraphicsContextBase, FigureManagerBase, FigureCanvasBase -from matplotlib import verbose -from matplotlib._pylab_helpers import Gcf -from matplotlib.cbook import enumerate, pieces, is_string_like -from matplotlib.colors import colorConverter -from matplotlib.figure import Figure -from matplotlib.transforms import Bbox -from matplotlib.font_manager import findfont -# support old font names -if (os.environ.has_key('GDFONTPATH') and not - os.environ.has_key('TTFPATH')): - os.environ['TTFPATH'] = os.environ['GDFONTPATH'] - - - - -PIXELS_PER_INCH = 96 # constant GD uses for screen DPI - - -def round(x): - return int(math.floor(x+0.5)) - - -class RendererGD(RendererBase): - """ - The renderer handles all the drawing primitives using a graphics - context instance that controls the colors/styles - """ - - - # todo: can gd support cap and join styles? - def __init__(self, im, dpi): - "Initialize the renderer with a gd image instance" - self.im = im - self._cached = {} # a map from get_color args to colors - - self.width, self.height = im.size() - self.dpi = dpi - - - def get_canvas_width_height(... [truncated message content] |
From: <md...@us...> - 2007-09-10 19:25:26
|
Revision: 3826 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3826&view=rev Author: mdboom Date: 2007-09-10 12:25:21 -0700 (Mon, 10 Sep 2007) Log Message: ----------- Running mathtext_demo.py without transforms.py/cpp. Totally broken, though. Not surprising... ;) Modified Paths: -------------- branches/transforms/lib/matplotlib/affine.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/axis.py branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/bbox.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/finance.py branches/transforms/lib/matplotlib/legend.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/text.py branches/transforms/lib/matplotlib/ticker.py branches/transforms/src/_backend_agg.cpp Modified: branches/transforms/lib/matplotlib/affine.py =================================================================== --- branches/transforms/lib/matplotlib/affine.py 2007-09-10 18:45:32 UTC (rev 3825) +++ branches/transforms/lib/matplotlib/affine.py 2007-09-10 19:25:21 UTC (rev 3826) @@ -67,7 +67,10 @@ def from_values(a, b, c, d, e, f): return Affine2D(Affine2D.matrix_from_values(a, b, c, d, e, f)) from_values = staticmethod(from_values) - + + def to_values(self): + return tuple(self.mtx[:2].swapaxes(0, 1).flatten()) + #@staticmethod def matrix_from_values(a, b, c, d, e, f): affine = N.zeros((3,3), N.float_) @@ -92,11 +95,12 @@ # This is nicer for now, however, since we can just keep a # regular affine matrix around + # MGDTODO: Trap cases where this isn't an array and fix there + points = N.array(points, N.float_) new_points = points.swapaxes(0, 1) new_points = N.vstack((new_points, N.ones((1, points.shape[0])))) result = N.dot(self.mtx, new_points)[:2] - result.swapaxes(0, 1) - return result + return result.swapaxes(0, 1) #@staticmethod def _concat(a, b): @@ -198,10 +202,14 @@ print transform.inverted() from bbox import Bbox + print "BBOX" boxin = Bbox([[10, 10], [320, 240]]) boxout = Bbox([[25, 25], [640, 400]]) - trans = bbox_transform(boxin, boxout) + print boxin._points, boxin.xmin(), boxin.ymin(), boxin.xmax(), boxin.ymax() + print boxout._points, boxout.xmin(), boxout.ymin(), boxout.xmax(), boxout.ymax() + trans = get_bbox_transform(boxin, boxout) print trans print trans(N.array([[10, 10], [320, 240]])) + print trans([[10, 10]]) __all__ = ['Transform', 'Affine2D'] Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-09-10 18:45:32 UTC (rev 3825) +++ branches/transforms/lib/matplotlib/axes.py 2007-09-10 19:25:21 UTC (rev 3826) @@ -618,10 +618,10 @@ martist.Artist.set_figure(self, fig) l, b, w, h = self._position - xmin = fig.bbox.ll().x() - xmax = fig.bbox.ur().x() - ymin = fig.bbox.ll().y() - ymax = fig.bbox.ur().y() + xmin = fig.bbox.xmin() + xmax = fig.bbox.xmax() + ymin = fig.bbox.ymin() + ymax = fig.bbox.ymax() figw = xmax-xmin figh = ymax-ymin self.left = l*figw @@ -695,9 +695,11 @@ ACCEPTS: len(4) sequence of floats """ if which in ('both', 'active'): - # Change values within self._position--don't replace it. - for num,val in zip(pos, self._position): - val.set(num) + # MGDTODO +# # Change values within self._position--don't replace it. +# for num,val in zip(pos, self._position): +# val.set(num) + self._position = pos if which in ('both', 'original'): self._originalPosition = pos @@ -714,7 +716,8 @@ self.xaxis.cla() self.yaxis.cla() - self.dataLim.ignore(1) + # MGDTODO + # self.dataLim.ignore(1) self.callbacks = cbook.CallbackRegistry(('xlim_changed', 'ylim_changed')) if self._sharex is not None: @@ -1176,7 +1179,9 @@ # Otherwise, it will compute the bounds of it's current data # and the data in xydata #print type(x), type(y) - self.dataLim.update_numerix(x, y, -1) + # MGDTODO + ## self.dataLim.update_numerix(x, y, -1) + pass def _get_verts_in_data_coords(self, trans, xys): if trans == self.transData: @@ -1273,8 +1278,9 @@ if not self.get_visible(): return renderer.open_group('axes') self.apply_aspect() - self.transData.freeze() # eval the lazy objects - self.transAxes.freeze() + # MGDTODO + # self.transData.freeze() # eval the lazy objects + # self.transAxes.freeze() if self.axison and self._frameon: self.axesPatch.draw(renderer) artists = [] @@ -1330,8 +1336,9 @@ for zorder, i, a in dsu: a.draw(renderer) - self.transData.thaw() # release the lazy objects - self.transAxes.thaw() # release the lazy objects + # MGDTODO + # self.transData.thaw() # release the lazy objects + # self.transAxes.thaw() # release the lazy objects renderer.close_group('axes') self._cachedRenderer = renderer Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-09-10 18:45:32 UTC (rev 3825) +++ branches/transforms/lib/matplotlib/axis.py 2007-09-10 19:25:21 UTC (rev 3826) @@ -261,7 +261,7 @@ horizontalalignment='center', ) - trans = blend_xy_sep_transformation( + trans = blend_xy_sep_transform( self.axes.transData, self.axes.transAxes) # offset the text upward with a post transformation trans = trans + Affine2D().translated(0, self._padPixels) @@ -1037,7 +1037,8 @@ bbox = bbox_union(bboxes) bottom = bbox.ymin() - self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi.get()/72.0)) + self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi/72.0)) +# self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi.get()/72.0)) MGDTODO else: if not len(bboxes2): @@ -1060,8 +1061,9 @@ else: bbox = bbox_union(bboxes) bottom = bbox.ymin() - self.offsetText.set_position((x, bottom-self.OFFSETTEXTPAD*self.figure.dpi.get()/72.0)) - + self.offsetText.set_position((x, bottom-self.OFFSETTEXTPAD*self.figure.dpi/72.0)) +# self.offsetText.set_position((x, bottom-self.OFFSETTEXTPAD*self.figure.dpi.get()/72.0)) MGDTODO + def set_ticks_position(self, position): """ Set the ticks position (top, bottom, both or default) @@ -1227,8 +1229,9 @@ bbox = bbox_union(bboxes) left = bbox.xmin() - self.label.set_position( (left-self.LABELPAD*self.figure.dpi.get()/72.0, y)) - + self.label.set_position( (left-self.LABELPAD*self.figure.dpi/72.0, y)) + # self.label.set_position( (left-self.LABELPAD*self.figure.dpi.get()/72.0, y)) MGDTODO + else: if not len(bboxes2): right = self.axes.bbox.xmax() @@ -1246,8 +1249,9 @@ """ x,y = self.offsetText.get_position() top = self.axes.bbox.ymax() - self.offsetText.set_position((x, top+self.OFFSETTEXTPAD*self.figure.dpi.get()/72.0)) - + self.offsetText.set_position((x, top+self.OFFSETTEXTPAD*self.figure.dpi/72.0)) +# self.offsetText.set_position((x, top+self.OFFSETTEXTPAD*self.figure.dpi.get()/72.0)) MGDTODO + def set_offset_position(self, position): assert position == 'left' or position == 'right' Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-09-10 18:45:32 UTC (rev 3825) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-09-10 19:25:21 UTC (rev 3826) @@ -1178,11 +1178,13 @@ if dpi is None: dpi = rcParams['savefig.dpi'] - origDPI = self.figure.dpi.get() + origDPI = self.figure.dpi origfacecolor = self.figure.get_facecolor() origedgecolor = self.figure.get_edgecolor() - self.figure.dpi.set(dpi) + # MGDTODO + # self.figure.dpi.set(dpi) + self.figure.dpi = dpi self.figure.set_facecolor(facecolor) self.figure.set_edgecolor(edgecolor) @@ -1195,7 +1197,9 @@ orientation=orientation, **kwargs) finally: - self.figure.dpi.set(origDPI) + # MGDTODO + # self.figure.dpi.set(origDPI) + self.figure.dpi = origDPI self.figure.set_facecolor(origfacecolor) self.figure.set_edgecolor(origedgecolor) self.figure.set_canvas(self) Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-10 18:45:32 UTC (rev 3825) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-10 19:25:21 UTC (rev 3826) @@ -106,14 +106,17 @@ self.height = height if __debug__: verbose.report('RendererAgg.__init__ width=%s, \ height=%s'%(width, height), 'debug-annoying') - self._renderer = _RendererAgg(int(width), int(height), dpi.get(), - debug=False) + # MGDTODO +# self._renderer = _RendererAgg(int(width), int(height), dpi.get(), +# debug=False) + self._renderer = _RendererAgg(int(width), int(height), dpi, + debug=False) if __debug__: verbose.report('RendererAgg.__init__ _RendererAgg done', 'debug-annoying') self.draw_polygon = self._renderer.draw_polygon self.draw_rectangle = self._renderer.draw_rectangle self.draw_path = self._renderer.draw_path - self.draw_lines = self._renderer.draw_lines + # self.draw_lines = self._renderer.draw_lines self.draw_markers = self._renderer.draw_markers self.draw_image = self._renderer.draw_image self.draw_line_collection = self._renderer.draw_line_collection @@ -156,6 +159,9 @@ y = npy.array([y1,y2], float) self._renderer.draw_lines(gc, x, y) + def draw_lines(self, gc, x, y, transform): + return self._renderer.draw_lines(gc, x, y, transform.to_values()) + def draw_point(self, gc, x, y): """ @@ -173,7 +179,9 @@ if __debug__: verbose.report('RendererAgg.draw_mathtext', 'debug-annoying') ox, oy, width, height, descent, font_image, used_characters = \ - self.mathtext_parser.parse(s, self.dpi.get(), prop) + self.mathtext_parser.parse(s, self.dpi, prop) +# ox, oy, width, height, descent, font_image, used_characters = \ +# self.mathtext_parser.parse(s, self.dpi.get(), prop) MGDTODO x = int(x) + ox y = int(y) - oy @@ -228,7 +236,9 @@ if ismath: ox, oy, width, height, descent, fonts, used_characters = \ - self.mathtext_parser.parse(s, self.dpi.get(), prop) + self.mathtext_parser.parse(s, self.dpi, prop) +# ox, oy, width, height, descent, fonts, used_characters = \ +# self.mathtext_parser.parse(s, self.dpi.get(), prop) MGDTODO return width, height, descent font = self._get_agg_font(prop) font.set_text(s, 0.0, flags=LOAD_DEFAULT) # the width and height of unrotated string @@ -302,7 +312,8 @@ font.clear() size = prop.get_size_in_points() - font.set_size(size, self.dpi.get()) + font.set_size(size, self.dpi) + # font.set_size(size, self.dpi.get()) MGDTODO return font @@ -380,7 +391,9 @@ def get_renderer(self): l,b,w,h = self.figure.bbox.get_bounds() - key = w, h, self.figure.dpi.get() + # MGDTODO + # key = w, h, self.figure.dpi.get() + key = w, h, self.figure.dpi try: self._lastKey, self.renderer except AttributeError: need_new_renderer = True else: need_new_renderer = (self._lastKey != key) Modified: branches/transforms/lib/matplotlib/bbox.py =================================================================== --- branches/transforms/lib/matplotlib/bbox.py 2007-09-10 18:45:32 UTC (rev 3825) +++ branches/transforms/lib/matplotlib/bbox.py 2007-09-10 19:25:21 UTC (rev 3826) @@ -6,9 +6,31 @@ import numpy as N +class Interval: + def __init__(self, bounds): + self._bounds = N.array(bounds, N.float_) + + def contains(self, value): + bounds = self._bounds + return value >= bounds[0] and value <= bounds[1] + + def contains_open(self, value): + bounds = self._bounds + return value > bounds[0] and value < bounds[1] + + def get_bounds(self): + return self._bounds + + def set_bounds(self, lower, upper): + self._bounds = lower, upper + + def span(self): + bounds = self._bounds + return bounds[1] - bounds[0] + class Bbox: def __init__(self, points): - self._points = N.array(points) + self._points = N.array(points, N.float_) #@staticmethod def unit(): @@ -23,7 +45,10 @@ #@staticmethod def from_lbrt(left, bottom, right, top): return Bbox([[left, bottom], [right, top]]) - from_lbwh = staticmethod(from_lbwh) + from_lbrt = staticmethod(from_lbrt) + + def copy(self): + return Bbox(self._points.copy()) # MGDTODO: Probably a more efficient ways to do this... def xmin(self): @@ -45,15 +70,29 @@ return self.ymax() - self.ymin() def transform(self, transform): - return Bbox(transform(points)) + return Bbox(transform(self._points)) def inverse_transform(self, transform): - return Bbox(transform.inverted()(points)) + return Bbox(transform.inverted()(self._points)) def get_bounds(self): return (self.xmin(), self.ymin(), self.xmax() - self.xmin(), self.ymax() - self.ymin()) - + + def intervalx(self): + return Interval(self._points[0]) + + def intervaly(self): + return Interval(self._points[1]) + + def scaled(self, sw, sh): + width = self.width() + height = self.height() + deltaw = (sw * width - width) / 2.0 + deltah = (sh * height - height) / 2.0 + a = N.array([[-deltaw, -deltah], [deltaw, deltah]]) + return Bbox(self._points + a) + def lbwh_to_bbox(left, bottom, width, height): return Bbox([[left, bottom], [left + width, bottom + height]]) @@ -67,18 +106,18 @@ return bboxes[0] bbox = bboxes[0] - xmin = bbox.xmin - ymin = bbox.ymin - xmax = bbox.xmax - ymax = bbox.ymax + xmin = bbox.xmin() + ymin = bbox.ymin() + xmax = bbox.xmax() + ymax = bbox.ymax() for bbox in bboxes[1:]: - xmin = min(xmin, bbox.xmin) - ymin = min(ymin, bbox.ymin) - xmax = max(xmax, bbox.xmax) - ymax = max(ymax, bbox.ymax) + xmin = min(xmin, bbox.xmin()) + ymin = min(ymin, bbox.ymin()) + xmax = max(xmax, bbox.xmax()) + ymax = max(ymax, bbox.ymax()) - return Bbox(xmin, ymin, xmax, ymax) + return Bbox.from_lbrt(xmin, ymin, xmax, ymax) # MGDTODO: There's probably a better place for this def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True): Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-09-10 18:45:32 UTC (rev 3825) +++ branches/transforms/lib/matplotlib/figure.py 2007-09-10 19:25:21 UTC (rev 3826) @@ -129,9 +129,10 @@ if edgecolor is None: edgecolor = rcParams['figure.edgecolor'] self.dpi = dpi + self.figsize = figsize self.bbox = Bbox.from_lbwh(0, 0, - self.figsize[0] * dpi, - self.figsize[1] * dpi) + figsize[0] * dpi, + figsize[1] * dpi) self.frameon = frameon @@ -581,7 +582,8 @@ #print 'figure draw' if not self.get_visible(): return renderer.open_group('figure') - self.transFigure.freeze() # eval the lazy objects + # MGDTODO + # self.transFigure.freeze() # eval the lazy objects if self.frameon: self.figurePatch.draw(renderer) @@ -615,7 +617,8 @@ for legend in self.legends: legend.draw(renderer) - self.transFigure.thaw() # release the lazy objects + # MGDTODO + # self.transFigure.thaw() # release the lazy objects renderer.close_group('figure') self._cachedRenderer = renderer Modified: branches/transforms/lib/matplotlib/finance.py =================================================================== --- branches/transforms/lib/matplotlib/finance.py 2007-09-10 18:45:32 UTC (rev 3825) +++ branches/transforms/lib/matplotlib/finance.py 2007-09-10 19:25:21 UTC (rev 3826) @@ -22,8 +22,7 @@ from matplotlib.colors import colorConverter from lines import Line2D, TICKLEFT, TICKRIGHT from patches import Rectangle -from matplotlib.transforms import scale_transform, Value, zero, one, \ - scale_sep_transform, blend_xy_sep_transform +from matplotlib.affine import Affine2D @@ -335,9 +334,9 @@ offsetsClose = [ (i, close) for i, close in zip(xrange(len(closes)), closes) if close != -1 ] - scale = ax.figure.dpi * Value(1/72.0) + scale = ax.figure.dpi * (1.0/72.0) - tickTransform = scale_transform( scale, zero()) + tickTransform = Affine2D().scaled(scale, 0.0) r,g,b = colorConverter.to_rgb(colorup) colorup = r,g,b,1 @@ -424,10 +423,10 @@ offsetsBars = [ (i, open) for i,open in zip(xrange(len(opens)), opens) if open != -1 ] - sx = ax.figure.dpi * Value(1/72.0) # scale for points + sx = ax.figure.dpi * (1.0/72.0) # scale for points sy = (ax.bbox.ur().y() - ax.bbox.ll().y()) / (ax.viewLim.ur().y() - ax.viewLim.ll().y()) - barTransform = scale_sep_transform(sx,sy) + barTransform = Affine2D().scaled(sx,sy) @@ -512,10 +511,10 @@ bars = [ ( (left, 0), (left, v), (right, v), (right, 0)) for v in volumes if v != -1 ] - sx = ax.figure.dpi * Value(1/72.0) # scale for points + sx = ax.figure.dpi * (1.0/72.0) # scale for points sy = (ax.bbox.ur().y() - ax.bbox.ll().y()) / (ax.viewLim.ur().y() - ax.viewLim.ll().y()) - barTransform = scale_sep_transform(sx,sy) + barTransform = Affine2D().scaled(sx,sy) offsetsBars = [ (i, 0) for i,v in enumerate(volumes) if v != -1 ] @@ -602,10 +601,10 @@ bars = [ ( (left, 0), (left, volume), (right, volume), (right, 0)) for d, open, close, high, low, volume in quotes] - sx = ax.figure.dpi * Value(1/72.0) # scale for points + sx = ax.figure.dpi * (1.0/72.0) # scale for points sy = (ax.bbox.ur().y() - ax.bbox.ll().y()) / (ax.viewLim.ur().y() - ax.viewLim.ll().y()) - barTransform = scale_sep_transform(sx,sy) + barTransform = Affine2D().scaled(sx,sy) dates = [d for d, open, close, high, low, volume in quotes] offsetsBars = [(d, 0) for d in dates] @@ -662,10 +661,10 @@ bars = [ ( (left, 0), (left, v), (right, v), (right, 0)) for v in vals if v != -1 ] - sx = ax.figure.dpi * Value(1/72.0) # scale for points + sx = ax.figure.dpi * (1.0/72.0) # scale for points sy = (ax.bbox.ur().y() - ax.bbox.ll().y()) / (ax.viewLim.ur().y() - ax.viewLim.ll().y()) - barTransform = scale_sep_transform(sx,sy) + barTransform = Affine2D().scaled(sx,sy) offsetsBars = [ (i, 0) for i,v in enumerate(vals) if v != -1 ] Modified: branches/transforms/lib/matplotlib/legend.py =================================================================== --- branches/transforms/lib/matplotlib/legend.py 2007-09-10 18:45:32 UTC (rev 3825) +++ branches/transforms/lib/matplotlib/legend.py 2007-09-10 19:25:21 UTC (rev 3826) @@ -224,7 +224,7 @@ a.set_transform(self.get_transform()) def _approx_text_height(self): - return self.fontsize/72.0*self.figure.dpi.get()/self.parent.bbox.height() + return self.fontsize/72.0*self.figure.dpi/self.parent.bbox.height() def draw(self, renderer): @@ -531,7 +531,7 @@ if not len(self.legendHandles) and not len(self.texts): return def get_tbounds(text): #get text bounds in axes coords bbox = text.get_window_extent(renderer) - bboxa = inverse_transform_bbox(self.get_transform(), bbox) + bboxa = bbox.inverse_transform(self.get_transform()) return bboxa.get_bounds() hpos = [] @@ -559,9 +559,11 @@ handle.set_height(h/2) # Set the data for the legend patch - bbox = self._get_handle_text_bbox(renderer).deepcopy() + # MGDTODO: This copy may no longer be needed now that Bboxes are + # essentially immutable + bbox = self._get_handle_text_bbox(renderer).copy() - bbox.scale(1 + self.pad, 1 + self.pad) + bbox = bbox.scaled(1 + self.pad, 1 + self.pad) l,b,w,h = bbox.get_bounds() self.legendPatch.set_bounds(l,b,w,h) Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-09-10 18:45:32 UTC (rev 3825) +++ branches/transforms/lib/matplotlib/lines.py 2007-09-10 19:25:21 UTC (rev 3826) @@ -362,8 +362,13 @@ else: x, y = self._get_plottable() - - x, y = self.get_transform().numerix_x_y(x, y) + # MGDTODO: Put this in a single Nx2 array, rather than these + # separate ones + #### Conversion code + a = npy.vstack((x, y)).swapaxes(0, 1) + #### + x, y = self.get_transform()(a) + #x, y = self.get_transform().seq_x_y(x, y) left = min(x) @@ -373,7 +378,8 @@ # correct for marker size, if any if self._marker is not None: - ms = self._markersize/72.0*self.figure.dpi.get() + ms = self._markersize/72.0*self.figure.dpi + # ms = self._markersize/72.0*self.figure.dpi.get() MGDTODO left -= ms/2 bottom -= ms/2 width += ms Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-09-10 18:45:32 UTC (rev 3825) +++ branches/transforms/lib/matplotlib/patches.py 2007-09-10 19:25:21 UTC (rev 3826) @@ -209,8 +209,13 @@ gc.set_hatch(self._hatch ) verts = self.get_verts() - tverts = self.get_transform().seq_xy_tups(verts) + tverts = self.get_transform()(verts) + # MGDTODO: This result is an Nx2 numpy array, which could be passed + # directly to renderer.draw_polygon. However, it currently expects + # a list of tuples so we're converting it to that now. + tverts = [tuple(x) for x in tverts] + renderer.draw_polygon(gc, rgbFace, tverts) Modified: branches/transforms/lib/matplotlib/text.py =================================================================== --- branches/transforms/lib/matplotlib/text.py 2007-09-10 18:45:32 UTC (rev 3825) +++ branches/transforms/lib/matplotlib/text.py 2007-09-10 19:25:21 UTC (rev 3826) @@ -151,7 +151,7 @@ def _get_xy_display(self): 'get the (possibly unit converted) transformed x,y in display coords' x, y = self.get_position() - return self.get_transform().xy_tup((x,y)) + return self.get_transform()([[x,y]])[0] def _get_multialignment(self): if self._multialignment is not None: return self._multialignment @@ -275,7 +275,8 @@ ty = [float(v[1][0])+offsety for v in xys] # now inverse transform back to data coords - xys = [self.get_transform().inverse_xy_tup( xy ) for xy in zip(tx, ty)] + inverse_transform = self.get_transform().inverted() + xys = inverse_transform(zip(tx, ty)) xs, ys = zip(*xys) @@ -328,7 +329,7 @@ return for line, wh, x, y in info: - x, y = trans.xy_tup((x, y)) + x, y = trans([[x, y]])[0] if renderer.flipy(): canvasw, canvash = renderer.get_canvas_width_height() @@ -405,7 +406,7 @@ return (x, y, self._text, self._color, self._verticalalignment, self._horizontalalignment, hash(self._fontproperties), self._rotation, - self.get_transform().as_vec6_val(), + self.get_transform().to_values(), ) def get_text(self): Modified: branches/transforms/lib/matplotlib/ticker.py =================================================================== --- branches/transforms/lib/matplotlib/ticker.py 2007-09-10 18:45:32 UTC (rev 3825) +++ branches/transforms/lib/matplotlib/ticker.py 2007-09-10 19:25:21 UTC (rev 3826) @@ -115,12 +115,11 @@ import matplotlib as mpl from matplotlib import verbose, rcParams from matplotlib import cbook -from matplotlib import transforms as mtrans +from matplotlib import bbox as mbbox - class TickHelper: viewInterval = None @@ -149,8 +148,8 @@ cases where the Intervals do not need to be updated automatically. ''' - self.dataInterval = mtrans.Interval(mtrans.Value(vmin), mtrans.Value(vmax)) - self.viewInterval = mtrans.Interval(mtrans.Value(vmin), mtrans.Value(vmax)) + self.dataInterval = mbbox.Interval([vmin, vmax]) + self.viewInterval = mbbox.Interval([vmin, vmax]) class Formatter(TickHelper): """ @@ -572,7 +571,7 @@ def autoscale(self): 'autoscale the view limits' self.verify_intervals() - return mtrans.nonsingular(*self.dataInterval.get_bounds()) + return mbbox.nonsingular(*self.dataInterval.get_bounds()) def pan(self, numsteps): 'Pan numticks (can be positive or negative)' @@ -714,7 +713,7 @@ vmin = math.floor(scale*vmin)/scale vmax = math.ceil(scale*vmax)/scale - return mtrans.nonsingular(vmin, vmax) + return mbbox.nonsingular(vmin, vmax) def closeto(x,y): @@ -798,7 +797,7 @@ vmin -=1 vmax +=1 - return mtrans.nonsingular(vmin, vmax) + return mbbox.nonsingular(vmin, vmax) def scale_range(vmin, vmax, n = 1, threshold=100): dv = abs(vmax - vmin) @@ -866,13 +865,13 @@ def __call__(self): self.verify_intervals() vmin, vmax = self.viewInterval.get_bounds() - vmin, vmax = mtrans.nonsingular(vmin, vmax, expander = 0.05) + vmin, vmax = mbbox.nonsingular(vmin, vmax, expander = 0.05) return self.bin_boundaries(vmin, vmax) def autoscale(self): self.verify_intervals() dmin, dmax = self.dataInterval.get_bounds() - dmin, dmax = mtrans.nonsingular(dmin, dmax, expander = 0.05) + dmin, dmax = mbbox.nonsingular(dmin, dmax, expander = 0.05) return npy.take(self.bin_boundaries(dmin, dmax), [0,-1]) @@ -973,7 +972,7 @@ if vmin==vmax: vmin = decade_down(vmin,self._base) vmax = decade_up(vmax,self._base) - return mtrans.nonsingular(vmin, vmax) + return mbbox.nonsingular(vmin, vmax) class AutoLocator(MaxNLocator): def __init__(self): Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-09-10 18:45:32 UTC (rev 3825) +++ branches/transforms/src/_backend_agg.cpp 2007-09-10 19:25:21 UTC (rev 3826) @@ -44,6 +44,27 @@ #define M_PI_2 1.57079632679489661923 #endif +agg::trans_affine py_sequence_to_agg_transformation_matrix(const Py::Object& obj) { + Py::SeqBase<Py::Float> seq; + try { + seq = obj; + } catch(...) { + throw Py::ValueError("Transformation matrix must be given as a 6-element list."); + } + + if (seq.size() != 6) { + throw Py::ValueError("Transformation matrix must be given as a 6-element list."); + } + + agg::trans_affine xytrans = agg::trans_affine + (Py::Float(seq[0]), + Py::Float(seq[1]), + Py::Float(seq[2]), + Py::Float(seq[3]), + Py::Float(seq[4]), + Py::Float(seq[5])); +} + GCAgg::GCAgg(const Py::Object &gc, double dpi, bool snapto) : dpi(dpi), snapto(snapto), isaa(true), linewidth(1.0), alpha(1.0), cliprect(NULL), clippath(NULL), @@ -646,7 +667,8 @@ Py::SeqBase<Py::Object> linewidths = args[4]; Py::SeqBase<Py::Object> linestyle = args[5]; Py::SeqBase<Py::Object> antialiaseds = args[6]; - + + // MGDTODO: Verify we don't need this offset stuff anymore bool usingOffsets = args[7].ptr()!=Py_None; Py::SeqBase<Py::Object> offsets; Transformation* transOffset=NULL; @@ -1534,24 +1556,14 @@ //path_t transpath(path, xytrans); _process_alpha_mask(gc); - Transformation* mpltransform = static_cast<Transformation*>(args[3].ptr()); + agg::trans_affine xytrans = py_sequence_to_agg_transformation_matrix(args[3]); - double a, b, c, d, tx, ty; - try { - mpltransform->affine_params_api(&a, &b, &c, &d, &tx, &ty); - } - catch(...) { - throw Py::ValueError("Domain error on affine_params_api in RendererAgg::draw_lines"); - } - - agg::trans_affine xytrans = agg::trans_affine(a,b,c,d,tx,ty); - - agg::path_storage path; + // MGDTODO + bool needNonlinear = false; + // mpltransform->need_nonlinear_api(); - bool needNonlinear = mpltransform->need_nonlinear_api(); - double thisx(0.0), thisy(0.0); double origdx(0.0), origdy(0.0), origdNorm2(0); bool moveto = true; @@ -1584,7 +1596,8 @@ if (needNonlinear) try { - mpltransform->nonlinear_only_api(&thisx, &thisy); + // MGDTODO + // mpltransform->nonlinear_only_api(&thisx, &thisy); } catch (...) { moveto = true; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-11 17:56:14
|
Revision: 3830 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3830&view=rev Author: mdboom Date: 2007-09-11 10:56:13 -0700 (Tue, 11 Sep 2007) Log Message: ----------- Just marking a milestone -- about to totally rip things up again. Modified Paths: -------------- branches/transforms/lib/matplotlib/affine.py branches/transforms/lib/matplotlib/artist.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/backends/backend_tkagg.py branches/transforms/lib/matplotlib/bbox.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/text.py branches/transforms/src/_backend_agg.cpp Modified: branches/transforms/lib/matplotlib/affine.py =================================================================== --- branches/transforms/lib/matplotlib/affine.py 2007-09-11 12:46:27 UTC (rev 3829) +++ branches/transforms/lib/matplotlib/affine.py 2007-09-11 17:56:13 UTC (rev 3830) @@ -58,10 +58,8 @@ self.mtx = matrix def __repr__(self): - return repr(self.mtx) - - def __str__(self): - return str(self.mtx) + return "Affine2D(%s)" % repr(self.mtx) + __str__ = __repr__ #@staticmethod def from_values(a, b, c, d, e, f): @@ -156,8 +154,8 @@ class BlendedAffine2D(Affine2D): def __init__(self, x_transform, y_transform): - assert isinstance(x_transform, Affine2D) - assert isinstance(y_transform, Affine2D) +# assert isinstance(x_transform, Affine2D) +# assert isinstance(y_transform, Affine2D) assert x_transform.is_separable() assert y_transform.is_separable() x_mtx = x_transform.mtx Modified: branches/transforms/lib/matplotlib/artist.py =================================================================== --- branches/transforms/lib/matplotlib/artist.py 2007-09-11 12:46:27 UTC (rev 3829) +++ branches/transforms/lib/matplotlib/artist.py 2007-09-11 17:56:13 UTC (rev 3830) @@ -138,6 +138,7 @@ ACCEPTS: a matplotlib.transform transformation instance """ + print "set_transform", t self._transform = t self._transformSet = True self.pchanged() Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-09-11 12:46:27 UTC (rev 3829) +++ branches/transforms/lib/matplotlib/axes.py 2007-09-11 17:56:13 UTC (rev 3830) @@ -10,9 +10,9 @@ from matplotlib import artist as martist from matplotlib import affine as maffine -from matplotlib import bbox as mbbox from matplotlib import agg from matplotlib import axis as maxis +from matplotlib import bbox as mbbox from matplotlib import cbook from matplotlib import collections as mcoll from matplotlib import colors as mcolors @@ -33,9 +33,9 @@ iterable = cbook.iterable is_string_like = cbook.is_string_like +Wrapper = cbook.Wrapper - def delete_masked_points(*args): """ Find all masked points in a set of arguments, and return @@ -437,7 +437,6 @@ 1 : 'log', } - def __str__(self): return "Axes(%g,%g;%gx%g)"%(self._position[0].get(),self._position[1].get(), self._position[2].get(),self._position[3].get()) @@ -535,7 +534,6 @@ if self.yaxis is not None: self._ycid = self.yaxis.callbacks.connect('units finalize', self.relim) - def get_window_extent(self, *args, **kwargs): 'get the axes bounding box in display space; args and kwargs are empty' return self.bbox @@ -655,16 +653,16 @@ bottom = 0.0 top = 1.0 - - self.viewLim = Bbox.from_lbrt(left, bottom, right, top) - self.dataLim = Bbox.unit() - + self.dataLim = Bbox.unit() + self.transData = maffine.get_bbox_transform( self.viewLim, self.bbox) self.transAxes = maffine.get_bbox_transform( - Bbox.unit(), self.bbox) + self.dataLim, self.bbox) + print "_set_lim_and_transforms", self.viewLim, self.transData, self.dataLim, self.transAxes, self.bbox + # MGDTODO # if self._sharex: # self.transData.set_funcx(self._sharex.transData.get_funcx()) @@ -677,7 +675,8 @@ if original: return self._originalPosition[:] else: - return [val.get() for val in self._position] + return self._position[:] + # return [val.get() for val in self._position] def set_position(self, pos, which='both'): """ @@ -699,10 +698,13 @@ # # Change values within self._position--don't replace it. # for num,val in zip(pos, self._position): # val.set(num) + print "set_position", self._position, pos self._position = pos + # MGDTODO: side-effects if which in ('both', 'original'): self._originalPosition = pos - + + def _set_artist_props(self, a): 'set the boilerplate props for artists added to axes' a.set_figure(self.figure) @@ -1181,7 +1183,10 @@ #print type(x), type(y) # MGDTODO ## self.dataLim.update_numerix(x, y, -1) - pass + print "update_datalim_numerix", self.dataLim, + self.dataLim = mbbox.Bbox.from_data(x, y) + print self.dataLim + # MGDTODO side-effects def _get_verts_in_data_coords(self, trans, xys): if trans == self.transData: @@ -1190,8 +1195,8 @@ # display and then back to data to get it in data units #xys = trans.seq_xy_tups(xys) #return [ self.transData.inverse_xy_tup(xy) for xy in xys] - xys = trans.numerix_xy(npy.asarray(xys)) - return self.transData.inverse_numerix_xy(xys) + xys = trans(npy.asarray(xys)) + return self.transData.inverted()(xys) def _process_unit_info(self, xdata=None, ydata=None, kwargs=None): 'look for unit kwargs and update the axis instances as necessary' @@ -1242,7 +1247,8 @@ axis direction reversal that has already been done. """ # if image data only just use the datalim - + print "autoscale_view" + if not self._autoscaleon: return if (tight or (len(self.images)>0 and len(self.lines)==0 and @@ -1278,7 +1284,7 @@ if not self.get_visible(): return renderer.open_group('axes') self.apply_aspect() - # MGDTODO + # MGDTODO -- this is where we can finalize all of the transforms # self.transData.freeze() # eval the lazy objects # self.transAxes.freeze() if self.axison and self._frameon: self.axesPatch.draw(renderer) @@ -1544,9 +1550,12 @@ # raise ValueError('Cannot set nonpositive limits with log transform') xmin, xmax = mbbox.nonsingular(xmin, xmax, increasing=False) - self.viewLim.intervalx().set_bounds(xmin, xmax) - if emit: self.callbacks.process('xlim_changed', self) + # MGDTODO: This is fairly cumbersome + # MGDTODO: side-effects on x-bounds should propagate + self.viewLim = mbbox.Bbox.from_lbrt(xmin, self.viewLim.ymin(), xmax, self.viewLim.ymax()) + print 'set_xlim', self.viewLim + return xmin, xmax def get_xscale(self): @@ -1649,7 +1658,7 @@ ACCEPTS: len(2) sequence of floats """ - + print "set_ylim", ymin, ymax, emit if ymax is None and iterable(ymin): ymin,ymax = ymin @@ -1669,9 +1678,11 @@ # raise ValueError('Cannot set nonpositive limits with log transform') ymin, ymax = mbbox.nonsingular(ymin, ymax, increasing=False) - self.viewLim.intervaly().set_bounds(ymin, ymax) + # MGDTODO: side-effects on y-bounds should propagate + self.viewLim = mbbox.Bbox.from_lbrt(self.viewLim.xmin(), ymin, self.viewLim.xmax(), ymax) if emit: self.callbacks.process('ylim_changed', self) - + print "set_ylim", self.viewLim + return ymin, ymax def get_yscale(self): @@ -2158,7 +2169,7 @@ %(Annotation)s """ a = mtext.Annotation(*args, **kwargs) - a.set_transform(maffine.Affine2D.identity()) + a.set_transform(maffine.Affine2D()) self._set_artist_props(a) if kwargs.has_key('clip_on'): a.set_clip_box(self.bbox) self.texts.append(a) @@ -2197,7 +2208,7 @@ %(Line2D)s """ - trans = maffine.blend_xy_sep_transform( self.transAxes, self.transData) + trans = maffine.blend_xy_sep_transform(self.transAxes, self.transData) l, = self.plot([xmin,xmax], [y,y], transform=trans, scalex=False, **kwargs) return l Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-09-11 12:46:27 UTC (rev 3829) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-09-11 17:56:13 UTC (rev 3830) @@ -752,7 +752,7 @@ else: # Just found one hit self.inaxes = axes_list[0] - try: xdata, ydata = self.inaxes.transData.inverse_xy_tup((x, y)) + try: xdata, ydata = self.inaxes.transData.inverted()([[x, y]])[0] except ValueError: self.xdata = None self.ydata = None Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-11 12:46:27 UTC (rev 3829) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-11 17:56:13 UTC (rev 3830) @@ -113,11 +113,12 @@ debug=False) if __debug__: verbose.report('RendererAgg.__init__ _RendererAgg done', 'debug-annoying') - self.draw_polygon = self._renderer.draw_polygon + # self.draw_polygon = self._renderer.draw_polygon self.draw_rectangle = self._renderer.draw_rectangle self.draw_path = self._renderer.draw_path + # MGDTODO -- remove these lines # self.draw_lines = self._renderer.draw_lines - self.draw_markers = self._renderer.draw_markers + # self.draw_markers = self._renderer.draw_markers self.draw_image = self._renderer.draw_image self.draw_line_collection = self._renderer.draw_line_collection self.draw_quad_mesh = self._renderer.draw_quad_mesh @@ -161,8 +162,13 @@ def draw_lines(self, gc, x, y, transform): return self._renderer.draw_lines(gc, x, y, transform.to_values()) - + def draw_markers(self, gc, path, color, x, y, transform): + return self._renderer.draw_markers(gc, path, color, x, y, transform.to_values()) + + def draw_polygon(self, *args): + return self._renderer.draw_polygon(*args) + def draw_point(self, gc, x, y): """ Draw a single point at x,y @@ -325,8 +331,10 @@ """ if __debug__: verbose.report('RendererAgg.points_to_pixels', 'debug-annoying') - return points*self.dpi.get()/72.0 - + # MGDTODO + # return points*self.dpi.get()/72.0 + return points*self.dpi/72.0 + def tostring_rgb(self): if __debug__: verbose.report('RendererAgg.tostring_rgb', 'debug-annoying') Modified: branches/transforms/lib/matplotlib/backends/backend_tkagg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_tkagg.py 2007-09-11 12:46:27 UTC (rev 3829) +++ branches/transforms/lib/matplotlib/backends/backend_tkagg.py 2007-09-11 17:56:13 UTC (rev 3830) @@ -175,7 +175,8 @@ self._resize_callback(event) # compute desired figure size in inches - dpival = self.figure.dpi.get() + # dpival = self.figure.dpi.get() MGDTODO + dpival = self.figure.dpi winch = width/dpival hinch = height/dpival self.figure.set_size_inches(winch, hinch) Modified: branches/transforms/lib/matplotlib/bbox.py =================================================================== --- branches/transforms/lib/matplotlib/bbox.py 2007-09-11 12:46:27 UTC (rev 3829) +++ branches/transforms/lib/matplotlib/bbox.py 2007-09-11 17:56:13 UTC (rev 3830) @@ -21,9 +21,6 @@ def get_bounds(self): return self._bounds - def set_bounds(self, lower, upper): - self._bounds = lower, upper - def span(self): bounds = self._bounds return bounds[1] - bounds[0] @@ -47,8 +44,23 @@ return Bbox([[left, bottom], [right, top]]) from_lbrt = staticmethod(from_lbrt) + #@staticmethod + def from_data(x, y): + return Bbox([[x.min(), y.min()], [x.max(), y.max()]]) + from_data = staticmethod(from_data) + def copy(self): return Bbox(self._points.copy()) + + def __repr__(self): + return 'Bbox(%s)' % repr(self._points) + __str__ = __repr__ + + def __cmp__(self, other): + # MGDTODO: Totally suboptimal + if isinstance(other, Bbox): + return (self._points == other._points).all() + return -1 # MGDTODO: Probably a more efficient ways to do this... def xmin(self): @@ -79,6 +91,7 @@ return (self.xmin(), self.ymin(), self.xmax() - self.xmin(), self.ymax() - self.ymin()) + # MGDTODO: This is an inefficient way to do this def intervalx(self): return Interval(self._points[0]) @@ -92,10 +105,11 @@ deltah = (sh * height - height) / 2.0 a = N.array([[-deltaw, -deltah], [deltaw, deltah]]) return Bbox(self._points + a) - -def lbwh_to_bbox(left, bottom, width, height): - return Bbox([[left, bottom], [left + width, bottom + height]]) - + + def contains(self, x, y): + return (x >= self.xmin() and x <= self.xmax() and + y >= self.ymin() and y <= self.ymax()) + def bbox_union(bboxes): """ Return the Bbox that bounds all bboxes Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-09-11 12:46:27 UTC (rev 3829) +++ branches/transforms/lib/matplotlib/figure.py 2007-09-11 17:56:13 UTC (rev 3830) @@ -105,8 +105,9 @@ class Figure(Artist): def __str__(self): - return "Figure(%gx%g)"%(self.figwidth.get(),self.figheight.get()) - + return "Figure(%gx%g)"%(self.figwidth, self.figheight) + # return "Figure(%gx%g)"%(self.figwidth.get(),self.figheight.get()) + def __init__(self, figsize = None, # defaults to rc figure.figsize dpi = None, # defaults to rc figure.dpi @@ -129,10 +130,9 @@ if edgecolor is None: edgecolor = rcParams['figure.edgecolor'] self.dpi = dpi - self.figsize = figsize - self.bbox = Bbox.from_lbwh(0, 0, - figsize[0] * dpi, - figsize[1] * dpi) + self.figwidth = figsize[0] * dpi + self.figheight = figsize[1] * dpi + self.bbox = Bbox.from_lbwh(0, 0, self.figwidth, self.figheight) self.frameon = frameon @@ -324,11 +324,16 @@ w,h = args[0] else: w,h = args - self.figwidth.set(w) - self.figheight.set(h) + + self.figwidth = w + self.figheight = h + # self.figwidth.set(w) MGDTODO + # self.figheight.set(h) + if forward: - dpival = self.dpi.get() + # dpival = self.dpi.get() + dpival = self.dpi canvasw = w*dpival canvash = h*dpival manager = getattr(self.canvas, 'manager', None) @@ -336,7 +341,8 @@ manager.resize(int(canvasw), int(canvash)) def get_size_inches(self): - return self.figwidth.get(), self.figheight.get() + return self.figwidth, self.figheight + # return self.figwidth.get(), self.figheight.get() MGDTODO def get_edgecolor(self): 'Get the edge color of the Figure rectangle' @@ -348,7 +354,8 @@ def get_figwidth(self): 'Return the figwidth as a float' - return self.figwidth.get() + return self.figwidth + # return self.figwidth.get() MGDTODO def get_figheight(self): 'Return the figheight as a float' @@ -356,7 +363,8 @@ def get_dpi(self): 'Return the dpi as a float' - return self.dpi.get() + return self.dpi + # return self.dpi.get() MGDTODO def get_frameon(self): 'get the boolean indicating frameon' @@ -384,7 +392,8 @@ ACCEPTS: float """ - self.dpi.set(val) + # self.dpi.set(val) MGDTODO + self.dpi = val def set_figwidth(self, val): """ @@ -392,15 +401,17 @@ ACCEPTS: float """ - self.figwidth.set(val) - + # self.figwidth.set(val) MGDTODO + self.figwidth = val + def set_figheight(self, val): """ Set the height of the figure in inches ACCEPTS: float """ - self.figheight.set(val) + # MGDTODO (set()) + self.figheight = val def set_frameon(self, b): """ Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-09-11 12:46:27 UTC (rev 3829) +++ branches/transforms/lib/matplotlib/lines.py 2007-09-11 17:56:13 UTC (rev 3830) @@ -18,7 +18,7 @@ from cbook import iterable, is_string_like, is_numlike from colors import colorConverter -from bbox import lbwh_to_bbox +from bbox import Bbox from matplotlib import rcParams # special-purpose marker identifiers: @@ -368,6 +368,7 @@ a = npy.vstack((x, y)).swapaxes(0, 1) #### x, y = self.get_transform()(a) + print "get_window_extent", self.get_transform() #x, y = self.get_transform().seq_x_y(x, y) @@ -384,10 +385,11 @@ bottom -= ms/2 width += ms height += ms - return lbwh_to_bbox(left, bottom, width, height) + return Bbox.from_lbwh(left, bottom, width, height) def set_axes(self, ax): + print "set_axes" Artist.set_axes(self, ax) if ax.xaxis is not None: self._xcid = ax.xaxis.callbacks.connect('units', self.recache) Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-09-11 12:46:27 UTC (rev 3829) +++ branches/transforms/lib/matplotlib/patches.py 2007-09-11 17:56:13 UTC (rev 3830) @@ -212,7 +212,7 @@ tverts = self.get_transform()(verts) # MGDTODO: This result is an Nx2 numpy array, which could be passed - # directly to renderer.draw_polygon. However, it currently expects + # directly to renderer.draw_polygon since it currently expects # a list of tuples so we're converting it to that now. tverts = [tuple(x) for x in tverts] Modified: branches/transforms/lib/matplotlib/text.py =================================================================== --- branches/transforms/lib/matplotlib/text.py 2007-09-11 12:46:27 UTC (rev 3829) +++ branches/transforms/lib/matplotlib/text.py 2007-09-11 17:56:13 UTC (rev 3830) @@ -15,7 +15,7 @@ from cbook import enumerate, is_string_like, maxdict, is_numlike from font_manager import FontProperties from patches import bbox_artist, YAArrow -from bbox import lbwh_to_bbox, bbox_union +from bbox import Bbox, bbox_union from lines import Line2D import matplotlib.nxutils as nxutils @@ -40,8 +40,6 @@ angle = float(rotation) return angle%360 -_unit_box = lbwh_to_bbox(0,0,1,1) - # these are not available for the object inspector until after the # class is build so we define an initial set here for the init # function and they will be overridden after object defn @@ -264,7 +262,7 @@ ymin += offsety ymax += offsety - bbox = lbwh_to_bbox(xmin, ymin, width, height) + bbox = Bbox.from_lbwh(xmin, ymin, width, height) # now rotate the positions around the first x,y position @@ -423,10 +421,10 @@ def get_window_extent(self, renderer=None): #return _unit_box - if not self.get_visible(): return _unit_box + if not self.get_visible(): return Bbox.unit() if self._text == '': tx, ty = self._get_xy_display() - return lbwh_to_bbox(tx,ty,0,0) + return Bbox.from_lbwh(tx,ty,0,0) if renderer is not None: self._renderer = renderer Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-09-11 12:46:27 UTC (rev 3829) +++ branches/transforms/src/_backend_agg.cpp 2007-09-11 17:56:13 UTC (rev 3830) @@ -56,7 +56,7 @@ throw Py::ValueError("Transformation matrix must be given as a 6-element list."); } - agg::trans_affine xytrans = agg::trans_affine + return agg::trans_affine (Py::Float(seq[0]), Py::Float(seq[1]), Py::Float(seq[2]), @@ -1935,18 +1935,8 @@ if (ya==NULL) throw Py::TypeError("RendererAgg::_draw_markers_cache expected numerix array"); - Transformation* mpltransform = static_cast<Transformation*>(args[5].ptr()); + agg::trans_affine xytrans = py_sequence_to_agg_transformation_matrix(args[5]); - double a, b, c, d, tx, ty; - try { - mpltransform->affine_params_api(&a, &b, &c, &d, &tx, &ty); - } - catch(...) { - throw Py::ValueError("Domain error on affine_params_api in RendererAgg::_draw_markers_cache"); - } - - agg::trans_affine xytrans = agg::trans_affine(a,b,c,d,tx,ty); - size_t Nx = xa->dimensions[0]; size_t Ny = ya->dimensions[0]; @@ -2006,15 +1996,16 @@ for (size_t i=0; i<Nx; i++) { thisx = *(double *)(xa->data + i*xa->strides[0]); thisy = *(double *)(ya->data + i*ya->strides[0]); + + // MGDTODO +// if (mpltransform->need_nonlinear_api()) +// try { +// mpltransform->nonlinear_only_api(&thisx, &thisy); +// } +// catch(...) { +// continue; +// } - if (mpltransform->need_nonlinear_api()) - try { - mpltransform->nonlinear_only_api(&thisx, &thisy); - } - catch(...) { - continue; - } - xytrans.transform(&thisx, &thisy); thisy = heightd - thisy; //flipy This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-11 17:57:48
|
Revision: 3831 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3831&view=rev Author: mdboom Date: 2007-09-11 10:57:47 -0700 (Tue, 11 Sep 2007) Log Message: ----------- Merged revisions 3824-3830 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3825 | pkienzle | 2007-09-10 14:45:32 -0400 (Mon, 10 Sep 2007) | 1 line Windows needs binary open flag for font files ........ r3827 | jouni | 2007-09-10 16:31:01 -0400 (Mon, 10 Sep 2007) | 2 lines Better bounding boxes for pdf usetex, including descents. ........ r3828 | jouni | 2007-09-10 16:55:29 -0400 (Mon, 10 Sep 2007) | 2 lines Bugfixes in pdf usetex ........ r3829 | mdboom | 2007-09-11 08:46:27 -0400 (Tue, 11 Sep 2007) | 3 lines Fix bug in PDF clip routine that resulted in the cryptic error message "There are too many arguments" in Adobe Acrobat. ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/backends/backend_pdf.py branches/transforms/lib/matplotlib/dviread.py branches/transforms/ttconv/pprdrv_tt.cpp Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3823 + /trunk/matplotlib:1-3830 Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-09-11 17:56:13 UTC (rev 3830) +++ branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-09-11 17:57:47 UTC (rev 3831) @@ -519,12 +519,13 @@ ul_position, ul_thickness = font.get_ps_font_info() if fontinfo.encodingfile is not None: - differencesArray = [ Name(ch) for ch in - dviread.Encoding(fontinfo.encodingfile) ] + enc = dviread.Encoding(fontinfo.encodingfile) + widths = [ afmdata.get_width_from_char_name(ch) + for ch in enc ] + differencesArray = [ Name(ch) for ch in enc ] differencesArray = [ 0 ] + differencesArray firstchar = 0 lastchar = len(differencesArray) - 2 - widths = [ 100 for x in range(firstchar,lastchar+1) ] # XXX TODO else: widths = [ None for i in range(256) ] for ch in range(256): @@ -1434,7 +1435,7 @@ fontsize = prop.get_size_in_points() dvifile = texmanager.make_dvi(s, fontsize) dvi = dviread.Dvi(dvifile, 72) - text, boxes = iter(dvi).next() + page = iter(dvi).next() dvi.close() if angle == 0: # avoid rounding errors in common case @@ -1448,7 +1449,7 @@ # Gather font information and do some setup for combining # characters into strings. oldfontnum, seq = None, [] - for x1, y1, fontnum, glyph, width in text: + for x1, y1, fontnum, glyph, width in page.text: if fontnum != oldfontnum: texname, fontsize = dvi.fontinfo(fontnum) fontinfo = self.tex_font_mapping(texname) @@ -1462,8 +1463,8 @@ seq += [('end',)] # Find consecutive text strings with constant x coordinate and - # combine into one string (if needed kern would be less than - # 0.1 points) or several strings interspersed with kerns. + # combine into a sequence of strings and kerns, or just one + # string (if any kerns would be less than 0.1 points). i, curx = 0, 0 while i < len(seq)-1: elt, next = seq[i:i+2] @@ -1503,7 +1504,7 @@ boxgc = self.new_gc() boxgc.copy_properties(gc) boxgc.set_linewidth(0) - for x1, y1, h, w in boxes: + for x1, y1, h, w in page.boxes: (x1, y1), (x2, y2), (x3, y3), (x4, y4) = \ mytrans(x1, y1), mytrans(x1+w, y1), \ mytrans(x1+w, y1+h), mytrans(x1, y1+h) @@ -1653,14 +1654,9 @@ fontsize = prop.get_size_in_points() dvifile = texmanager.make_dvi(s, fontsize) dvi = dviread.Dvi(dvifile, 72) - text, boxes = iter(dvi).next() - # TODO: better bounding box -- this is not quite right: - l = min(p[0] for p in text+boxes) - r = max(p[0] for p in text+boxes) + fontsize - b = min(p[1] for p in text+boxes) - t = max(p[1] for p in text+boxes) + fontsize - # (not to even mention finding the baseline) - return r-l, t-b, t-b + page = iter(dvi).next() + dvi.close() + return page.width, page.height, page.descent if ismath: w, h, d, glyphs, rects, used_characters = \ self.mathtext_parser.parse(s, 72, prop) @@ -1837,7 +1833,7 @@ cmds.extend(self.pop()) # Unless we hit the right one, set the clip polygon if (self._cliprect, self._clippath) != (cliprect, clippath): - cmds.append(self.push()) + cmds.extend(self.push()) if self._cliprect != cliprect: cmds.extend([t for t in cliprect] + [Op.rectangle, Op.clip, Op.endpath]) Modified: branches/transforms/lib/matplotlib/dviread.py =================================================================== --- branches/transforms/lib/matplotlib/dviread.py 2007-09-11 17:56:13 UTC (rev 3830) +++ branches/transforms/lib/matplotlib/dviread.py 2007-09-11 17:57:47 UTC (rev 3831) @@ -6,19 +6,21 @@ Interface: dvi = Dvi(filename, 72) - for text, boxes in dvi: # iterate over pages - text, boxes = dvi.output(72) - for x,y,font,glyph,width in text: + for page in dvi: # iterate over pages + w, h, d = page.width, page.height, page.descent + for x,y,font,glyph,width in page.text: fontname, pointsize = dvi.fontinfo(font) ... - for x,y,height,width in boxes: + for x,y,height,width in page.boxes: ... """ -# TODO: support for TeX virtual fonts (*.vf) which are a dvi-like format +# TODO: support TeX virtual fonts (*.vf) which are a sort of +# subroutine collections for dvi files import matplotlib import matplotlib.cbook as mpl_cbook +import numpy as npy import os import struct @@ -74,21 +76,34 @@ def _output(self): """ Output the text and boxes belonging to the most recent page. - text, boxes = dvi._output() + page = dvi._output() """ - t0 = self.text[0] - minx, miny, maxx, maxy = t0[0], t0[1], t0[0], t0[1] + minx, miny, maxx, maxy = npy.inf, npy.inf, -npy.inf, -npy.inf + maxy_pure = -npy.inf for elt in self.text + self.boxes: - x,y = elt[:2] - if x < minx: minx = x - if y < miny: miny = y - if x > maxx: maxx = x - if y > maxy: maxy = y + if len(elt) == 4: # box + x,y,h,w = elt + e = 0 # zero depth + else: # glyph + x,y,f,g,w = elt + font = self.fonts[f] + h = (font.scale * font.tfm.height[g]) >> 20 + e = (font.scale * font.tfm.depth[g]) >> 20 + minx = min(minx, x) + miny = min(miny, y - h) + maxx = max(maxx, x + w) + maxy = max(maxy, y + e) + maxy_pure = max(maxy_pure, y) + d = self.dpi / (72.27 * 2**16) # from TeX's "scaled points" to dpi units text = [ ((x-minx)*d, (maxy-y)*d, f, g, w*d) for (x,y,f,g,w) in self.text ] boxes = [ ((x-minx)*d, (maxy-y)*d, h*d, w*d) for (x,y,h,w) in self.boxes ] - return text, boxes + return mpl_cbook.Bunch(text=text, boxes=boxes, + width=(maxx-minx)*d, + height=(maxy_pure-miny)*d, + descent=(maxy-maxy_pure)*d) + def fontinfo(self, f): """ texname, pointsize = dvi.fontinfo(fontnum) @@ -361,6 +376,7 @@ width[i]: width of character #i, needs to be scaled by the factor specified in the dvi file (this is a dict because indexing may not start from 0) + height[i], depth[i]: height and depth of character #i """ def __init__(self, filename): @@ -368,22 +384,29 @@ try: header1 = file.read(24) - lh, bc, ec, nw = \ - struct.unpack('!4H', header1[2:10]) + lh, bc, ec, nw, nh, nd = \ + struct.unpack('!6H', header1[2:14]) header2 = file.read(4*lh) self.checksum, self.design_size = \ struct.unpack('!2I', header2[:8]) # there is also encoding information etc. char_info = file.read(4*(ec-bc+1)) widths = file.read(4*nw) + heights = file.read(4*nh) + depths = file.read(4*nd) finally: file.close() - widths = struct.unpack('!%dI' % nw, widths) - self.width = {} + self.width, self.height, self.depth = {}, {}, {} + widths, heights, depths = \ + [ struct.unpack('!%dI' % n, x) + for n,x in [(nw, widths), (nh, heights), (nd, depths)] ] for i in range(ec-bc): self.width[bc+i] = widths[ord(char_info[4*i])] + self.height[bc+i] = heights[ord(char_info[4*i+1]) >> 4] + self.depth[bc+i] = depths[ord(char_info[4*i+1]) & 0xf] + class PsfontsMap(object): """ A psfonts.map formatted file, mapping TeX fonts to PS fonts. Modified: branches/transforms/ttconv/pprdrv_tt.cpp =================================================================== --- branches/transforms/ttconv/pprdrv_tt.cpp 2007-09-11 17:56:13 UTC (rev 3830) +++ branches/transforms/ttconv/pprdrv_tt.cpp 2007-09-11 17:57:47 UTC (rev 3831) @@ -1088,7 +1088,7 @@ font.filename=filename; /* Open the font file */ - if( (font.file = fopen(filename,"r")) == (FILE*)NULL ) + if( (font.file = fopen(filename,"rb")) == (FILE*)NULL ) throw TTException("Failed to open TrueType font"); /* Allocate space for the unvarying part of the offset table. */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-12 14:05:25
|
Revision: 3836 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3836&view=rev Author: mdboom Date: 2007-09-12 07:05:20 -0700 (Wed, 12 Sep 2007) Log Message: ----------- Merged revisions 3831-3835 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3832 | dsdale | 2007-09-11 14:46:47 -0400 (Tue, 11 Sep 2007) | 3 lines removed MANIFEST from revision control. It is generated by MANIFEST.in when building source distribution archives ........ r3833 | jrevans | 2007-09-11 15:40:27 -0400 (Tue, 11 Sep 2007) | 5 lines Added the ability for the following in the various GUI backends: >>> import pylab >>> fig = pylab.figure() >>> fig.canvas.set_window_title("My Plot Window") ........ r3834 | jouni | 2007-09-12 03:04:38 -0400 (Wed, 12 Sep 2007) | 3 lines Further development of dviread. It now attempts to read virtual fonts, but the positioning is still somewhat off. ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_fltkagg.py branches/transforms/lib/matplotlib/backends/backend_gtk.py branches/transforms/lib/matplotlib/backends/backend_pdf.py branches/transforms/lib/matplotlib/backends/backend_qt.py branches/transforms/lib/matplotlib/backends/backend_qt4.py branches/transforms/lib/matplotlib/backends/backend_tkagg.py branches/transforms/lib/matplotlib/backends/backend_wx.py branches/transforms/lib/matplotlib/dviread.py Removed Paths: ------------- branches/transforms/MANIFEST Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3830 + /trunk/matplotlib:1-3835 Deleted: branches/transforms/MANIFEST =================================================================== --- branches/transforms/MANIFEST 2007-09-12 13:36:25 UTC (rev 3835) +++ branches/transforms/MANIFEST 2007-09-12 14:05:20 UTC (rev 3836) @@ -1,1398 +0,0 @@ -API_CHANGES -CHANGELOG -INSTALL -INTERACTIVE -KNOWN_BUGS -MANIFEST.in -Makefile -NUMARRAY_ISSUES -README -TODO -__init__.py -makeswig.py -matplotlibrc.template -setup.cfg -setup.py -setupegg.py -setupext.py -CXX/Config.hxx -CXX/Exception.hxx -CXX/Extensions.hxx -CXX/IndirectPythonInterface.cxx -CXX/IndirectPythonInterface.hxx -CXX/Objects.hxx -CXX/Version.hxx -CXX/cxx_extensions.cxx -CXX/cxxextensions.c -CXX/cxxsupport.cxx -agg23/font_freetype/Makefile.am -agg23/font_freetype/agg_font_freetype.cpp -agg23/font_freetype/agg_font_freetype.h -agg23/font_win32_tt/agg_font_win32_tt.cpp -agg23/font_win32_tt/agg_font_win32_tt.h -agg23/include/Makefile.am -agg23/include/agg_alpha_mask_u8.h -agg23/include/agg_arc.h -agg23/include/agg_array.h -agg23/include/agg_arrowhead.h -agg23/include/agg_basics.h -agg23/include/agg_bezier_arc.h -agg23/include/agg_bitset_iterator.h -agg23/include/agg_bounding_rect.h -agg23/include/agg_bspline.h -agg23/include/agg_clip_liang_barsky.h -agg23/include/agg_color_gray.h -agg23/include/agg_color_rgba.h -agg23/include/agg_config.h -agg23/include/agg_conv_adaptor_vcgen.h -agg23/include/agg_conv_adaptor_vpgen.h -agg23/include/agg_conv_bspline.h -agg23/include/agg_conv_clip_polygon.h -agg23/include/agg_conv_clip_polyline.h -agg23/include/agg_conv_close_polygon.h -agg23/include/agg_conv_concat.h -agg23/include/agg_conv_contour.h -agg23/include/agg_conv_curve.h -agg23/include/agg_conv_dash.h -agg23/include/agg_conv_gpc.h -agg23/include/agg_conv_marker.h -agg23/include/agg_conv_marker_adaptor.h -agg23/include/agg_conv_segmentator.h -agg23/include/agg_conv_shorten_path.h -agg23/include/agg_conv_smooth_poly1.h -agg23/include/agg_conv_stroke.h -agg23/include/agg_conv_transform.h -agg23/include/agg_conv_unclose_polygon.h -agg23/include/agg_curves.h -agg23/include/agg_dda_line.h -agg23/include/agg_ellipse.h -agg23/include/agg_ellipse_bresenham.h -agg23/include/agg_embedded_raster_fonts.h -agg23/include/agg_font_cache_manager.h -agg23/include/agg_gamma_functions.h -agg23/include/agg_gamma_lut.h -agg23/include/agg_glyph_raster_bin.h -agg23/include/agg_gsv_text.h -agg23/include/agg_image_filters.h -agg23/include/agg_line_aa_basics.h -agg23/include/agg_math.h -agg23/include/agg_math_stroke.h -agg23/include/agg_path_storage.h -agg23/include/agg_path_storage_integer.h -agg23/include/agg_pattern_filters_rgba.h -agg23/include/agg_pixfmt_amask_adaptor.h -agg23/include/agg_pixfmt_gray.h -agg23/include/agg_pixfmt_rgb.h -agg23/include/agg_pixfmt_rgb_packed.h -agg23/include/agg_pixfmt_rgba.h -agg23/include/agg_rasterizer_outline.h -agg23/include/agg_rasterizer_outline_aa.h -agg23/include/agg_rasterizer_scanline_aa.h -agg23/include/agg_render_scanlines.h -agg23/include/agg_renderer_base.h -agg23/include/agg_renderer_markers.h -agg23/include/agg_renderer_mclip.h -agg23/include/agg_renderer_outline_aa.h -agg23/include/agg_renderer_outline_image.h -agg23/include/agg_renderer_primitives.h -agg23/include/agg_renderer_raster_text.h -agg23/include/agg_renderer_scanline.h -agg23/include/agg_rendering_buffer.h -agg23/include/agg_rendering_buffer_dynarow.h -agg23/include/agg_rounded_rect.h -agg23/include/agg_scanline_bin.h -agg23/include/agg_scanline_boolean_algebra.h -agg23/include/agg_scanline_p.h -agg23/include/agg_scanline_storage_aa.h -agg23/include/agg_scanline_storage_bin.h -agg23/include/agg_scanline_u.h -agg23/include/agg_shorten_path.h -agg23/include/agg_simul_eq.h -agg23/include/agg_span_allocator.h -agg23/include/agg_span_converter.h -agg23/include/agg_span_generator.h -agg23/include/agg_span_gouraud.h -agg23/include/agg_span_gouraud_gray.h -agg23/include/agg_span_gouraud_rgba.h -agg23/include/agg_span_gradient.h -agg23/include/agg_span_gradient_alpha.h -agg23/include/agg_span_image_filter.h -agg23/include/agg_span_image_filter_gray.h -agg23/include/agg_span_image_filter_rgb.h -agg23/include/agg_span_image_filter_rgba.h -agg23/include/agg_span_image_resample.h -agg23/include/agg_span_image_resample_gray.h -agg23/include/agg_span_image_resample_rgb.h -agg23/include/agg_span_image_resample_rgba.h -agg23/include/agg_span_interpolator_adaptor.h -agg23/include/agg_span_interpolator_linear.h -agg23/include/agg_span_interpolator_persp.h -agg23/include/agg_span_interpolator_trans.h -agg23/include/agg_span_pattern.h -agg23/include/agg_span_pattern_filter_gray.h -agg23/include/agg_span_pattern_filter_rgb.h -agg23/include/agg_span_pattern_filter_rgba.h -agg23/include/agg_span_pattern_resample_gray.h -agg23/include/agg_span_pattern_resample_rgb.h -agg23/include/agg_span_pattern_resample_rgba.h -agg23/include/agg_span_pattern_rgb.h -agg23/include/agg_span_pattern_rgba.h -agg23/include/agg_span_solid.h -agg23/include/agg_span_subdiv_adaptor.h -agg23/include/agg_trans_affine.h -agg23/include/agg_trans_bilinear.h -agg23/include/agg_trans_double_path.h -agg23/include/agg_trans_lens.h -agg23/include/agg_trans_perspective.h -agg23/include/agg_trans_single_path.h -agg23/include/agg_trans_viewport.h -agg23/include/agg_trans_warp_magnifier.h -agg23/include/agg_vcgen_bspline.h -agg23/include/agg_vcgen_contour.h -agg23/include/agg_vcgen_dash.h -agg23/include/agg_vcgen_markers_term.h -agg23/include/agg_vcgen_smooth_poly1.h -agg23/include/agg_vcgen_stroke.h -agg23/include/agg_vcgen_vertex_sequence.h -agg23/include/agg_vertex_sequence.h -agg23/include/agg_vpgen_clip_polygon.h -agg23/include/agg_vpgen_clip_polyline.h -agg23/include/agg_vpgen_segmentator.h -agg23/include/ctrl/Makefile.am -agg23/include/ctrl/agg_bezier_ctrl.h -agg23/include/ctrl/agg_cbox_ctrl.h -agg23/include/ctrl/agg_ctrl.h -agg23/include/ctrl/agg_gamma_ctrl.h -agg23/include/ctrl/agg_gamma_spline.h -agg23/include/ctrl/agg_polygon_ctrl.h -agg23/include/ctrl/agg_rbox_ctrl.h -agg23/include/ctrl/agg_scale_ctrl.h -agg23/include/ctrl/agg_slider_ctrl.h -agg23/include/ctrl/agg_spline_ctrl.h -agg23/include/platform/Makefile.am -agg23/include/platform/agg_platform_support.h -agg23/include/platform/mac/agg_mac_pmap.h -agg23/include/platform/win32/agg_win32_bmp.h -agg23/include/util/Makefile.am -agg23/include/util/agg_color_conv.h -agg23/include/util/agg_color_conv_rgb16.h -agg23/include/util/agg_color_conv_rgb8.h -agg23/src/ChangeLog -agg23/src/Makefile -agg23/src/Makefile.am -agg23/src/agg_arc.cpp -agg23/src/agg_arrowhead.cpp -agg23/src/agg_bezier_arc.cpp -agg23/src/agg_bspline.cpp -agg23/src/agg_curves.cpp -agg23/src/agg_embedded_raster_fonts.cpp -agg23/src/agg_gsv_text.cpp -agg23/src/agg_image_filters.cpp -agg23/src/agg_line_aa_basics.cpp -agg23/src/agg_line_profile_aa.cpp -agg23/src/agg_path_storage.cpp -agg23/src/agg_rasterizer_scanline_aa.cpp -agg23/src/agg_rounded_rect.cpp -agg23/src/agg_sqrt_tables.cpp -agg23/src/agg_trans_affine.cpp -agg23/src/agg_trans_double_path.cpp -agg23/src/agg_trans_single_path.cpp -agg23/src/agg_trans_warp_magnifier.cpp -agg23/src/agg_vcgen_bspline.cpp -agg23/src/agg_vcgen_contour.cpp -agg23/src/agg_vcgen_dash.cpp -agg23/src/agg_vcgen_markers_term.cpp -agg23/src/agg_vcgen_smooth_poly1.cpp -agg23/src/agg_vcgen_stroke.cpp -agg23/src/agg_vpgen_clip_polygon.cpp -agg23/src/agg_vpgen_clip_polyline.cpp -agg23/src/agg_vpgen_segmentator.cpp -agg23/src/authors -agg23/src/autogen.sh -agg23/src/configure.in -agg23/src/copying -agg23/src/install -agg23/src/news -agg23/src/readme -agg23/src/ctrl/Makefile.am -agg23/src/ctrl/agg_bezier_ctrl.cpp -agg23/src/ctrl/agg_cbox_ctrl.cpp -agg23/src/ctrl/agg_gamma_ctrl.cpp -agg23/src/ctrl/agg_gamma_spline.cpp -agg23/src/ctrl/agg_polygon_ctrl.cpp -agg23/src/ctrl/agg_rbox_ctrl.cpp -agg23/src/ctrl/agg_scale_ctrl.cpp -agg23/src/ctrl/agg_slider_ctrl.cpp -agg23/src/ctrl/agg_spline_ctrl.cpp -agg23/src/platform/Makefile.am -agg23/src/platform/AmigaOS/agg_platform_support.cpp -agg23/src/platform/BeOS/agg_platform_support.cpp -agg23/src/platform/X11/Makefile.am -agg23/src/platform/X11/agg_platform_support.cpp -agg23/src/platform/mac/agg_mac_pmap.cpp -agg23/src/platform/mac/agg_platform_support.cpp -agg23/src/platform/sdl/agg_platform_support.cpp -agg23/src/platform/win32/agg_platform_support.cpp -agg23/src/platform/win32/agg_win32_bmp.cpp -agg23/svg/agg_svg_exception.h -agg23/svg/agg_svg_parser.cpp -agg23/svg/agg_svg_parser.h -agg23/svg/agg_svg_path_renderer.cpp -agg23/svg/agg_svg_path_renderer.h -agg23/svg/agg_svg_path_tokenizer.cpp -agg23/svg/agg_svg_path_tokenizer.h -agg23/svg/svg_test.cpp -agg23/svg/BeOS/Makefile -agg23/svg/X11/Makefile -agg23/svg/macos_cw/expat.h -agg23/svg/macos_cw/include.h -agg23/svg/macos_cw/xmlparse.h -agg23/svg/win32_api/Makefile -agg23/svg/win32_api/svg_test.dsp -agg23/svg/win32_api/svg_test.dsw -examples/README -examples/__init__.py -examples/accented_text.py -examples/agg_oo.py -examples/agg_resize.py -examples/agg_test.py -examples/alignment_test.py -examples/anim.py -examples/anim_tk.py -examples/animation_blit.py -examples/animation_blit_fltk.py -examples/animation_blit_qt.py -examples/animation_blit_qt4.py -examples/animation_blit_tk.py -examples/animation_blit_wx.py -examples/annotation_demo.py -examples/anscombe.py -examples/arctest.py -examples/arrow_demo.py -examples/axes_demo.py -examples/axes_props.py -examples/axhspan_demo.py -examples/axis_equal_demo.py -examples/backend_driver.py -examples/bar_stacked.py -examples/barchart_demo.py -examples/barcode_demo.py -examples/barh_demo.py -examples/boxplot_demo.py -examples/break.py -examples/broken_barh.py -examples/clippath_test.py -examples/clippedline.py -examples/collections_demo.py -examples/color_by_yvalue.py -examples/color_demo.py -examples/colours.py -examples/contour_demo.py -examples/contour_image.py -examples/contourf_demo.py -examples/coords_demo.py -examples/coords_report.py -examples/csd_demo.py -examples/cursor_demo.py -examples/custom_figure_class.py -examples/custom_ticker1.py -examples/customize_rc.py -examples/dannys_example.py -examples/dash_control.py -examples/dashpointlabel.py -examples/dashtick.py -examples/data_helper.py -examples/date_demo1.py -examples/date_demo2.py -examples/date_demo_convert.py -examples/date_demo_rrule.py -examples/dynamic_collection.py -examples/dynamic_demo.py -examples/dynamic_demo_wx.py -examples/dynamic_image_gtkagg.py -examples/dynamic_image_wxagg.py -examples/dynamic_image_wxagg2.py -examples/ellipse_demo.py -examples/ellipse_rotated.py -examples/embedding_in_gtk.py -examples/embedding_in_gtk2.py -examples/embedding_in_gtk3.py -examples/embedding_in_qt.py -examples/embedding_in_qt4.py -examples/embedding_in_tk.py -examples/embedding_in_tk2.py -examples/embedding_in_wx.py -examples/embedding_in_wx2.py -examples/embedding_in_wx3.py -examples/embedding_in_wx4.py -examples/errorbar_demo.py -examples/figimage_demo.py -examples/figlegend_demo.py -examples/figtext.py -examples/fill_between.py -examples/fill_between_posneg.py -examples/fill_demo.py -examples/fill_demo2.py -examples/fill_spiral.py -examples/finance_demo.py -examples/font_indexing.py -examples/font_table_ttf.py -examples/fonts_demo.py -examples/fonts_demo_kw.py -examples/ftface_props.py -examples/ganged_plots.py -examples/gdtest.py -examples/glyph_to_path.py -examples/gtk_spreadsheet.py -examples/hatch_demo.py -examples/histogram_demo.py -examples/histogram_demo_canvasagg.py -examples/image_demo.py -examples/image_demo2.py -examples/image_demo3.py -examples/image_demo_na.py -examples/image_interp.py -examples/image_masked.py -examples/image_origin.py -examples/integral_demo.py -examples/interactive.py -examples/interactive2.py -examples/interp_demo.py -examples/invert_axes.py -examples/keypress_demo.py -examples/lasso_demo.py -examples/layer_images.py -examples/legend_auto.py -examples/legend_demo.py -examples/legend_demo2.py -examples/legend_scatter.py -examples/line_collection.py -examples/line_collection2.py -examples/line_styles.py -examples/load_converter.py -examples/log_bar.py -examples/log_demo.py -examples/log_test.py -examples/logo.py -examples/major_minor_demo1.py -examples/major_minor_demo2.py -examples/masked_demo.py -examples/mathtext2_demo.py -examples/mathtext_demo.py -examples/matplotlib_icon.py -examples/matshow.py -examples/movie_demo.py -examples/mpl_with_glade.py -examples/mri_demo.py -examples/mri_with_eeg.py -examples/multi_image.py -examples/multiline.py -examples/multiple_figs_demo.py -examples/newscalarformatter_demo.py -examples/object_picker.py -examples/pcolor_demo.py -examples/pcolor_demo2.py -examples/pcolor_log.py -examples/pcolor_nonuniform.py -examples/pcolor_small.py -examples/pick_event_demo.py -examples/picker_demo.py -examples/pie_demo.py -examples/polar_bar.py -examples/polar_demo.py -examples/polar_legend.py -examples/polar_scatter.py -examples/poly_editor.py -examples/poormans_contour.py -examples/print_stdout.py -examples/printing_in_wx.py -examples/psd_demo.py -examples/pstest.py -examples/pylab_with_gtk.py -examples/pythonic_matplotlib.py -examples/quadmesh_demo.py -examples/quiver_demo.py -examples/scatter_custom_symbol.py -examples/scatter_demo.py -examples/scatter_demo2.py -examples/scatter_masked.py -examples/scatter_profile.py -examples/scatter_star_poly.py -examples/set_and_get.py -examples/shared_axis_demo.py -examples/simple3d.py -examples/simple3d_oo.py -examples/simple_plot.py -examples/specgram_demo.py -examples/spy_demos.py -examples/stem_plot.py -examples/stock_demo.py -examples/strip_chart_demo.py -examples/subplot_demo.py -examples/subplot_toolbar.py -examples/subplots_adjust.py -examples/system_monitor.py -examples/table_demo.py -examples/tex_demo.py -examples/text_handles.py -examples/text_rotation.py -examples/text_themes.py -examples/to_numeric.py -examples/toggle_images.py -examples/transoffset.py -examples/two_scales.py -examples/unicode_demo.py -examples/vertical_ticklabels.py -examples/vline_demo.py -examples/webapp_demo.py -examples/wxcursor_demo.py -examples/xcorr_demo.py -examples/zoom_window.py -examples/zorder_demo.py -examples/data/AAPL.dat -examples/data/INTC.dat -examples/data/ct.raw -examples/data/eeg.dat -examples/data/embedding_in_wx3.xrc -examples/data/intc.csv -examples/data/lena.jpg -examples/data/membrane.dat -examples/data/msft.csv -examples/data/s1045.ima -examples/units/__init__.py -examples/units/artist_tests.py -examples/units/bar_unit_demo.py -examples/units/basic_units.py -examples/units/date_converter.py -examples/units/date_support.py -examples/units/evans_test.py -examples/units/evans_test2.py -examples/units/radian_demo.py -examples/units/units_sample.py -examples/units/units_scatter.py -examples/widgets/README -examples/widgets/buttons.py -examples/widgets/check_buttons.py -examples/widgets/cursor.py -examples/widgets/multicursor.py -examples/widgets/radio_buttons.py -examples/widgets/rectangle_selector.py -examples/widgets/sliders.py -examples/widgets/span_selector.py -lib/pylab.py -lib/dateutil/__init__.py -lib/dateutil/easter.py -lib/dateutil/parser.py -lib/dateutil/relativedelta.py -lib/dateutil/rrule.py -lib/dateutil/tz.py -lib/matplotlib/.cvsignore -lib/matplotlib/__init__.py -lib/matplotlib/_cm.py -lib/matplotlib/_contour.py -lib/matplotlib/_image.py -lib/matplotlib/_mathtext_data.py -lib/matplotlib/_pylab_helpers.py -lib/matplotlib/_transforms.py -lib/matplotlib/afm.py -lib/matplotlib/agg.py -lib/matplotlib/art3d.py -lib/matplotlib/artist.py -lib/matplotlib/artist.py~ -lib/matplotlib/axes.py -lib/matplotlib/axes.py~ -lib/matplotlib/axes3d.py -lib/matplotlib/axis.py -lib/matplotlib/axis3d.py -lib/matplotlib/backend_bases.py -lib/matplotlib/cbook.py -lib/matplotlib/cm.py -lib/matplotlib/collections.py -lib/matplotlib/colorbar.py -lib/matplotlib/colors.py -lib/matplotlib/contour.py -lib/matplotlib/dates.py -lib/matplotlib/dviread.py -lib/matplotlib/figure.py -lib/matplotlib/finance.py -lib/matplotlib/font_manager.py -lib/matplotlib/image.py -lib/matplotlib/legend.py -lib/matplotlib/lines.py -lib/matplotlib/mathtext.py -lib/matplotlib/mathtext2.py -lib/matplotlib/mlab.py -lib/matplotlib/nxutils.py -lib/matplotlib/patches.py -lib/matplotlib/proj3d.py -lib/matplotlib/pylab.py -lib/matplotlib/pyparsing.py -lib/matplotlib/quiver.py -lib/matplotlib/table.py -lib/matplotlib/texmanager.py -lib/matplotlib/text.py -lib/matplotlib/ticker.py -lib/matplotlib/transforms.py -lib/matplotlib/units.py -lib/matplotlib/widgets.py -lib/matplotlib/windowing.py -lib/matplotlib/backends/.cvsignore -lib/matplotlib/backends/__init__.py -lib/matplotlib/backends/backend_agg.py -lib/matplotlib/backends/backend_agg2.py -lib/matplotlib/backends/backend_cairo.py -lib/matplotlib/backends/backend_cocoaagg.py -lib/matplotlib/backends/backend_emf.py -lib/matplotlib/backends/backend_fltkagg.py -lib/matplotlib/backends/backend_gd.py -lib/matplotlib/backends/backend_gdk.py -lib/matplotlib/backends/backend_gtk.py -lib/matplotlib/backends/backend_gtkagg.py -lib/matplotlib/backends/backend_gtkcairo.py -lib/matplotlib/backends/backend_paint.py -lib/matplotlib/backends/backend_pdf.py -lib/matplotlib/backends/backend_ps.py -lib/matplotlib/backends/backend_qt.py -lib/matplotlib/backends/backend_qt4.py -lib/matplotlib/backends/backend_qt4agg.py -lib/matplotlib/backends/backend_qtagg.py -lib/matplotlib/backends/backend_svg.py -lib/matplotlib/backends/backend_template.py -lib/matplotlib/backends/backend_tkagg.py -lib/matplotlib/backends/backend_wx.py -lib/matplotlib/backends/backend_wxagg.py -lib/matplotlib/backends/tkagg.py -lib/matplotlib/backends/Matplotlib.nib/classes.nib -lib/matplotlib/backends/Matplotlib.nib/info.nib -lib/matplotlib/backends/Matplotlib.nib/keyedobjects.nib -lib/matplotlib/enthought/__init__.py -lib/matplotlib/enthought/resource/__init__.py -lib/matplotlib/enthought/resource/resource_factory.py -lib/matplotlib/enthought/resource/resource_manager.py -lib/matplotlib/enthought/resource/resource_path.py -lib/matplotlib/enthought/resource/resource_reference.py -lib/matplotlib/enthought/traits/__init__.py -lib/matplotlib/enthought/traits/category.py -lib/matplotlib/enthought/traits/ctraits.c -lib/matplotlib/enthought/traits/has_traits.py -lib/matplotlib/enthought/traits/info_traits.py -lib/matplotlib/enthought/traits/standard.py -lib/matplotlib/enthought/traits/trait_base.py -lib/matplotlib/enthought/traits/trait_db.py -lib/matplotlib/enthought/traits/trait_errors.py -lib/matplotlib/enthought/traits/trait_handlers.py -lib/matplotlib/enthought/traits/trait_notifiers.py -lib/matplotlib/enthought/traits/trait_numeric.py -lib/matplotlib/enthought/traits/traits.py -lib/matplotlib/enthought/traits/ui/__init__.py -lib/matplotlib/enthought/traits/ui/editor.py -lib/matplotlib/enthought/traits/ui/editor_factory.py -lib/matplotlib/enthought/traits/ui/editors.py -lib/matplotlib/enthought/traits/ui/group.py -lib/matplotlib/enthought/traits/ui/handler.py -lib/matplotlib/enthought/traits/ui/help.py -lib/matplotlib/enthought/traits/ui/help_template.py -lib/matplotlib/enthought/traits/ui/helper.py -lib/matplotlib/enthought/traits/ui/include.py -lib/matplotlib/enthought/traits/ui/item.py -lib/matplotlib/enthought/traits/ui/menu.py -lib/matplotlib/enthought/traits/ui/toolkit.py -lib/matplotlib/enthought/traits/ui/tree_node.py -lib/matplotlib/enthought/traits/ui/ui.py -lib/matplotlib/enthought/traits/ui/ui_info.py -lib/matplotlib/enthought/traits/ui/ui_traits.py -lib/matplotlib/enthought/traits/ui/undo.py -lib/matplotlib/enthought/traits/ui/view.py -lib/matplotlib/enthought/traits/ui/view_element.py -lib/matplotlib/enthought/traits/ui/view_elements.py -lib/matplotlib/enthought/traits/ui/null/__init__.py -lib/matplotlib/enthought/traits/ui/null/color_trait.py -lib/matplotlib/enthought/traits/ui/null/font_trait.py -lib/matplotlib/enthought/traits/ui/null/rgb_color_trait.py -lib/matplotlib/enthought/traits/ui/null/rgba_color_trait.py -lib/matplotlib/enthought/traits/ui/null/toolkit.py -lib/matplotlib/enthought/util/__init__.py -lib/matplotlib/enthought/util/resource.py -lib/matplotlib/mpl-data/matplotlibrc -lib/matplotlib/mpl-data/fonts/afm/cmex10.afm -lib/matplotlib/mpl-data/fonts/afm/cmmi10.afm -lib/matplotlib/mpl-data/fonts/afm/cmr10.afm -lib/matplotlib/mpl-data/fonts/afm/cmsy10.afm -lib/matplotlib/mpl-data/fonts/afm/cmtt10.afm -lib/matplotlib/mpl-data/fonts/afm/pagd8a.afm -lib/matplotlib/mpl-data/fonts/afm/pagdo8a.afm -lib/matplotlib/mpl-data/fonts/afm/pagk8a.afm -lib/matplotlib/mpl-data/fonts/afm/pagko8a.afm -lib/matplotlib/mpl-data/fonts/afm/pbkd8a.afm -lib/matplotlib/mpl-data/fonts/afm/pbkdi8a.afm -lib/matplotlib/mpl-data/fonts/afm/pbkl8a.afm -lib/matplotlib/mpl-data/fonts/afm/pbkli8a.afm -lib/matplotlib/mpl-data/fonts/afm/pcrb8a.afm -lib/matplotlib/mpl-data/fonts/afm/pcrbo8a.afm -lib/matplotlib/mpl-data/fonts/afm/pcrr8a.afm -lib/matplotlib/mpl-data/fonts/afm/pcrro8a.afm -lib/matplotlib/mpl-data/fonts/afm/phvb8a.afm -lib/matplotlib/mpl-data/fonts/afm/phvb8an.afm -lib/matplotlib/mpl-data/fonts/afm/phvbo8a.afm -lib/matplotlib/mpl-data/fonts/afm/phvbo8an.afm -lib/matplotlib/mpl-data/fonts/afm/phvl8a.afm -lib/matplotlib/mpl-data/fonts/afm/phvlo8a.afm -lib/matplotlib/mpl-data/fonts/afm/phvr8a.afm -lib/matplotlib/mpl-data/fonts/afm/phvr8an.afm -lib/matplotlib/mpl-data/fonts/afm/phvro8a.afm -lib/matplotlib/mpl-data/fonts/afm/phvro8an.afm -lib/matplotlib/mpl-data/fonts/afm/pncb8a.afm -lib/matplotlib/mpl-data/fonts/afm/pncbi8a.afm -lib/matplotlib/mpl-data/fonts/afm/pncr8a.afm -lib/matplotlib/mpl-data/fonts/afm/pncri8a.afm -lib/matplotlib/mpl-data/fonts/afm/pplb8a.afm -lib/matplotlib/mpl-data/fonts/afm/pplbi8a.afm -lib/matplotlib/mpl-data/fonts/afm/pplr8a.afm -lib/matplotlib/mpl-data/fonts/afm/pplri8a.afm -lib/matplotlib/mpl-data/fonts/afm/psyr.afm -lib/matplotlib/mpl-data/fonts/afm/ptmb8a.afm -lib/matplotlib/mpl-data/fonts/afm/ptmbi8a.afm -lib/matplotlib/mpl-data/fonts/afm/ptmr8a.afm -lib/matplotlib/mpl-data/fonts/afm/ptmri8a.afm -lib/matplotlib/mpl-data/fonts/afm/putb8a.afm -lib/matplotlib/mpl-data/fonts/afm/putbi8a.afm -lib/matplotlib/mpl-data/fonts/afm/putr8a.afm -lib/matplotlib/mpl-data/fonts/afm/putri8a.afm -lib/matplotlib/mpl-data/fonts/afm/pzcmi8a.afm -lib/matplotlib/mpl-data/fonts/afm/pzdr.afm -lib/matplotlib/mpl-data/fonts/pdfcorefonts/Courier-Bold.afm -lib/matplotlib/mpl-data/fonts/pdfcorefonts/Courier-BoldOblique.afm -lib/matplotlib/mpl-data/fonts/pdfcorefonts/Courier-Oblique.afm -lib/matplotlib/mpl-data/fonts/pdfcorefonts/Courier.afm -lib/matplotlib/mpl-data/fonts/pdfcorefonts/Helvetica-Bold.afm -lib/matplotlib/mpl-data/fonts/pdfcorefonts/Helvetica-BoldOblique.afm -lib/matplotlib/mpl-data/fonts/pdfcorefonts/Helvetica-Oblique.afm -lib/matplotlib/mpl-data/fonts/pdfcorefonts/Helvetica.afm -lib/matplotlib/mpl-data/fonts/pdfcorefonts/Symbol.afm -lib/matplotlib/mpl-data/fonts/pdfcorefonts/Times-Bold.afm -lib/matplotlib/mpl-data/fonts/pdfcorefonts/Times-BoldItalic.afm -lib/matplotlib/mpl-data/fonts/pdfcorefonts/Times-Italic.afm -lib/matplotlib/mpl-data/fonts/pdfcorefonts/Times-Roman.afm -lib/matplotlib/mpl-data/fonts/pdfcorefonts/ZapfDingbats.afm -lib/matplotlib/mpl-data/fonts/pdfcorefonts/readme.txt -lib/matplotlib/mpl-data/fonts/ttf/COPYRIGHT.TXT -lib/matplotlib/mpl-data/fonts/ttf/README.TXT -lib/matplotlib/mpl-data/fonts/ttf/RELEASENOTES.TXT -lib/matplotlib/mpl-data/fonts/ttf/Vera.ttf -lib/matplotlib/mpl-data/fonts/ttf/VeraBI.ttf -lib/matplotlib/mpl-data/fonts/ttf/VeraBd.ttf -lib/matplotlib/mpl-data/fonts/ttf/VeraIt.ttf -lib/matplotlib/mpl-data/fonts/ttf/VeraMoBI.ttf -lib/matplotlib/mpl-data/fonts/ttf/VeraMoBd.ttf -lib/matplotlib/mpl-data/fonts/ttf/VeraMoIt.ttf -lib/matplotlib/mpl-data/fonts/ttf/VeraMono.ttf -lib/matplotlib/mpl-data/fonts/ttf/VeraSe.ttf -lib/matplotlib/mpl-data/fonts/ttf/VeraSeBd.ttf -lib/matplotlib/mpl-data/fonts/ttf/cmex10.ttf -lib/matplotlib/mpl-data/fonts/ttf/cmmi10.ttf -lib/matplotlib/mpl-data/fonts/ttf/cmr10.ttf -lib/matplotlib/mpl-data/fonts/ttf/cmsy10.ttf -lib/matplotlib/mpl-data/fonts/ttf/cmtt10.ttf -lib/matplotlib/mpl-data/fonts/ttf/local.conf -lib/matplotlib/mpl-data/images/back.png -lib/matplotlib/mpl-data/images/back.ppm -lib/matplotlib/mpl-data/images/back.svg -lib/matplotlib/mpl-data/images/back.xpm -lib/matplotlib/mpl-data/images/filesave.png -lib/matplotlib/mpl-data/images/filesave.ppm -lib/matplotlib/mpl-data/images/filesave.svg -lib/matplotlib/mpl-data/images/filesave.xpm -lib/matplotlib/mpl-data/images/forward.png -lib/matplotlib/mpl-data/images/forward.ppm -lib/matplotlib/mpl-data/images/forward.svg -lib/matplotlib/mpl-data/images/forward.xpm -lib/matplotlib/mpl-data/images/hand.png -lib/matplotlib/mpl-data/images/hand.ppm -lib/matplotlib/mpl-data/images/hand.svg -lib/matplotlib/mpl-data/images/hand.xpm -lib/matplotlib/mpl-data/images/home.png -lib/matplotlib/mpl-data/images/home.ppm -lib/matplotlib/mpl-data/images/home.svg -lib/matplotlib/mpl-data/images/home.xpm -lib/matplotlib/mpl-data/images/matplotlib.png -lib/matplotlib/mpl-data/images/matplotlib.svg -lib/matplotlib/mpl-data/images/move.png -lib/matplotlib/mpl-data/images/move.ppm -lib/matplotlib/mpl-data/images/move.svg -lib/matplotlib/mpl-data/images/move.xpm -lib/matplotlib/mpl-data/images/stock_close.ppm -lib/matplotlib/mpl-data/images/stock_close.xpm -lib/matplotlib/mpl-data/images/stock_down.ppm -lib/matplotlib/mpl-data/images/stock_down.xpm -lib/matplotlib/mpl-data/images/stock_left.ppm -lib/matplotlib/mpl-data/images/stock_left.xpm -lib/matplotlib/mpl-data/images/stock_refresh.ppm -lib/matplotlib/mpl-data/images/stock_refresh.xpm -lib/matplotlib/mpl-data/images/stock_right.ppm -lib/matplotlib/mpl-data/images/stock_right.xpm -lib/matplotlib/mpl-data/images/stock_save_as.ppm -lib/matplotlib/mpl-data/images/stock_save_as.xpm -lib/matplotlib/mpl-data/images/stock_up.ppm -lib/matplotlib/mpl-data/images/stock_up.xpm -lib/matplotlib/mpl-data/images/stock_zoom-in.ppm -lib/matplotlib/mpl-data/images/stock_zoom-in.xpm -lib/matplotlib/mpl-data/images/stock_zoom-out.ppm -lib/matplotlib/mpl-data/images/stock_zoom-out.xpm -lib/matplotlib/mpl-data/images/subplots.png -lib/matplotlib/mpl-data/images/subplots.ppm -lib/matplotlib/mpl-data/images/subplots.xpm -lib/matplotlib/mpl-data/images/zoom_to_rect.png -lib/matplotlib/mpl-data/images/zoom_to_rect.ppm -lib/matplotlib/mpl-data/images/zoom_to_rect.svg -lib/matplotlib/mpl-data/images/zoom_to_rect.xpm -lib/matplotlib/numerix/.cvsignore -lib/matplotlib/numerix/__init__.py -lib/matplotlib/numerix/_na_imports.py -lib/matplotlib/numerix/_nc_imports.py -lib/matplotlib/numerix/_sp_imports.py -lib/matplotlib/numerix/fft/__init__.py -lib/matplotlib/numerix/linear_algebra/__init__.py -lib/matplotlib/numerix/ma/__init__.py -lib/matplotlib/numerix/mlab/.cvsignore -lib/matplotlib/numerix/mlab/__init__.py -lib/matplotlib/numerix/random_array/__init__.py -lib/matplotlib/toolkits/__init__.py -lib/pytz/__init__.py -lib/pytz/reference.py -lib/pytz/test_tzinfo.py -lib/pytz/tzinfo.py -lib/pytz/zoneinfo/CET.py -lib/pytz/zoneinfo/CST6CDT.py -lib/pytz/zoneinfo/Cuba.py -lib/pytz/zoneinfo/EET.py -lib/pytz/zoneinfo/EST.py -lib/pytz/zoneinfo/EST5EDT.py -lib/pytz/zoneinfo/Egypt.py -lib/pytz/zoneinfo/Eire.py -lib/pytz/zoneinfo/GB.py -lib/pytz/zoneinfo/GB_minus_Eire.py -lib/pytz/zoneinfo/GMT.py -lib/pytz/zoneinfo/GMT0.py -lib/pytz/zoneinfo/GMT_minus_0.py -lib/pytz/zoneinfo/GMT_plus_0.py -lib/pytz/zoneinfo/Greenwich.py -lib/pytz/zoneinfo/HST.py -lib/pytz/zoneinfo/Hongkong.py -lib/pytz/zoneinfo/Iceland.py -lib/pytz/zoneinfo/Iran.py -lib/pytz/zoneinfo/Israel.py -lib/pytz/zoneinfo/Jamaica.py -lib/pytz/zoneinfo/Japan.py -lib/pytz/zoneinfo/Kwajalein.py -lib/pytz/zoneinfo/Libya.py -lib/pytz/zoneinfo/MET.py -lib/pytz/zoneinfo/MST.py -lib/pytz/zoneinfo/MST7MDT.py -lib/pytz/zoneinfo/NZ.py -lib/pytz/zoneinfo/NZ_minus_CHAT.py -lib/pytz/zoneinfo/Navajo.py -lib/pytz/zoneinfo/PRC.py -lib/pytz/zoneinfo/PST8PDT.py -lib/pytz/zoneinfo/Poland.py -lib/pytz/zoneinfo/Portugal.py -lib/pytz/zoneinfo/ROC.py -lib/pytz/zoneinfo/ROK.py -lib/pytz/zoneinfo/Singapore.py -lib/pytz/zoneinfo/Turkey.py -lib/pytz/zoneinfo/UCT.py -lib/pytz/zoneinfo/UTC.py -lib/pytz/zoneinfo/Universal.py -lib/pytz/zoneinfo/WET.py -lib/pytz/zoneinfo/W_minus_SU.py -lib/pytz/zoneinfo/Zulu.py -lib/pytz/zoneinfo/__init__.py -lib/pytz/zoneinfo/posixrules.py -lib/pytz/zoneinfo/Africa/Abidjan.py -lib/pytz/zoneinfo/Africa/Accra.py -lib/pytz/zoneinfo/Africa/Addis_Ababa.py -lib/pytz/zoneinfo/Africa/Algiers.py -lib/pytz/zoneinfo/Africa/Asmera.py -lib/pytz/zoneinfo/Africa/Bamako.py -lib/pytz/zoneinfo/Africa/Bangui.py -lib/pytz/zoneinfo/Africa/Banjul.py -lib/pytz/zoneinfo/Africa/Bissau.py -lib/pytz/zoneinfo/Africa/Blantyre.py -lib/pytz/zoneinfo/Africa/Brazzaville.py -lib/pytz/zoneinfo/Africa/Bujumbura.py -lib/pytz/zoneinfo/Africa/Cairo.py -lib/pytz/zoneinfo/Africa/Casablanca.py -lib/pytz/zoneinfo/Africa/Ceuta.py -lib/pytz/zoneinfo/Africa/Conakry.py -lib/pytz/zoneinfo/Africa/Dakar.py -lib/pytz/zoneinfo/Africa/Dar_es_Salaam.py -lib/pytz/zoneinfo/Africa/Djibouti.py -lib/pytz/zoneinfo/Africa/Douala.py -lib/pytz/zoneinfo/Africa/El_Aaiun.py -lib/pytz/zoneinfo/Africa/Freetown.py -lib/pytz/zoneinfo/Africa/Gaborone.py -lib/pytz/zoneinfo/Africa/Harare.py -lib/pytz/zoneinfo/Africa/Johannesburg.py -lib/pytz/zoneinfo/Africa/Kampala.py -lib/pytz/zoneinfo/Africa/Khartoum.py -lib/pytz/zoneinfo/Africa/Kigali.py -lib/pytz/zoneinfo/Africa/Kinshasa.py -lib/pytz/zoneinfo/Africa/Lagos.py -lib/pytz/zoneinfo/Africa/Libreville.py -lib/pytz/zoneinfo/Africa/Lome.py -lib/pytz/zoneinfo/Africa/Luanda.py -lib/pytz/zoneinfo/Africa/Lubumbashi.py -lib/pytz/zoneinfo/Africa/Lusaka.py -lib/pytz/zoneinfo/Africa/Malabo.py -lib/pytz/zoneinfo/Africa/Maputo.py -lib/pytz/zoneinfo/Africa/Maseru.py -lib/pytz/zoneinfo/Africa/Mbabane.py -lib/pytz/zoneinfo/Africa/Mogadishu.py -lib/pytz/zoneinfo/Africa/Monrovia.py -lib/pytz/zoneinfo/Africa/Nairobi.py -lib/pytz/zoneinfo/Africa/Ndjamena.py -lib/pytz/zoneinfo/Africa/Niamey.py -lib/pytz/zoneinfo/Africa/Nouakchott.py -lib/pytz/zoneinfo/Africa/Ouagadougou.py -lib/pytz/zoneinfo/Africa/Porto_minus_Novo.py -lib/pytz/zoneinfo/Africa/Sao_Tome.py -lib/pytz/zoneinfo/Africa/Timbuktu.py -lib/pytz/zoneinfo/Africa/Tripoli.py -lib/pytz/zoneinfo/Africa/Tunis.py -lib/pytz/zoneinfo/Africa/Windhoek.py -lib/pytz/zoneinfo/Africa/__init__.py -lib/pytz/zoneinfo/America/Adak.py -lib/pytz/zoneinfo/America/Anchorage.py -lib/pytz/zoneinfo/America/Anguilla.py -lib/pytz/zoneinfo/America/Antigua.py -lib/pytz/zoneinfo/America/Araguaina.py -lib/pytz/zoneinfo/America/Aruba.py -lib/pytz/zoneinfo/America/Asuncion.py -lib/pytz/zoneinfo/America/Atka.py -lib/pytz/zoneinfo/America/Bahia.py -lib/pytz/zoneinfo/America/Barbados.py -lib/pytz/zoneinfo/America/Belem.py -lib/pytz/zoneinfo/America/Belize.py -lib/pytz/zoneinfo/America/Boa_Vista.py -lib/pytz/zoneinfo/America/Bogota.py -lib/pytz/zoneinfo/America/Boise.py -lib/pytz/zoneinfo/America/Buenos_Aires.py -lib/pytz/zoneinfo/America/Cambridge_Bay.py -lib/pytz/zoneinfo/America/Campo_Grande.py -lib/pytz/zoneinfo/America/Cancun.py -lib/pytz/zoneinfo/America/Caracas.py -lib/pytz/zoneinfo/America/Catamarca.py -lib/pytz/zoneinfo/America/Cayenne.py -lib/pytz/zoneinfo/America/Cayman.py -lib/pytz/zoneinfo/America/Chicago.py -lib/pytz/zoneinfo/America/Chihuahua.py -lib/pytz/zoneinfo/America/Cordoba.py -lib/pytz/zoneinfo/America/Costa_Rica.py -lib/pytz/zoneinfo/America/Cuiaba.py -lib/pytz/zoneinfo/America/Curacao.py -lib/pytz/zoneinfo/America/Danmarkshavn.py -lib/pytz/zoneinfo/America/Dawson.py -lib/pytz/zoneinfo/America/Dawson_Creek.py -lib/pytz/zoneinfo/America/Denver.py -lib/pytz/zoneinfo/America/Detroit.py -lib/pytz/zoneinfo/America/Dominica.py -lib/pytz/zoneinfo/America/Edmonton.py -lib/pytz/zoneinfo/America/Eirunepe.py -lib/pytz/zoneinfo/America/El_Salvador.py -lib/pytz/zoneinfo/America/Ensenada.py -lib/pytz/zoneinfo/America/Fort_Wayne.py -lib/pytz/zoneinfo/America/Fortaleza.py -lib/pytz/zoneinfo/America/Glace_Bay.py -lib/pytz/zoneinfo/America/Godthab.py -lib/pytz/zoneinfo/America/Goose_Bay.py -lib/pytz/zoneinfo/America/Grand_Turk.py -lib/pytz/zoneinfo/America/Grenada.py -lib/pytz/zoneinfo/America/Guadeloupe.py -lib/pytz/zoneinfo/America/Guatemala.py -lib/pytz/zoneinfo/America/Guayaquil.py -lib/pytz/zoneinfo/America/Guyana.py -lib/pytz/zoneinfo/America/Halifax.py -lib/pytz/zoneinfo/America/Havana.py -lib/pytz/zoneinfo/America/Hermosillo.py -lib/pytz/zoneinfo/America/Indianapolis.py -lib/pytz/zoneinfo/America/Inuvik.py -lib/pytz/zoneinfo/America/Iqaluit.py -lib/pytz/zoneinfo/America/Jamaica.py -lib/pytz/zoneinfo/America/Jujuy.py -lib/pytz/zoneinfo/America/Juneau.py -lib/pytz/zoneinfo/America/Knox_IN.py -lib/pytz/zoneinfo/America/La_Paz.py -lib/pytz/zoneinfo/America/Lima.py -lib/pytz/zoneinfo/America/Los_Angeles.py -lib/pytz/zoneinfo/America/Louisville.py -lib/pytz/zoneinfo/America/Maceio.py -lib/pytz/zoneinfo/America/Managua.py -lib/pytz/zoneinfo/America/Manaus.py -lib/pytz/zoneinfo/America/Martinique.py -lib/pytz/zoneinfo/America/Mazatlan.py -lib/pytz/zoneinfo/America/Mendoza.py -lib/pytz/zoneinfo/America/Menominee.py -lib/pytz/zoneinfo/America/Merida.py -lib/pytz/zoneinfo/America/Mexico_City.py -lib/pytz/zoneinfo/America/Miquelon.py -lib/pytz/zoneinfo/America/Monterrey.py -lib/pytz/zoneinfo/America/Montevideo.py -lib/pytz/zoneinfo/America/Montreal.py -lib/pytz/zoneinfo/America/Montserrat.py -lib/pytz/zoneinfo/America/Nassau.py -lib/pytz/zoneinfo/America/New_York.py -lib/pytz/zoneinfo/America/Nipigon.py -lib/pytz/zoneinfo/America/Nome.py -lib/pytz/zoneinfo/America/Noronha.py -lib/pytz/zoneinfo/America/Panama.py -lib/pytz/zoneinfo/America/Pangnirtung.py -lib/pytz/zoneinfo/America/Paramaribo.py -lib/pytz/zoneinfo/America/Phoenix.py -lib/pytz/zoneinfo/America/Port_minus_au_minus_Prince.py -lib/pytz/zoneinfo/America/Port_of_Spain.py -lib/pytz/zoneinfo/America/Porto_Acre.py -lib/pytz/zoneinfo/America/Porto_Velho.py -lib/pytz/zoneinfo/America/Puerto_Rico.py -lib/pytz/zoneinfo/America/Rainy_River.py -lib/pytz/zoneinfo/America/Rankin_Inlet.py -lib/pytz/zoneinfo/America/Recife.py -lib/pytz/zoneinfo/America/Regina.py -lib/pytz/zoneinfo/America/Rio_Branco.py -lib/pytz/zoneinfo/America/Rosario.py -lib/pytz/zoneinfo/America/Santiago.py -lib/pytz/zoneinfo/America/Santo_Domingo.py -lib/pytz/zoneinfo/America/Sao_Paulo.py -lib/pytz/zoneinfo/America/Scoresbysund.py -lib/pytz/zoneinfo/America/Shiprock.py -lib/pytz/zoneinfo/America/St_Johns.py -lib/pytz/zoneinfo/America/St_Kitts.py -lib/pytz/zoneinfo/America/St_Lucia.py -lib/pytz/zoneinfo/America/St_Thomas.py -lib/pytz/zoneinfo/America/St_Vincent.py -lib/pytz/zoneinfo/America/Swift_Current.py -lib/pytz/zoneinfo/America/Tegucigalpa.py -lib/pytz/zoneinfo/America/Thule.py -lib/pytz/zoneinfo/America/Thunder_Bay.py -lib/pytz/zoneinfo/America/Tijuana.py -lib/pytz/zoneinfo/America/Toronto.py -lib/pytz/zoneinfo/America/Tortola.py -lib/pytz/zoneinfo/America/Vancouver.py -lib/pytz/zoneinfo/America/Virgin.py -lib/pytz/zoneinfo/America/Whitehorse.py -lib/pytz/zoneinfo/America/Winnipeg.py -lib/pytz/zoneinfo/America/Yakutat.py -lib/pytz/zoneinfo/America/Yellowknife.py -lib/pytz/zoneinfo/America/__init__.py -lib/pytz/zoneinfo/America/Argentina/Buenos_Aires.py -lib/pytz/zoneinfo/America/Argentina/Catamarca.py -lib/pytz/zoneinfo/America/Argentina/ComodRivadavia.py -lib/pytz/zoneinfo/America/Argentina/Cordoba.py -lib/pytz/zoneinfo/America/Argentina/Jujuy.py -lib/pytz/zoneinfo/America/Argentina/La_Rioja.py -lib/pytz/zoneinfo/America/Argentina/Mendoza.py -lib/pytz/zoneinfo/America/Argentina/Rio_Gallegos.py -lib/pytz/zoneinfo/America/Argentina/San_Juan.py -lib/pytz/zoneinfo/America/Argentina/Tucuman.py -lib/pytz/zoneinfo/America/Argentina/Ushuaia.py -lib/pytz/zoneinfo/America/Argentina/__init__.py -lib/pytz/zoneinfo/America/Indiana/Indianapolis.py -lib/pytz/zoneinfo/America/Indiana/Knox.py -lib/pytz/zoneinfo/America/Indiana/Marengo.py -lib/pytz/zoneinfo/America/Indiana/Vevay.py -lib/pytz/zoneinfo/America/Indiana/__init__.py -lib/pytz/zoneinfo/America/Kentucky/Louisville.py -lib/pytz/zoneinfo/America/Kentucky/Monticello.py -lib/pytz/zoneinfo/America/Kentucky/__init__.py -lib/pytz/zoneinfo/America/North_Dakota/Center.py -lib/pytz/zoneinfo/America/North_Dakota/__init__.py -lib/pytz/zoneinfo/Antarctica/Casey.py -lib/pytz/zoneinfo/Antarctica/Davis.py -lib/pytz/zoneinfo/Antarctica/DumontDUrville.py -lib/pytz/zoneinfo/Antarctica/Mawson.py -lib/pytz/zoneinfo/Antarctica/McMurdo.py -lib/pytz/zoneinfo/Antarctica/Palmer.py -lib/pytz/zoneinfo/Antarctica/Rothera.py -lib/pytz/zoneinfo/Antarctica/South_Pole.py -lib/pytz/zoneinfo/Antarctica/Syowa.py -lib/pytz/zoneinfo/Antarctica/Vostok.py -lib/pytz/zoneinfo/Antarctica/__init__.py -lib/pytz/zoneinfo/Arctic/Longyearbyen.py -lib/pytz/zoneinfo/Arctic/__init__.py -lib/pytz/zoneinfo/Asia/Aden.py -lib/pytz/zoneinfo/Asia/Almaty.py -lib/pytz/zoneinfo/Asia/Amman.py -lib/pytz/zoneinfo/Asia/Anadyr.py -lib/pytz/zoneinfo/Asia/Aqtau.py -lib/pytz/zoneinfo/Asia/Aqtobe.py -lib/pytz/zoneinfo/Asia/Ashgabat.py -lib/pytz/zoneinfo/Asia/Ashkhabad.py -lib/pytz/zoneinfo/Asia/Baghdad.py -lib/pytz/zoneinfo/Asia/Bahrain.py -lib/pytz/zoneinfo/Asia/Baku.py -lib/pytz/zoneinfo/Asia/Bangkok.py -lib/pytz/zoneinfo/Asia/Beirut.py -lib/pytz/zoneinfo/Asia/Bishkek.py -lib/pytz/zoneinfo/Asia/Brunei.py -lib/pytz/zoneinfo/Asia/Calcutta.py -lib/pytz/zoneinfo/Asia/Choibalsan.py -lib/pytz/zoneinfo/Asia/Chongqing.py -lib/pytz/zoneinfo/Asia/Chungking.py -lib/pytz/zoneinfo/Asia/Colombo.py -lib/pytz/zoneinfo/Asia/Dacca.py -lib/pytz/zoneinfo/Asia/Damascus.py -lib/pytz/zoneinfo/Asia/Dhaka.py -lib/pytz/zoneinfo/Asia/Dili.py -lib/pytz/zoneinfo/Asia/Dubai.py -lib/pytz/zoneinfo/Asia/Dushanbe.py -lib/pytz/zoneinfo/Asia/Gaza.py -lib/pytz/zoneinfo/Asia/Harbin.py -lib/pytz/zoneinfo/Asia/Hong_Kong.py -lib/pytz/zoneinfo/Asia/Hovd.py -lib/pytz/zoneinfo/Asia/Irkutsk.py -lib/pytz/zoneinfo/Asia/Istanbul.py -lib/pytz/zoneinfo/Asia/Jakarta.py -lib/pytz/zoneinfo/Asia/Jayapura.py -lib/pytz/zoneinfo/Asia/Jerusalem.py -lib/pytz/zoneinfo/Asia/Kabul.py -lib/pytz/zoneinfo/Asia/Kamchatka.py -lib/pytz/zoneinfo/Asia/Karachi.py -lib/pytz/zoneinfo/Asia/Kashgar.py -lib/pytz/zoneinfo/Asia/Katmandu.py -lib/pytz/zoneinfo/Asia/Krasnoyarsk.py -lib/pytz/zoneinfo/Asia/Kuala_Lumpur.py -lib/pytz/zoneinfo/Asia/Kuching.py -lib/pytz/zoneinfo/Asia/Kuwait.py -lib/pytz/zoneinfo/Asia/Macao.py -lib/pytz/zoneinfo/Asia/Macau.py -lib/pytz/zoneinfo/Asia/Magadan.py -lib/pytz/zoneinfo/Asia/Makassar.py -lib/pytz/zoneinfo/Asia/Manila.py -lib/pytz/zoneinfo/Asia/Muscat.py -lib/pytz/zoneinfo/Asia/Nicosia.py -lib/pytz/zoneinfo/Asia/Novosibirsk.py -lib/pytz/zoneinfo/Asia/Omsk.py -lib/pytz/zoneinfo/Asia/Oral.py -lib/pytz/zoneinfo/Asia/Phnom_Penh.py -lib/pytz/zoneinfo/Asia/Pontianak.py -lib/pytz/zoneinfo/Asia/Pyongyang.py -lib/pytz/zoneinfo/Asia/Qatar.py -lib/pytz/zoneinfo/Asia/Qyzylorda.py -lib/pytz/zoneinfo/Asia/Rangoon.py -lib/pytz/zoneinfo/Asia/Riyadh.py -lib/pytz/zoneinfo/Asia/Saigon.py -lib/pytz/zoneinfo/Asia/Sakhalin.py -lib/pytz/zoneinfo/Asia/Samarkand.py -lib/pytz/zoneinfo/Asia/Seoul.py -lib/pytz/zoneinfo/Asia/Shanghai.py -lib/pytz/zoneinfo/Asia/Singapore.py -lib/pytz/zoneinfo/Asia/Taipei.py -lib/pytz/zoneinfo/Asia/Tashkent.py -lib/pytz/zoneinfo/Asia/Tbilisi.py -lib/pytz/zoneinfo/Asia/Tehran.py -lib/pytz/zoneinfo/Asia/Tel_Aviv.py -lib/pytz/zoneinfo/Asia/Thimbu.py -lib/pytz/zoneinfo/Asia/Thimphu.py -lib/pytz/zoneinfo/Asia/Tokyo.py -lib/pytz/zoneinfo/Asia/Ujung_Pandang.py -lib/pytz/zoneinfo/Asia/Ulaanbaatar.py -lib/pytz/zoneinfo/Asia/Ulan_Bator.py -lib/pytz/zoneinfo/Asia/Urumqi.py -lib/pytz/zoneinfo/Asia/Vientiane.py -lib/pytz/zoneinfo/Asia/Vladivostok.py -lib/pytz/zoneinfo/Asia/Yakutsk.py -lib/pytz/zoneinfo/Asia/Yekaterinburg.py -lib/pytz/zoneinfo/Asia/Yerevan.py -lib/pytz/zoneinfo/Asia/__init__.py -lib/pytz/zoneinfo/Atlantic/Azores.py -lib/pytz/zoneinfo/Atlantic/Bermuda.py -lib/pytz/zoneinfo/Atlantic/Canary.py -lib/pytz/zoneinfo/Atlantic/Cape_Verde.py -lib/pytz/zoneinfo/Atlantic/Faeroe.py -lib/pytz/zoneinfo/Atlantic/Jan_Mayen.py -lib/pytz/zoneinfo/Atlantic/Madeira.py -lib/pytz/zoneinfo/Atlantic/Reykjavik.py -lib/pytz/zoneinfo/Atlantic/South_Georgia.py -lib/pytz/zoneinfo/Atlantic/St_Helena.py -lib/pytz/zoneinfo/Atlantic/Stanley.py -lib/pytz/zoneinfo/Atlantic/__init__.py -lib/pytz/zoneinfo/Australia/ACT.py -lib/pytz/zoneinfo/Australia/Adelaide.py -lib/pytz/zoneinfo/Australia/Brisbane.py -lib/pytz/zoneinfo/Australia/Broken_Hill.py -lib/pytz/zoneinfo/Australia/Canberra.py -lib/pytz/zoneinfo/Australia/Darwin.py -lib/pytz/zoneinfo/Australia/Hobart.py -lib/pytz/zoneinfo/Australia/LHI.py -lib/pytz/zoneinfo/Australia/Lindeman.py -lib/pytz/zoneinfo/Australia/Lord_Howe.py -lib/pytz/zoneinfo/Australia/Melbourne.py -lib/pytz/zoneinfo/Australia/NSW.py -lib/pytz/zoneinfo/Australia/North.py -lib/pytz/zoneinfo/Australia/Perth.py -lib/pytz/zoneinfo/Australia/Queensland.py -lib/pytz/zoneinfo/Australia/South.py -lib/pytz/zoneinfo/Australia/Sydney.py -lib/pytz/zoneinfo/Australia/Tasmania.py -lib/pytz/zoneinfo/Australia/Victoria.py -lib/pytz/zoneinfo/Australia/West.py -lib/pytz/zoneinfo/Australia/Yancowinna.py -lib/pytz/zoneinfo/Australia/__init__.py -lib/pytz/zoneinfo/Brazil/Acre.py -lib/pytz/zoneinfo/Brazil/DeNoronha.py -lib/pytz/zoneinfo/Brazil/East.py -lib/pytz/zoneinfo/Brazil/West.py -lib/pytz/zoneinfo/Brazil/__init__.py -lib/pytz/zoneinfo/Canada/Atlantic.py -lib/pytz/zoneinfo/Canada/Central.py -lib/pytz/zoneinfo/Canada/East_minus_Saskatchewan.py -lib/pytz/zoneinfo/Canada/Eastern.py -lib/pytz/zoneinfo/Canada/Mountain.py -lib/pytz/zoneinfo/Canada/Newfoundland.py -lib/pytz/zoneinfo/Canada/Pacific.py -lib/pytz/zoneinfo/Canada/Saskatchewan.py -lib/pytz/zoneinfo/Canada/Yukon.py -lib/pytz/zoneinfo/Canada/__init__.py -lib/pytz/zoneinfo/Chile/Continental.py -lib/pytz/zoneinfo/Chile/EasterIsland.py -lib/pytz/zoneinfo/Chile/__init__.py -lib/pytz/zoneinfo/Etc/GMT.py -lib/pytz/zoneinfo/Etc/GMT0.py -lib/pytz/zoneinfo/Etc/GMT_minus_0.py -lib/pytz/zoneinfo/Etc/GMT_minus_1.py -lib/pytz/zoneinfo/Etc/GMT_minus_10.py -lib/pytz/zoneinfo/Etc/GMT_minus_11.py -lib/pytz/zoneinfo/Etc/GMT_minus_12.py -lib/pytz/zoneinfo/Etc/GMT_minus_13.py -lib/pytz/zoneinfo/Etc/GMT_minus_14.py -lib/pytz/zoneinfo/Etc/GMT_minus_2.py -lib/pytz/zoneinfo/Etc/GMT_minus_3.py -lib/pytz/zoneinfo/Etc/GMT_minus_4.py -lib/pytz/zoneinfo/Etc/GMT_minus_5.py -lib/pytz/zoneinfo/Etc/GMT_minus_6.py -lib/pytz/zoneinfo/Etc/GMT_minus_7.py -lib/pytz/zoneinfo/Etc/GMT_minus_8.py -lib/pytz/zoneinfo/Etc/GMT_minus_9.py -lib/pytz/zoneinfo/Etc/GMT_plus_0.py -lib/pytz/zoneinfo/Etc/GMT_plus_1.py -lib/pytz/zoneinfo/Etc/GMT_plus_10.py -lib/pytz/zoneinfo/Etc/GMT_plus_11.py -lib/pytz/zoneinfo/Etc/GMT_plus_12.py -lib/pytz/zoneinfo/Etc/GMT_plus_2.py -lib/pytz/zoneinfo/Etc/GMT_plus_3.py -lib/pytz/zoneinfo/Etc/GMT_plus_4.py -lib/pytz/zoneinfo/Etc/GMT_plus_5.py -lib/pytz/zoneinfo/Etc/GMT_plus_6.py -lib/pytz/zoneinfo/Etc/GMT_plus_7.py -lib/pytz/zoneinfo/Etc/GMT_plus_8.py -lib/pytz/zoneinfo/Etc/GMT_plus_9.py -lib/pytz/zoneinfo/Etc/Greenwich.py -lib/pytz/zoneinfo/Etc/UCT.py -lib/pytz/zoneinfo/Etc/UTC.py -lib/pytz/zoneinfo/Etc/Universal.py -lib/pytz/zoneinfo/Etc/Zulu.py -lib/pytz/zoneinfo/Etc/__init__.py -lib/pytz/zoneinfo/Europe/Amsterdam.py -lib/pytz/zoneinfo/Europe/Andorra.py -lib/pytz/zoneinfo/Europe/Athens.py -lib/pytz/zoneinfo/Europe/Belfast.py -lib/pytz/zoneinfo/Europe/Belgrade.py -lib/pytz/zoneinfo/Europe/Berlin.py -lib/pytz/zoneinfo/Europe/Bratislava.py -lib/pytz/zoneinfo/Europe/Brussels.py -lib/pytz/zoneinfo/Europe/Bucharest.py -lib/pytz/zoneinfo/Europe/Budapest.py -lib/pytz/zoneinfo/Europe/Chisinau.py -lib/pytz/zoneinfo/Europe/Copenhagen.py -lib/pytz/zoneinfo/Europe/Dublin.py -lib/pytz/zoneinfo/Europe/Gibraltar.py -lib/pytz/zoneinfo/Europe/Helsinki.py -lib/pytz/zoneinfo/Europe/Istanbul.py -lib/pytz/zoneinfo/Europe/Kaliningrad.py -lib/pytz/zoneinfo/Europe/Kiev.py -lib/pytz/zoneinfo/Europe/Lisbon.py -lib/pytz/zoneinfo/Europe/Ljubljana.py -lib/pytz/zoneinfo/Europe/London.py -lib/pytz/zoneinfo/Europe/Luxembourg.py -lib/pytz/zoneinfo/Europe/Madrid.py -lib/pytz/zoneinfo/Europe/Malta.py -lib/pytz/zoneinfo/Europe/Mariehamn.py -lib/pytz/zoneinfo/Europe/Minsk.py -lib/pytz/zoneinfo/Europe/Monaco.py -lib/pytz/zoneinfo/Europe/Moscow.py -lib/pytz/zoneinfo/Europe/Nicosia.py -lib/pytz/zoneinfo/Europe/Oslo.py -lib/pytz/zoneinfo/Europe/Paris.py -lib/pytz/zoneinfo/Europe/Prague.py -lib/pytz/zoneinfo/Europe/Riga.py -lib/pytz/zoneinfo/Europe/Rome.py -lib/pytz/zoneinfo/Europe/Samara.py -lib/pytz/zoneinfo/Europe/San_Marino.py -lib/pytz/zoneinfo/Europe/Sarajevo.py -lib/pytz/zoneinfo/Europe/Simferopol.py -lib/pytz/zoneinfo/Europe/Skopje.py -lib/pytz/zoneinfo/Europe/Sofia.py -lib/pytz/zoneinfo/Europe/Stockholm.py -lib/pytz/zoneinfo/Europe/Tallinn.py -lib/pytz/zoneinfo/Europe/Tirane.py -lib/pytz/zoneinfo/Europe/Tiraspol.py -lib/pytz/zoneinfo/Europe/Uzhgorod.py -lib/pytz/zoneinfo/Europe/Vaduz.py -lib/pytz/zoneinfo/Europe/Vatican.py -lib/pytz/zoneinfo/Europe/Vienna.py -lib/pytz/zoneinfo/Europe/Vilnius.py -lib/pytz/zoneinfo/Europe/Warsaw.py -lib/pytz/zoneinfo/Europe/Zagreb.py -lib/pytz/zoneinfo/Europe/Zaporozhye.py -lib/pytz/zoneinfo/Europe/Zurich.py -lib/pytz/zoneinfo/Europe/__init__.py -lib/pytz/zoneinfo/Indian/Antananarivo.py -lib/pytz/zoneinfo/Indian/Chagos.py -lib/pytz/zoneinfo/Indian/Christmas.py -lib/pytz/zoneinfo/Indian/Cocos.py -lib/pytz/zoneinfo/Indian/Comoro.py -lib/pytz/zoneinfo/Indian/Kerguelen.py -lib/pytz/zoneinfo/Indian/Mahe.py -lib/pytz/zoneinfo/Indian/Maldives.py -lib/pytz/zoneinfo/Indian/Mauritius.py -lib/pytz/zoneinfo/Indian/Mayotte.py -lib/pytz/zoneinfo/Indian/Reunion.py -lib/pytz/zoneinfo/Indian/__init__.py -lib/pytz/zoneinfo/Mexico/BajaNorte.py -lib/pytz/zoneinfo/Mexico/BajaSur.py -lib/pytz/zoneinfo/Mexico/General.py -lib/pytz/zoneinfo/Mexico/__init__.py -lib/pytz/zoneinfo/Pacific/Apia.py -lib/pytz/zoneinfo/Pacific/Auckland.py -lib/pytz/zoneinfo/Pacific/Chatham.py -lib/pytz/zoneinfo/Pacific/Easter.py -lib/pytz/zoneinfo/Pacific/Efate.py -lib/pytz/zoneinfo/Pacific/Enderbury.py -lib/pytz/zoneinfo/Pacific/Fakaofo.py -lib/pytz/zoneinfo/Pacific/Fiji.py -lib/pytz/zoneinfo/Pacific/Funafuti.py -lib/pytz/zoneinfo/Pacific/Galapagos.py -lib/pytz/zoneinfo/Pacific/Gambier.py -lib/pytz/zoneinfo/Pacific/Guadalcanal.py -lib/pytz/zoneinfo/Pacific/Guam.py -lib/pytz/zoneinfo/Pacific/Honolulu.py -lib/pytz/zoneinfo/Pacific/Johnston.py -lib/pytz/zoneinfo/Pacific/Kiritimati.py -lib/pytz/zoneinfo/Pacific/Kosrae.py -lib/pytz/zoneinfo/Pacific/Kwajalein.py -lib/pytz/zoneinfo/Pacific/Majuro.py -lib/pytz/zoneinfo/Pacific/Marquesas.py -lib/pytz/zoneinfo/Pacific/Midway.py -lib/pytz/zoneinfo/Pacific/Nauru.py -lib/pytz/zoneinfo/Pacific/Niue.py -lib/pytz/zoneinfo/Pacific/Norfolk.py -lib/pytz/zoneinfo/Pacific/Noumea.py -lib/pytz/zoneinfo/Pacific/Pago_Pago.py -lib/pytz/zoneinfo/Pacific/Palau.py -lib/pytz/zoneinfo/Pacific/Pitcairn.py -lib/pytz/zoneinfo/Pacific/Ponape.py -lib/pytz/zoneinfo/Pacific/Port_Moresby.py -lib/pytz/zoneinfo/Pacific/Rarotonga.py -lib/pytz/zoneinfo/Pacific/Saipan.py -lib/pytz/zoneinfo/Pacific/Samoa.py -lib/pytz/zoneinfo/Pacific/Tahiti.py -lib/pytz/zoneinfo/Pacific/Tarawa.py -lib/pytz/zoneinfo/Pacific/Tongatapu.py -lib/pytz/zoneinfo/Pacific/Truk.py -lib/pytz/zoneinfo/Pacific/Wake.py -lib/pytz/zoneinfo/Pacific/Wallis.py -lib/pytz/zoneinfo/Pacific/Yap.py -lib/pytz/zoneinfo/Pacific/__init__.py -lib/pytz/zoneinfo/SystemV/AST4.py -lib/pytz/zoneinfo/SystemV/AST4ADT.py -lib/pytz/zoneinfo/SystemV/CST6.py -lib/pytz/zoneinfo/SystemV/CST6CDT.py -lib/pytz/zoneinfo/SystemV/EST5.py -lib/pytz/zoneinfo/SystemV/EST5EDT.py -lib/pytz/zoneinfo/SystemV/HST10.py -lib/pytz/zoneinfo/SystemV/MST7.py -lib/pytz/zoneinfo/SystemV/MST7MDT.py -lib/pytz/zoneinfo/SystemV/PST8.py -lib/pytz/zoneinfo/SystemV/PST8PDT.py -lib/pytz/zoneinfo/SystemV/YST9.py -lib/pytz/zoneinfo/SystemV/YST9YDT.py -lib/pytz/zoneinfo/SystemV/__init__.py -lib/pytz/zoneinfo/US/Alaska.py -lib/pytz/zoneinfo/US/Aleutian.py -lib/pytz/zoneinfo/US/Arizona.py -lib/pytz/zoneinfo/US/Central.py -lib/pytz/zoneinfo/US/East_minus_Indiana.py -lib/pytz/zoneinfo/US/Eastern.py -lib/pytz/zoneinfo/US/Hawaii.py -lib/pytz/zoneinfo/US/Indiana_minus_Starke.py -lib/pytz/zoneinfo/US/Michigan.py -lib/pytz/zoneinfo/US/Mountain.py -lib/pytz/zoneinfo/US/Pacific.py -lib/pytz/zoneinfo/US/Pacific_minus_New.py -lib/pytz/zoneinfo/US/Samoa.py -lib/pytz/zoneinfo/US/__init__.py -lib/subprocess/__init__.py -lib/subprocess/subprocess.py -license/DATEUTIL_LICENSE.txt -license/LICENSE -license/LICENSE_BAKOMA -license/LICENSE_COLORBREWER -license/LICENSE_PAINT -license/LICENSE_PIL -license/LICENSE_YORICK -license/LICENSE_enthought.txt -license/PYTZ_LICENSE.txt -src/MPL_isnan.h -src/_backend_agg.cpp -src/_backend_agg.h -src/_backend_gdk.c -src/_gtkagg.cpp -src/_image.cpp -src/_image.h -src/_isnan.c -src/_na_backend_agg.cpp -src/_na_backend_gdk.c -src/_na_cntr.c -src/_na_image.cpp -src/_na_nxutils.c -src/_na_transforms.cpp -src/_nc_backend_agg.cpp -src/_nc_backend_gdk.c -src/_nc_cntr.c -src/_nc_image.cpp -src/_nc_nxutils.c -src/_nc_transforms.cpp -src/_ns_backend_agg.cpp -src/_ns_backend_gdk.c -src/_ns_cntr.c -src/_ns_image.cpp -src/_ns_nxutils.c -src/_ns_transforms.cpp -src/_subprocess.c -src/_tkagg.cpp -src/_transforms.cpp -src/_transforms.h -src/_windowing.cpp -src/_wxagg.cpp -src/agg.cxx -src/cntr.c -src/ft2font.cpp -src/ft2font.h -src/mplutils.cpp -src/mplutils.h -src/numerix.h -src/nxutils.c -src/swig_runtime.h -swig/agg.i -swig/agg_basics.i -swig/agg_buffer.h -swig/agg_conv_curve.i -swig/agg_conv_stroke.i -swig/agg_conv_transform.i -swig/agg_path_storage.i -swig/agg_rasterizer_scanline_aa.i -swig/agg_renderer_base.i -swig/agg_renderer_scanline.i -swig/agg_scanline_bin.i -swig/agg_span_image_filter.i -swig/agg_trans_affine.i -swig/agg_typedefs.h -swig/agg_typemaps.i Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-09-12 13:36:25 UTC (rev 3835) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-09-12 14:05:20 UTC (rev 3836) @@ -1209,6 +1209,14 @@ def get_default_filetype(self): raise NotImplementedError + def set_window_title(self, title): + """ + Set the title text of the window containing the figure. Note that + this has no effect if there is no window (eg, a PS backend). + """ + if hasattr(self, "manager"): + self.manager.set_window_title(title) + def switch_backends(self, FigureCanvasClass): """ instantiate an instance of FigureCanvasClass @@ -1321,6 +1329,13 @@ """ pass + def set_window_title(self, title): + """ + Set the title text of the window containing the figure. Note that + this has no effect if there is no window (eg, a PS backend). + """ + pass + # cursors class Cursors: #namespace HAND, POINTER, SELECT_REGION, MOVE = range(4) Modified: branches/transforms/lib/matplotlib/backends/backend_fltkagg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_fltkagg.py 2007-09-12 13:36:25 UTC (rev 3835) +++ branches/transforms/lib/matplotlib/backends/backend_fltkagg.py 2007-09-12 14:05:20 UTC (rev 3836) @@ -299,6 +299,9 @@ self.canvas.draw() self.window.redraw() + def set_window_title(self, title): + self.window_title=title + self.window.label(title) class AxisMenu: def __init__(self, toolbar): Modified: branches/transforms/lib/matplotlib/backends/backend_gtk.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_gtk.py 2007-09-12 13:36:25 UTC (rev 3835) +++ branches/transforms/lib/matplotlib/backends/backend_gtk.py 2007-09-12 14:05:20 UTC (rev 3836) @@ -460,6 +460,8 @@ toolbar = None return toolbar + def set_window_title(self, title): + self.window.set_title(title) def resize(self, width, height): 'set the canvas size in pixels' Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-09-12 13:36:25 UTC (rev 3835) +++ branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-09-12 14:05:20 UTC (rev 3836) @@ -491,6 +491,7 @@ return fontdictObject def embedType1(self, filename, fontinfo): + # TODO: font effects such as SlantFont fh = open(filename, 'rb') matplotlib.verbose.report( 'Embedding Type 1 font ' + filename, 'debug') @@ -520,8 +521,15 @@ if fontinfo.encodingfile is not None: enc = dviread.Encoding(fontinfo.encodingfile) - widths = [ afmdata.get_width_from_char_name(ch) - for ch in enc ] + widths = [] + for ch in enc: + try: + widths.append(afmdata.get_width_from_char_name(ch)) + except KeyError: + matplotlib.verbose.report( + 'No width for %s in %s' % (ch, fullname), 'debug') + widths.append(0) + differencesArray = [ Name(ch) for ch in enc ] differencesArray = [ 0 ] + differencesArray firstchar = 0 @@ -538,11 +546,24 @@ firstchar = not_None.next() lastchar = max(not_None) widths = widths[firstchar:lastchar+1] + for i,w in enumerate(widths): + if w is None: widths[i] = 0 - differencesArray = [ firstchar ] + differencesArray = [ ] + need_idx = True for ch in range(firstchar, lastchar+1): - differencesArray.append(Name( - afmdata.get_name_char(ch, isord=True))) + try: + name = afmdata.get_name_char(ch, isord=True) + if need_idx: + differencesArray.append(ch) + need_idx = False + differencesArray.append(Name(name)) + except KeyError: + matplotlib.verbose.report( + 'No name for glyph %d in %s' % (ch, fullname), + 'debug') + need_idx = True + fontdict = { 'Type': Name('Font'), @@ -1448,17 +1469,16 @@ # Gather font information and do some setup for combining # characters into strings. - oldfontnum, seq = None, [] - for x1, y1, fontnum, glyph, width in page.text: - if fontnum != oldfontnum: - texname, fontsize = dvi.fontinfo(fontnum) - fontinfo = self.tex_font_mapping(texname) + oldfont, seq = None, [] + for x1, y1, dvifont, glyph, width in page.text: + if dvifont != oldfont: + fontinfo = self.tex_font_mapping(dvifont.texname) pdfname = self.file.fontName(fontinfo.filename) self.file.fontInfo[pdfname] = Bunch( encodingfile=fontinfo.encoding, afmfile=fontinfo.afm) - seq += [['font', pdfname, fontsize]] - oldfontnum = fontnum + seq += [['font', pdfname, dvifont.size]] + oldfont = dvifont seq += [['text', x1, y1, [chr(glyph)], x1+width]] seq += [('end',)] Modified: branches/transforms/lib/matplotlib/backends/backend_qt.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_qt.py 2007-09-12 13:36:25 UTC (rev 3835) +++ branches/transforms/lib/matplotlib/backends/backend_qt.py 2007-09-12 14:05:20 UTC (rev 3836) @@ -247,6 +247,9 @@ if DEBUG: print "destroy figure manager" self.window.close(True) + def set_window_title(self, title): + self.window.setCaption(title) + class NavigationToolbar2QT( NavigationToolbar2, qt.QWidget ): # list of toolitems to add to the toolbar, format is: # text, tooltip_text, image_file, callback(str) Modified: branches/transforms/lib/matplotlib/backends/backend_qt4.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_qt4.py 2007-09-12 13:36:25 UTC (rev 3835) +++ branches/transforms/lib/matplotlib/backends/backend_qt4.py 2007-09-12 14:05:20 UTC (rev 3836) @@ -249,6 +249,9 @@ if DEBUG: print "destroy figure manager" self.window.close() + def set_window_title(self, title): + self.window.setWindowTitle(title) + class NavigationToolbar2QT( NavigationToolbar2, QtGui.QWidget ): # list of toolitems to add to the toolbar, format is: # text, tooltip_text, image_file, callback(str) Modified: branches/transforms/lib/matplotlib/backends/backend_tkagg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_tkagg.py 2007-09-12 13:36:25 UTC (rev 3835) +++ branches/transforms/lib/matplotlib/backends/backend_tkagg.py 2007-09-12 14:05:20 UTC (rev 3836) @@ -350,6 +350,9 @@ pass self.window = None + def set_window_title(self, title): + self.window.wm_title(title) + class AxisMenu: def __init__(self, master, naxes): self._master = master Modified: branches/transforms/lib/matplotlib/backends/backend_wx.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_wx.py 2007-09-12 13:36:25 UTC (rev 3835) +++ branches/transforms/lib/matplotlib/backends/backend_wx.py 2007-09-12 14:05:20 UTC (rev 3836) @@ -1399,6 +1399,9 @@ #wx.GetApp().ProcessIdle() wx.WakeUpIdle() + def set_window_title(self, title): + self.window.SetTitle(title) + # Identifiers for toolbar controls - images_wx contains bitmaps for the images # used in the controls. wxWindows does not provide any stock images, so I've # 'stolen' those from GTK2, and transformed them into the appropriate format. Modified: branches/transforms/lib/matplotlib/dviread.py =================================================================== --- branches/transforms/lib/matplotlib/dviread.py 2007-09-12 13:36:25 UTC (rev 3835) +++ branches/transforms/lib/matplotlib/dviread.py 2007-09-12 14:05:20 UTC (rev 3836) @@ -9,15 +9,13 @@ for page in dvi: # iterate over pages w, h, d = page.width, page.height, page.descent for x,y,font,glyph,width in page.text: - fontname, pointsize = dvi.fontinfo(font) + fontname = font.texname + pointsize = font.size ... for x,y,height,width in page.boxes: ... """ -# TODO: support TeX virtual fonts (*.vf) which... [truncated message content] |
From: <md...@us...> - 2007-09-13 12:50:07
|
Revision: 3847 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3847&view=rev Author: mdboom Date: 2007-09-13 05:50:05 -0700 (Thu, 13 Sep 2007) Log Message: ----------- Merged revisions 3836-3846 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3844 | jdh2358 | 2007-09-12 16:37:41 -0400 (Wed, 12 Sep 2007) | 1 line fixed a bar units bug ........ r3845 | jouni | 2007-09-13 02:29:14 -0400 (Thu, 13 Sep 2007) | 3 lines More work on dviread and usetex in pdf. It is more usable now, so I am renaming the method from _draw_tex to draw_tex. ........ Modified Paths: -------------- branches/transforms/API_CHANGES branches/transforms/CHANGELOG branches/transforms/lib/matplotlib/artist.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/axis.py branches/transforms/lib/matplotlib/backends/backend_pdf.py branches/transforms/lib/matplotlib/dviread.py branches/transforms/lib/matplotlib/mlab.py branches/transforms/lib/matplotlib/patches.py Added Paths: ----------- branches/transforms/examples/units/bar_demo2.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3835 + /trunk/matplotlib:1-3846 Modified: branches/transforms/API_CHANGES =================================================================== --- branches/transforms/API_CHANGES 2007-09-13 12:44:16 UTC (rev 3846) +++ branches/transforms/API_CHANGES 2007-09-13 12:50:05 UTC (rev 3847) @@ -1,3 +1,5 @@ + Made skiprows=1 the default on csv2rec + The gd and paint backends have been deleted. The errorbar method and function now accept additional kwargs Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-09-13 12:44:16 UTC (rev 3846) +++ branches/transforms/CHANGELOG 2007-09-13 12:50:05 UTC (rev 3847) @@ -1,3 +1,10 @@ +2007-09-13 The usetex support in the pdf backend is more usable now, + so I am enabling it. - JKS + +2007-09-12 Fixed a Axes.bar unit bug - JDH + +2007-09-10 Made skiprows=1 the default on csv2rec - JDH + 2007-09-09 Split out the plotting part of pylab and put it in pyplot.py; removed numerix from the remaining pylab.py, which imports everything from pyplot.py. The intention Copied: branches/transforms/examples/units/bar_demo2.py (from rev 3845, trunk/matplotlib/examples/units/bar_demo2.py) =================================================================== --- branches/transforms/examples/units/bar_demo2.py (rev 0) +++ branches/transforms/examples/units/bar_demo2.py 2007-09-13 12:50:05 UTC (rev 3847) @@ -0,0 +1,34 @@ +""" +plot using a variety of cm vs inches conversions. The example shows +how default unit instrospection works (ax1), how various keywords can +be used to set the x and y units to override the defaults (ax2, ax3, +ax4) and how one can set the xlimits using scalars (ax3, current units +assumed) or units (conversions applied to get the numbers to current +units) + +""" +from basic_units import cm, inch +from pylab import figure, show, nx + +cms = cm *nx.arange(0, 10, 2) +bottom=0*cm +width=0.8*cm + +fig = figure() + +ax1 = fig.add_subplot(2,2,1) +ax1.bar(cms, cms, bottom=bottom) + +ax2 = fig.add_subplot(2,2,2) +ax2.bar(cms, cms, bottom=bottom, width=width, xunits=cm, yunits=inch) + +ax3 = fig.add_subplot(2,2,3) +ax3.bar(cms, cms, bottom=bottom, width=width, xunits=inch, yunits=cm) +ax3.set_xlim(3, 6) # scalars are interpreted in current units + +ax4 = fig.add_subplot(2,2,4) +ax4.bar(cms, cms, bottom=bottom, width=width, xunits=inch, yunits=inch) +#fig.savefig('simple_conversion_plot.png') +ax4.set_xlim(3*cm, 6*cm) # cm are converted to inches + +show() Modified: branches/transforms/lib/matplotlib/artist.py =================================================================== --- branches/transforms/lib/matplotlib/artist.py 2007-09-13 12:44:16 UTC (rev 3846) +++ branches/transforms/lib/matplotlib/artist.py 2007-09-13 12:50:05 UTC (rev 3847) @@ -51,7 +51,7 @@ self._remove_method = None def remove(self): - ''' + """ Remove the artist from the figure if possible. The effect will not be visible until the figure is redrawn, e.g., with ax.draw_idle(). Call ax.relim() to update the axes limits if desired. @@ -60,7 +60,7 @@ was added to axes with autolim=True. Note: there is no support for removing the artist's legend entry. - ''' + """ # There is no method to set the callback. Instead the parent should set # the _remove_method attribute directly. This would be a protected Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-09-13 12:44:16 UTC (rev 3846) +++ branches/transforms/lib/matplotlib/axes.py 2007-09-13 12:50:05 UTC (rev 3847) @@ -1193,23 +1193,27 @@ def _process_unit_info(self, xdata=None, ydata=None, kwargs=None): 'look for unit kwargs and update the axis instances as necessary' - if self.xaxis is None or self.xaxis is None: return + if self.xaxis is None or self.yaxis is None: return - + #print 'processing', self.get_geometry() if xdata is not None: self.xaxis.update_units(xdata) + #print '\tset from xdata', self.xaxis.units if ydata is not None: self.yaxis.update_units(ydata) + #print '\tset from ydata', self.yaxis.units # process kwargs 2nd since these will override default units if kwargs is not None: xunits = kwargs.pop( 'xunits', self.xaxis.units) if xunits!=self.xaxis.units: + #print '\tkw setting xunits', xunits self.xaxis.set_units(xunits) yunits = kwargs.pop('yunits', self.yaxis.units) if yunits!=self.yaxis.units: + #print '\tkw setting yunits', yunits self.yaxis.set_units(yunits) def in_axes(self, xwin, ywin): @@ -3122,11 +3126,13 @@ else: raise ValueError, 'invalid orientation: %s' % orientation - left = npy.asarray(left) - height = npy.asarray(height) - width = npy.asarray(width) - bottom = npy.asarray(bottom) + # do not convert to array here as unit info is lost + #left = npy.asarray(left) + #height = npy.asarray(height) + #width = npy.asarray(width) + #bottom = npy.asarray(bottom) + if len(linewidth) == 1: linewidth = linewidth * nbars # if color looks like a color string, an RGB tuple or a @@ -3169,14 +3175,14 @@ # lets do some conversions now if self.xaxis is not None: xconv = self.xaxis.converter - if ( xconv ): + if xconv is not None: units = self.xaxis.get_units() left = xconv.convert( left, units ) width = xconv.convert( width, units ) if self.yaxis is not None: yconv = self.yaxis.converter - if ( yconv ): + if yconv is not None : units = self.yaxis.get_units() bottom = yconv.convert( bottom, units ) height = yconv.convert( height, units ) @@ -3216,12 +3222,14 @@ if xerr is not None or yerr is not None: if orientation == 'vertical': - x = left + 0.5*width - y = bottom + height + # using list comps rather than arrays to preserve unit info + x = [l+0.5*w for l, w in zip(left, width)] + y = [b+h for b,h in zip(bottom, height)] elif orientation == 'horizontal': - x = left + width - y = bottom + 0.5*height + # using list comps rather than arrays to preserve unit info + x = [l+w for l,w in zip(left, width)] + y = [b+0.5*h for b,h in zip(bottom, height)] self.errorbar( x, y, Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-09-13 12:44:16 UTC (rev 3846) +++ branches/transforms/lib/matplotlib/axis.py 2007-09-13 12:50:05 UTC (rev 3847) @@ -821,7 +821,7 @@ return x ret = self.converter.convert(x, self.units) - #print 'convert_units converting: units=%s, converter=%s, in=%s, out=%s'%(self.units, self.converter, x, ret) + #print 'convert_units converting: axis=%s, units=%s, converter=%s, in=%s, out=%s'%(self, self.units, self.converter, x, ret) return ret def set_units(self, u): Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-09-13 12:44:16 UTC (rev 3846) +++ branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-09-13 12:50:05 UTC (rev 3847) @@ -527,7 +527,7 @@ widths.append(afmdata.get_width_from_char_name(ch)) except KeyError: matplotlib.verbose.report( - 'No width for %s in %s' % (ch, fullname), 'debug') + 'No width for %s in %s' % (ch, fullname), 'debug-annoying') widths.append(0) differencesArray = [ Name(ch) for ch in enc ] @@ -561,7 +561,7 @@ except KeyError: matplotlib.verbose.report( 'No name for glyph %d in %s' % (ch, fullname), - 'debug') + 'debug-annoying') need_idx = True @@ -1449,9 +1449,7 @@ # Pop off the global transformation self.file.output(Op.grestore) - def _draw_tex(self, gc, x, y, s, prop, angle): - # Rename to draw_tex to enable - + def draw_tex(self, gc, x, y, s, prop, angle): texmanager = self.get_texmanager() fontsize = prop.get_size_in_points() dvifile = texmanager.make_dvi(s, fontsize) @@ -1494,7 +1492,7 @@ elt[3][-1] += next[3][0] elt[4] += next[4]-next[1] else: - elt[3] += [offset, next[3][0]] + elt[3] += [offset*1000.0/dvifont.size, next[3][0]] elt[4] = next[4] del seq[i+1] continue Modified: branches/transforms/lib/matplotlib/dviread.py =================================================================== --- branches/transforms/lib/matplotlib/dviread.py 2007-09-13 12:44:16 UTC (rev 3846) +++ branches/transforms/lib/matplotlib/dviread.py 2007-09-13 12:50:05 UTC (rev 3847) @@ -84,16 +84,22 @@ e = 0 # zero depth else: # glyph x,y,font,g,w = elt - h = (font.scale * font.tfm.height[g]) >> 20 - e = (font.scale * font.tfm.depth[g]) >> 20 + h = _mul2012(font._scale, font._tfm.height[g]) + e = _mul2012(font._scale, font._tfm.depth[g]) minx = min(minx, x) miny = min(miny, y - h) maxx = max(maxx, x + w) maxy = max(maxy, y + e) maxy_pure = max(maxy_pure, y) + if self.dpi is None: + # special case for ease of debugging: output raw dvi coordinates + return mpl_cbook.Bunch(text=self.text, boxes=self.boxes, + width=maxx-minx, height=maxy_pure-miny, + descent=maxy-maxy_pure) + d = self.dpi / (72.27 * 2**16) # from TeX's "scaled points" to dpi units - text = [ ((x-minx)*d, (maxy-y)*d, DviFont(f), g, w*d) + text = [ ((x-minx)*d, (maxy-y)*d, f, g, w*d) for (x,y,f,g,w) in self.text ] boxes = [ ((x-minx)*d, (maxy-y)*d, h*d, w*d) for (x,y,h,w) in self.boxes ] @@ -110,11 +116,11 @@ while True: byte = ord(self.file.read(1)) self._dispatch(byte) - if self.state == _dvistate.inpage: - matplotlib.verbose.report( - 'Dvi._read: after %d at %f,%f' % - (byte, self.h, self.v), - 'debug-annoying') +# if self.state == _dvistate.inpage: +# matplotlib.verbose.report( +# 'Dvi._read: after %d at %f,%f' % +# (byte, self.h, self.v), +# 'debug-annoying') if byte == 140: # end of page return True if self.state == _dvistate.post_post: # end of file @@ -225,21 +231,11 @@ # I think we can assume this is constant self.state = _dvistate.outer - def _width_of(self, char, font): - width = font.tfm.width.get(char, None) - if width is not None: - return (width * font.scale) >> 20 - - matplotlib.verbose.report( - 'No width for char %d in font %s' % (char, font.name), - 'debug') - return 0 - def _set_char(self, char): if self.state != _dvistate.inpage: raise ValueError, "misplaced set_char in dvi file" self._put_char(char) - self.h += self._width_of(char, self.fonts[self.f]) + self.h += self.fonts[self.f]._width_of(char) def _set_rule(self, a, b): if self.state != _dvistate.inpage: @@ -251,20 +247,33 @@ if self.state != _dvistate.inpage: raise ValueError, "misplaced put_char in dvi file" font = self.fonts[self.f] - if font.vf is None: + if font._vf is None: self.text.append((self.h, self.v, font, char, - self._width_of(char, font))) + font._width_of(char))) +# matplotlib.verbose.report( +# 'Dvi._put_char: %d,%d %d' %(self.h, self.v, char), +# 'debug-annoying') else: - self.text.extend([(self.h + x, self.v + y, f, g, w) - for x, y, f, g, w in font.vf[char].text]) - self.boxes.extend([(self.h + x, self.v + y, a, b) - for x, y, a, b in font.vf[char].boxes]) + scale = font._scale + for x, y, f, g, w in font._vf[char].text: + newf = DviFont(scale=_mul2012(scale, f._scale), + tfm=f._tfm, texname=f.texname, vf=f._vf) + self.text.append((self.h + _mul2012(x, scale), + self.v + _mul2012(y, scale), + newf, g, newf._width_of(g))) + self.boxes.extend([(self.h + _mul2012(x, scale), + self.v + _mul2012(y, scale), + _mul2012(a, scale), _mul2012(b, scale)) + for x, y, a, b in font._vf[char].boxes]) def _put_rule(self, a, b): if self.state != _dvistate.inpage: raise ValueError, "misplaced put_rule in dvi file" if a > 0 and b > 0: self.boxes.append((self.h, self.v, a, b)) +# matplotlib.verbose.report( +# 'Dvi._put_rule: %d,%d %d,%d' % (self.h, self.v, a, b), +# 'debug-annoying') def _nop(self): pass @@ -357,7 +366,7 @@ vf = _vffile(n[-l:]) - self.fonts[k] = mpl_cbook.Bunch(scale=s, tfm=tfm, name=n, vf=vf) + self.fonts[k] = DviFont(scale=s, tfm=tfm, texname=n, vf=vf) def _post(self): if self.state != _dvistate.outer: @@ -370,17 +379,20 @@ raise NotImplementedError class DviFont(object): - __slots__ = ('texname', 'size') + """ + Object that holds a font's texname and size and supports comparison. + There are also internal attributes (for use by dviread.py) that + are _not_ used for comparison. - def __init__(self, f): - """ - Object that holds a font's texname and size and supports comparison. + The size is in Adobe points (converted from TeX points). + """ + __slots__ = ('texname', 'size', '_scale', '_vf', '_tfm') - The size is in Adobe points (converted from TeX points). - """ + def __init__(self, scale, tfm, texname, vf): + self._scale, self._tfm, self.texname, self._vf = \ + scale, tfm, texname, vf # TODO: would it make more sense to have the size in dpi units? - self.texname = f.name - self.size = f.scale * (72.0 / (72.27 * 2**16)) + self.size = scale * (72.0 / (72.27 * 2**16)) def __eq__(self, other): return self.__class__ == other.__class__ and \ @@ -389,6 +401,16 @@ def __ne__(self, other): return not self.__eq__(other) + def _width_of(self, char): + width = self._tfm.width.get(char, None) + if width is not None: + return _mul2012(width, self._scale) + + matplotlib.verbose.report( + 'No width for char %d in font %s' % (char, self.texname), + 'debug') + return 0 + class Vf(Dvi): """ A virtual font (*.vf file) containing subroutines for dvi files. @@ -465,7 +487,8 @@ raise ValueError, "pre command in middle of vf file" if i != 202: raise ValueError, "Unknown vf format %d" % i - matplotlib.verbose.report('vf file comment: ' + x, 'debug') + if len(x): + matplotlib.verbose.report('vf file comment: ' + x, 'debug') self.state = _dvistate.outer # cs = checksum, ds = design size @@ -474,7 +497,7 @@ if self._first_font is None: self._first_font = k -def fix2comp(num): +def _fix2comp(num): """ Convert from two's complement to negative. """ @@ -484,6 +507,13 @@ else: return num +def _mul2012(num1, num2): + """ + Multiply two numbers in 20.12 fixed point format. + """ + # Separated into a function because >> has surprising precedence + return (num1*num2) >> 20 + class Tfm(object): """ A TeX Font Metric file. This implementation covers only the bare @@ -497,6 +527,7 @@ (this is a dict because indexing may not start from 0) height[i], depth[i]: height and depth of character #i """ + __slots__ = ('checksum', 'design_size', 'width', 'height', 'depth') def __init__(self, filename): matplotlib.verbose.report('opening tfm file ' + filename, 'debug') @@ -525,9 +556,9 @@ [ struct.unpack('!%dI' % (len(x)/4), x) for x in (widths, heights, depths) ] for i in range(ec-bc): - self.width[bc+i] = fix2comp(widths[ord(char_info[4*i])]) - self.height[bc+i] = fix2comp(heights[ord(char_info[4*i+1]) >> 4]) - self.depth[bc+i] = fix2comp(depths[ord(char_info[4*i+1]) & 0xf]) + self.width[bc+i] = _fix2comp(widths[ord(char_info[4*i])]) + self.height[bc+i] = _fix2comp(heights[ord(char_info[4*i+1]) >> 4]) + self.depth[bc+i] = _fix2comp(depths[ord(char_info[4*i+1]) & 0xf]) class PsfontsMap(object): @@ -552,6 +583,7 @@ the pdf-related files perhaps only avoid the "Base 14" pdf fonts. But the user may have configured these files differently. """ + __slots__ = ('_font',) def __init__(self, filename): self._font = {} @@ -627,7 +659,17 @@ encoding=encoding, filename=filename) class Encoding(object): + """ + Parses a *.enc file referenced from a psfonts.map style file. + The format this class understands is a very limited subset of + PostScript. + Usage (subject to change): + for name in Encoding(filename): + whatever(name) + """ + __slots__ = ('encoding',) + def __init__(self, filename): file = open(filename, 'rt') try: @@ -694,6 +736,10 @@ return result +# With multiple text objects per figure (e.g. tick labels) we may end +# up reading the same tfm and vf files many times, so we implement a +# simple cache. TODO: is this worth making persistent? + _tfmcache = {} _vfcache = {} @@ -721,19 +767,22 @@ if __name__ == '__main__': - matplotlib.verbose.set_level('debug') - dvi = Dvi('foo.dvi', 72) + import sys + matplotlib.verbose.set_level('debug-annoying') + fname = sys.argv[1] + try: dpi = float(sys.argv[2]) + except IndexError: dpi = None + dvi = Dvi(fname, dpi) fontmap = PsfontsMap(find_tex_file('pdftex.map')) - for text,boxes in dvi: + for page in dvi: print '=== new page ===' fPrev = None - for x,y,f,c in text: - texname = dvi.fonts[f].name - print x,y,c,chr(c),texname + for x,y,f,c,w in page.text: if f != fPrev: - print 'font', texname, '=', fontmap[texname].__dict__ + print 'font', f.texname, 'scaled', f._scale/pow(2.0,20) fPrev = f - for x,y,w,h in boxes: + print x,y,c, 32 <= c < 128 and chr(c) or '.', w + for x,y,w,h in page.boxes: print x,y,'BOX',w,h Modified: branches/transforms/lib/matplotlib/mlab.py =================================================================== --- branches/transforms/lib/matplotlib/mlab.py 2007-09-13 12:44:16 UTC (rev 3846) +++ branches/transforms/lib/matplotlib/mlab.py 2007-09-13 12:50:05 UTC (rev 3847) @@ -1253,9 +1253,9 @@ if r==1 or c==1: X.shape = max(r,c), if unpack: return X.transpose() - return X + else: return X -def csv2rec(fname, comments='#', skiprows=0, checkrows=5, delimiter=',', +def csv2rec(fname, comments='#', skiprows=1, checkrows=5, delimiter=',', converterd=None, names=None, missing=None): """ Load data from comma/space/tab delimited file in fname into a Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-09-13 12:44:16 UTC (rev 3846) +++ branches/transforms/lib/matplotlib/patches.py 2007-09-13 12:50:05 UTC (rev 3847) @@ -77,6 +77,8 @@ if len(kwargs): artist.setp(self, **kwargs) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd + + def contains(self, mouseevent): """Test whether the mouse event occurred in the patch. @@ -352,7 +354,6 @@ Return the vertices of the rectangle """ x, y = self.xy - left, right = self.convert_xunits((x, x + self.width)) bottom, top = self.convert_yunits((y, y + self.height)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-14 13:03:33
|
Revision: 3851 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3851&view=rev Author: mdboom Date: 2007-09-14 06:03:31 -0700 (Fri, 14 Sep 2007) Log Message: ----------- Removed transforms on the C++ side -- removed many methods that depend on it in backend_agg in preparation for path generalization. Lots of general renaming... Modified Paths: -------------- branches/transforms/lib/matplotlib/artist.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/axis.py branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/finance.py branches/transforms/lib/matplotlib/legend.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/table.py branches/transforms/lib/matplotlib/text.py branches/transforms/lib/matplotlib/ticker.py branches/transforms/lib/matplotlib/widgets.py branches/transforms/setup.py branches/transforms/setupext.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h branches/transforms/src/_gtkagg.cpp branches/transforms/src/_tkagg.cpp Added Paths: ----------- branches/transforms/lib/matplotlib/transforms.py Removed Paths: ------------- branches/transforms/lib/matplotlib/affine.py branches/transforms/src/_transforms.cpp branches/transforms/src/_transforms.h Deleted: branches/transforms/lib/matplotlib/affine.py =================================================================== --- branches/transforms/lib/matplotlib/affine.py 2007-09-14 12:24:20 UTC (rev 3850) +++ branches/transforms/lib/matplotlib/affine.py 2007-09-14 13:03:31 UTC (rev 3851) @@ -1,854 +0,0 @@ -""" -A set of classes to handle transformations. - -2007 Michael Droettboom -""" - -import numpy as npy -from numpy.linalg import inv -from sets import Set - -# MGDTODO: The name of this module is bad, since it deals with -# non-affine transformations as well. It should probably just be -# "transforms", but we already had one of those... ;) - -# MGDTODO: This creates a ton of cyclical references. We may want to -# consider using weak references - -# MGDTODO: deep copying is probably incorrect wrt the parent/child -# relationships - -class TransformNode(object): - def __init__(self): - self._parents = Set() - - def invalidate(self): - if not self._do_invalidation(): - for parent in self._parents: - parent.invalidate() - - def _do_invalidation(self): - return False - - def set_children(self, children): - for child in children: - getattr(self, child)._parents.add(self) - self._children = children - -# def replace_child(self, index, child): -# children = self._children -# getattr(self, children[index])._parents.remove(self) -# setattr(self, children[index], child) -# # We have to reset children in case two or more -# # of the children are the same -# for child in children: -# getattr(self, child)._parents.add(self) -# self.invalidate() - -class BboxBase(TransformNode): - ''' - This is the read-only part of a bounding-box - ''' - - def __init__(self): - TransformNode.__init__(self) - - def __array__(self): - return self.get_points() - - # MGDTODO: Probably a more efficient ways to do this... - def _get_xmin(self): - return self.get_points()[0, 0] - xmin = property(_get_xmin) - - def _get_ymin(self): - return self.get_points()[0, 1] - ymin = property(_get_ymin) - - def _get_xmax(self): - return self.get_points()[1, 0] - xmax = property(_get_xmax) - - def _get_ymax(self): - return self.get_points()[1, 1] - ymax = property(_get_ymax) - - def _get_min(self): - return self.get_points()[0] - min = property(_get_min) - - def _get_max(self): - return self.get_points()[1] - max = property(_get_max) - - def _get_intervalx(self): - return self.get_points()[:, 0] - intervalx = property(_get_intervalx) - - def _get_intervaly(self): - return self.get_points()[:, 1] - intervaly = property(_get_intervaly) - - def _get_width(self): - return self.xmax - self.xmin - width = property(_get_width) - - def _get_height(self): - return self.ymax - self.ymin - height = property(_get_height) - - def _get_bounds(self): - return (self.xmin, self.ymin, - self.xmax - self.xmin, self.ymax - self.ymin) - bounds = property(_get_bounds) - - def get_points(self): - return NotImplementedError() - - # MGDTODO: Optimize - def containsx(self, x): - return x >= self.xmin and x <= self.xmax - - def containsy(self, y): - return y >= self.ymin and y <= self.ymax - - def contains(self, x, y): - return self.containsx(x) and self.containsy(y) - - def overlapsx(self, other): - return self.containsx(other.xmin) \ - or self.containsx(other.xmax) - - def overlapsy(self, other): - return self.containsy(other.ymin) \ - or self.containsx(other.ymax) - - def overlaps(self, other): - return self.overlapsx(other) \ - and self.overlapsy(other) - - def fully_containsx(self, x): - return x > self.xmin and x < self.xmax - - def fully_containsy(self, y): - return y > self.ymin and y < self.ymax - - def fully_contains(self, x, y): - return self.fully_containsx(x) \ - and self.fully_containsy(y) - - def fully_overlapsx(self, other): - return self.fully_containsx(other.xmin) \ - or self.fully_containsx(other.xmax) - - def fully_overlapsy(self, other): - return self.fully_containsy(other.ymin) \ - or self.fully_containsx(other.ymax) - - def fully_overlaps(self, other): - return self.fully_overlapsx(other) and \ - self.fully_overlapsy(other) - - -class Bbox(BboxBase): - def __init__(self, points): - BboxBase.__init__(self) - self._points = npy.asarray(points, npy.float_) - - #@staticmethod - def unit(): - return Bbox.from_lbrt(0., 0., 1., 1.) - unit = staticmethod(unit) - - #@staticmethod - def from_lbwh(left, bottom, width, height): - return Bbox.from_lbrt(left, bottom, left + width, bottom + height) - from_lbwh = staticmethod(from_lbwh) - - #@staticmethod - def from_lbrt(*args): - points = npy.array(args, dtype=npy.float_).reshape(2, 2) - return Bbox(points) - from_lbrt = staticmethod(from_lbrt) - - def __copy__(self): - return Bbox(self._points.copy()) - - def __deepcopy__(self, memo): - return Bbox(self._points.copy()) - - def __cmp__(self, other): - # MGDTODO: Totally suboptimal - if isinstance(other, Bbox) and (self._points == other._points).all(): - return 0 - return -1 - - def __repr__(self): - return 'Bbox(%s)' % repr(self._points) - __str__ = __repr__ - - # JDH: the update method will update the box limits from the - # existing limits and the new data; it appears here you are just - # using the new data. We use an "ignore" flag to specify whether - # you want to include the existing data or not in the update - def update_from_data(self, x, y, ignore=True): - self._points = npy.array( - [[x.min(), y.min()], [x.max(), y.max()]], - npy.float_) - self.invalidate() - - # MGDTODO: Probably a more efficient ways to do this... - def _set_xmin(self, val): - self._points[0, 0] = val - self.invalidate() - xmin = property(BboxBase._get_xmin, _set_xmin) - - def _set_ymin(self, val): - self._points[0, 1] = val - self.invalidate() - ymin = property(BboxBase._get_ymin, _set_ymin) - - def _set_xmax(self, val): - self._points[1, 0] = val - self.invalidate() - xmax = property(BboxBase._get_xmax, _set_xmax) - - def _set_ymax(self, val): - self._points[1, 1] = val - self.invalidate() - ymax = property(BboxBase._get_ymax, _set_ymax) - - def _set_min(self, val): - self._points[0] = val - self.invalidate() - min = property(BboxBase._get_min, _set_min) - - def _set_max(self, val): - self._points[1] = val - self.invalidate() - max = property(BboxBase._get_max, _set_max) - - def _set_intervalx(self, interval): - self._points[:, 0] = interval - self.invalidate() - intervalx = property(BboxBase._get_intervalx, _set_intervalx) - - def _set_intervaly(self, interval): - self._points[:, 1] = interval - self.invalidate() - intervaly = property(BboxBase._get_intervaly, _set_intervaly) - - def _set_bounds(self, bounds): - l,b,w,h = bounds - self._points = npy.array([[l, b], [l+w, b+h]], npy.float_) - self.invalidate() - bounds = property(BboxBase._get_bounds, _set_bounds) - - def get_points(self): - return self._points - - def set_points(self, points): - self._points = points - self.invalidate() - - def set(self, other): - self._points = other.get_points() - self.invalidate() - - def transformed(self, transform): - return Bbox(transform(self._points)) - - def inverse_transformed(self, transform): - return Bbox(transform.inverted()(self._points)) - - def expanded(self, sw, sh): - width = self.width - height = self.height - deltaw = (sw * width - width) / 2.0 - deltah = (sh * height - height) / 2.0 - a = npy.array([[-deltaw, -deltah], [deltaw, deltah]]) - return Bbox(self._points + a) - - #@staticmethod - def union(bboxes): - """ - Return the Bbox that bounds all bboxes - """ - assert(len(bboxes)) - - if len(bboxes) == 1: - return bboxes[0] - - bbox = bboxes[0] - xmin = bbox.xmin - ymin = bbox.ymin - xmax = bbox.xmax - ymax = bbox.ymax - - for bbox in bboxes[1:]: - xmin = min(xmin, bbox.xmin) - ymin = min(ymin, bbox.ymin) - xmax = max(xmax, bbox.xmax) - ymax = max(ymax, bbox.ymax) - - return Bbox.from_lbrt(xmin, ymin, xmax, ymax) - union = staticmethod(union) - -class TransformedBbox(BboxBase): - def __init__(self, bbox, transform): - assert isinstance(bbox, Bbox) - assert isinstance(transform, Transform) - - BboxBase.__init__(self) - self.bbox = bbox - self.transform = transform - self.set_children(['bbox', 'transform']) - self._points = None - - def __repr__(self): - return "TransformedBbox(%s, %s)" % (self.bbox, self.transform) - __str__ = __repr__ - - def _do_invalidation(self): - self._points = None - - def get_points(self): - if self._points is None: - self._points = self.transform(self.bbox.get_points()) - return self._points - -# MGDTODO: This code probably works, but I don't think it's a good idea -# (from a code clarity perspective) -# class BlendedBbox(BboxBase): -# def __init__(self, bbox_x, bbox_y): -# assert isinstance(bbox_x, BboxBase) -# assert isinstance(bbox_y, BboxBase) - -# BboxBase.__init__(self) -# self._x = bbox_x -# self._y = bbox_y -# self.set_children(['_x', '_y']) -# self._points = None - -# def __repr__(self): -# return "TransformedBbox(%s, %s)" % (self.bbox, self.transform) -# __str__ = __repr__ - -# def _do_invalidation(self): -# self._points = None - -# def get_points(self): -# if self._points is None: -# # MGDTODO: Optimize -# if self._x == self._y: -# self._points = self._x.get_points() -# else: -# x_points = self._x.get_points() -# y_points = self._y.get_points() -# self._points = npy.array( -# [[x_points[0,0], y_points[0,1]], -# [x_points[1,0], y_points[1,1]]], -# npy.float_) -# return self._points - -# def _set_intervalx(self, pair): -# # MGDTODO: Optimize -# bbox = Bbox([[pair[0], 0.0], [pair[1], 0.0]]) -# self.replace_child(0, bbox) -# intervalx = property(BboxBase._get_intervalx, _set_intervalx) - -# def _set_intervaly(self, pair): -# # MGDTODO: Optimize -# bbox = Bbox([[0.0, pair[0]], [0.0, pair[1]]]) -# self.replace_child(1, bbox) -# intervaly = property(BboxBase._get_intervaly, _set_intervaly) - -class Transform(TransformNode): - def __init__(self): - TransformNode.__init__(self) - - def __call__(self, points): - raise NotImplementedError() - - def __add__(self, other): - if isinstance(other, Transform): - return composite_transform_factory(self, other) - raise TypeError( - "Can not add Transform to object of type '%s'" % type(other)) - - def __radd__(self, other): - if isinstance(other, Transform): - return composite_transform_factory(other, self) - raise TypeError( - "Can not add Transform to object of type '%s'" % type(other)) - - def transform_point(self, point): - return self.__call__(npy.asarray([point]))[0] - - def has_inverse(self): - raise NotImplementedError() - - def inverted(self): - raise NotImplementedError() - - def is_separable(self): - return False - - def is_affine(self): - return False - -class Affine2DBase(Transform): - input_dims = 2 - output_dims = 2 - - def __init__(self): - Transform.__init__(self) - self._inverted = None - - def _do_invalidation(self): - result = self._inverted is None - self._inverted = None - return result - - #@staticmethod - def _concat(a, b): - return npy.dot(b, a) - _concat = staticmethod(_concat) - - #@staticmethod - def concat(a, b): - return Affine2D(Affine2D._concat(a.get_matrix(), b.get_matrix())) - concat = staticmethod(concat) - - def to_values(self): - mtx = self.get_matrix() - return tuple(mtx[:2].swapaxes(0, 1).flatten()) - - #@staticmethod - def matrix_from_values(a, b, c, d, e, f): - affine = npy.zeros((3, 3), npy.float_) - affine[0, ] = a, c, e - affine[1, ] = b, d, f - affine[2, 2] = 1 - return affine - matrix_from_values = staticmethod(matrix_from_values) - - def get_matrix(self): - raise NotImplementedError() - - def __call__(self, points): - """ - Applies the transformation to an array of 2D points and - returns the result. - - points must be a numpy array of shape (N, 2), where N is the - number of points. - """ - # MGDTODO: The major speed trap here is just converting to - # the points to an array in the first place. If we can use - # more arrays upstream, that should help here. - if not isinstance(points, npy.ndarray): - import traceback - print '-' * 60 - print 'A non-numpy array was passed in for transformation. Please ' - print 'correct this.' - print "".join(traceback.format_stack()) - print points - mtx = self.get_matrix() - points = npy.asarray(points, npy.float_) - points = points.transpose() - points = npy.dot(mtx[0:2, 0:2], points) - points = points + mtx[0:2, 2:] - return points.transpose() - - def inverted(self): - if self._inverted is None: - mtx = self.get_matrix() - self._inverted = Affine2D(inv(mtx)) - return self._inverted - - def is_separable(self): - mtx = self.get_matrix() - return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0 - - def is_affine(self): - return True - - -class Affine2D(Affine2DBase): - input_dims = 2 - output_dims = 2 - - def __init__(self, matrix = None): - """ - Initialize an Affine transform from a 3x3 numpy float array. - - a c e - b d f - 0 0 1 - """ - Affine2DBase.__init__(self) - if matrix is None: - matrix = npy.identity(3) - else: - assert matrix.shape == (3, 3) - self._mtx = matrix - self._inverted = None - - def __repr__(self): - return "Affine2D(%s)" % repr(self._mtx) - __str__ = __repr__ - - def __cmp__(self, other): - if (isinstance(other, Affine2D) and - (self.get_matrix() == other.get_matrix()).all()): - return 0 - return -1 - - def __copy__(self): - return Affine2D(self._mtx.copy()) - - def __deepcopy__(self, memo): - return Affine2D(self._mtx.copy()) - - #@staticmethod - def from_values(a, b, c, d, e, f): - return Affine2D(Affine2D.matrix_from_values(a, b, c, d, e, f)) - from_values = staticmethod(from_values) - - def get_matrix(self): - return self._mtx - - def set_matrix(self, mtx): - self._mtx = mtx - self.invalidate() - - def set(self, other): - self._mtx = other.get_matrix() - self.invalidate() - - #@staticmethod - def identity(): - return Affine2D(npy.identity(3)) - identity = staticmethod(identity) - - def clear(self): - self._mtx = npy.identity(3) - self.invalidate() - return self - - def rotate(self, theta): - a = npy.cos(theta) - b = npy.sin(theta) - rotate_mtx = self.matrix_from_values(a, b, -b, a, 0, 0) - self._mtx = self._concat(self._mtx, rotate_mtx) - self.invalidate() - return self - - def rotate_deg(self, degrees): - return self.rotate(degrees*npy.pi/180.) - - def rotate_around(self, x, y, theta): - return self.translate(-x, -y).rotate(theta).translate(x, y) - - def rotate_deg_around(self, x, y, degrees): - return self.translate(-x, -y).rotate_deg(degrees).translate(x, y) - - def translate(self, tx, ty): - translate_mtx = self.matrix_from_values(1., 0., 0., 1., tx, ty) - self._mtx = self._concat(self._mtx, translate_mtx) - self.invalidate() - return self - - def scale(self, sx, sy=None): - if sy is None: - sy = sx - scale_mtx = self.matrix_from_values(sx, 0., 0., sy, 0., 0.) - self._mtx = self._concat(self._mtx, scale_mtx) - self.invalidate() - return self - - def inverted(self): - if self._inverted is None: - mtx = self.get_matrix() - self._inverted = Affine2D(inv(mtx)) - return self._inverted - - def is_separable(self): - mtx = self.get_matrix() - return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0 - - def is_affine(self): - return True - -class BlendedTransform(Transform): - def __init__(self, x_transform, y_transform): - assert x_transform.is_separable() - assert y_transform.is_separable() - - Transform.__init__(self) - self._x = x_transform - self._y = y_transform - self.set_children(['_x', '_y']) - - def __call__(self, points): - if self._x == self._y: - return self._x(points) - - x_points = self._x(points) - y_points = self._y(points) - # This works because we already know the transforms are - # separable - return npy.hstack((x_points[:, 0:1], y_points[:, 1:2])) - -# def set_x_transform(self, x_transform): -# self.replace_child(0, x_transform) - -# def set_y_transform(self, y_transform): -# self.replace_child(1, y_transform) - -class BlendedAffine2D(Affine2DBase, BlendedTransform): - def __init__(self, x_transform, y_transform): - assert x_transform.is_affine() - assert y_transform.is_affine() - assert x_transform.is_separable() - assert y_transform.is_separable() - BlendedTransform.__init__(self, x_transform, y_transform) - - Affine2DBase.__init__(self) - self._mtx = None - - def __repr__(self): - return "BlendedAffine2D(%s,%s)" % (self._x, self._y) - __str__ = __repr__ - - def _do_invalidation(self): - if self._mtx is not None: - self._mtx = None - Affine2DBase._do_invalidation(self) - return False - return True - - def is_separable(self): - return True - - def get_matrix(self): - if self._mtx is None: - if self._x == self._y: - self._mtx = self._x.get_matrix() - else: - x_mtx = self._x.get_matrix() - y_mtx = self._y.get_matrix() - # This works because we already know the transforms are - # separable, though normally one would want to set b and - # c to zero. - self._mtx = npy.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0])) - return self._mtx - -class CompositeTransform(Transform): - def __init__(self, a, b): - assert a.output_dims == b.input_dims - self.input_dims = a.input_dims - self.output_dims = b.output_dims - - Transform.__init__(self) - self._a = a - self._b = b - self.set_children(['_a', '_b']) - - def __call__(self, points): - return self._b(self._a(points)) - -class CompositeAffine2D(Affine2DBase): - def __init__(self, a, b): - assert a.is_affine() - assert b.is_affine() - - Affine2DBase.__init__(self) - self._a = a - self._b = b - self.set_children(['_a', '_b']) - self._mtx = None - - def __repr__(self): - return "CompositeAffine2D(%s, %s)" % (self._a, self._b) - __str__ = __repr__ - - def _do_invalidation(self): - self._mtx = None - Affine2DBase._do_invalidation(self) - - def get_matrix(self): - if self._mtx is None: - self._mtx = self._concat( - self._a.get_matrix(), - self._b.get_matrix()) - return self._mtx - -class BboxTransform(Affine2DBase): - def __init__(self, boxin, boxout): - assert isinstance(boxin, BboxBase) - assert isinstance(boxout, BboxBase) - - Affine2DBase.__init__(self) - self._boxin = boxin - self._boxout = boxout - self.set_children(['_boxin', '_boxout']) - self._mtx = None - self._inverted = None - - def __repr__(self): - return "BboxTransform(%s, %s)" % (self._boxin, self._boxout) - __str__ = __repr__ - - def _do_invalidation(self): - if self._mtx is not None: - self._mtx = None - Affine2DBase._do_invalidation(self) - return False - return True - - def is_separable(self): - return True - - def get_matrix(self): - if self._mtx is None: - boxin = self._boxin - boxout = self._boxout - x_scale = boxout.width / boxin.width - y_scale = boxout.height / boxin.height - - # MGDTODO: Optimize - affine = Affine2D() \ - .translate(-boxin.xmin, -boxin.ymin) \ - .scale(x_scale, y_scale) \ - .translate(boxout.xmin, boxout.ymin) - - self._mtx = affine._mtx - return self._mtx - -def blend_xy_sep_transform(x_transform, y_transform): - if x_transform.is_affine() and y_transform.is_affine(): - return BlendedAffine2D(x_transform, y_transform) - return BlendedTransform(x_transform, y_transform) - -def composite_transform_factory(a, b): - if a.is_affine() and b.is_affine(): - return CompositeAffine2D(a, b) - return CompositeTransform(a, b) - -# MGDTODO: There's probably a better place for this -def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True): - ''' - Ensure the endpoints of a range are not too close together. - - "too close" means the interval is smaller than 'tiny' times - the maximum absolute value. - - If they are too close, each will be moved by the 'expander'. - If 'increasing' is True and vmin > vmax, they will be swapped, - regardless of whether they are too close. - ''' - swapped = False - if vmax < vmin: - vmin, vmax = vmax, vmin - swapped = True - if vmax - vmin <= max(abs(vmin), abs(vmax)) * tiny: - if vmin == 0.0: - vmin = -expander - vmax = expander - else: - vmin -= expander*abs(vmin) - vmax += expander*abs(vmax) - if swapped and not increasing: - vmin, vmax = vmax, vmin - return vmin, vmax - -# MGDTODO: Optimize -def interval_contains(interval, val): - return interval[0] <= val and interval[1] >= val - -def interval_contains_open(interval, val): - return interval[0] < val and interval[1] > val - -if __name__ == '__main__': - import copy - from random import random - import timeit - - bbox = Bbox.from_lbrt(10., 15., 20., 25.) - assert bbox.xmin == 10 - assert bbox.ymin == 15 - assert bbox.xmax == 20 - assert bbox.ymax == 25 - - assert npy.all(bbox.min == [10, 15]) - assert npy.all(bbox.max == [20, 25]) - assert npy.all(bbox.intervalx == (10, 20)) - assert npy.all(bbox.intervaly == (15, 25)) - - assert bbox.width == 10 - assert bbox.height == 10 - - assert bbox.bounds == (10, 15, 10, 10) - - print npy.asarray(bbox) - - bbox.intervalx = (11, 21) - bbox.intervaly = (16, 26) - - assert bbox.bounds == (11, 16, 10, 10) - - bbox.xmin = 12 - bbox.ymin = 17 - bbox.xmax = 22 - bbox.ymax = 27 - - assert bbox.bounds == (12, 17, 10, 10) - - bbox = Bbox.from_lbwh(10, 11, 12, 13) - assert bbox.bounds == (10, 11, 12, 13) - - bbox_copy = copy.copy(bbox) - assert bbox == bbox_copy - bbox_copy.max = (14, 15) - assert bbox.bounds == (10, 11, 12, 13) - assert bbox_copy.bounds == (10, 11, 4, 4) - - bbox1 = Bbox([[10., 15.], [20., 25.]]) - bbox2 = Bbox([[30., 35.], [40., 45.]]) - trans = BboxTransform(bbox1, bbox2) - bbox3 = bbox1.transformed(trans) - assert bbox3 == bbox2 - - translation = Affine2D().translate(10, 20) - assert translation.to_values() == (1, 0, 0, 1, 10, 20) - scale = Affine2D().scale(10, 20) - assert scale.to_values() == (10, 0, 0, 20, 0, 0) - rotation = Affine2D().rotate_deg(30) - print rotation.to_values() == (0.86602540378443871, 0.49999999999999994, - -0.49999999999999994, 0.86602540378443871, - 0.0, 0.0) - - points = npy.array([[1,2],[3,4],[5,6],[7,8]], npy.float_) - translated_points = translation(points) - assert (translated_points == [[11., 22.], [13., 24.], [15., 26.], [17., 28.]]).all() - scaled_points = scale(points) - print scaled_points - rotated_points = rotation(points) - print rotated_points - - tpoints1 = rotation(translation(scale(points))) - trans_sum = scale + translation + rotation - tpoints2 = trans_sum(points) - print tpoints1, tpoints2 - print tpoints1 == tpoints2 - # Need to do some sort of fuzzy comparison here? - # assert (tpoints1 == tpoints2).all() - - # Here are some timing tests - points = npy.asarray([(random(), random()) for i in xrange(10000)]) - t = timeit.Timer("trans_sum(points)", "from __main__ import trans_sum, points") - print "Time to transform 10000 x 10 points:", t.timeit(10) - -__all__ = ['Transform', 'Affine2D'] Modified: branches/transforms/lib/matplotlib/artist.py =================================================================== --- branches/transforms/lib/matplotlib/artist.py 2007-09-14 12:24:20 UTC (rev 3850) +++ branches/transforms/lib/matplotlib/artist.py 2007-09-14 13:03:31 UTC (rev 3851) @@ -1,7 +1,7 @@ from __future__ import division import sys, re from cbook import iterable, flatten -from affine import Affine2D +from transforms import Affine2D import matplotlib.units as units ## Note, matplotlib artists use the doc strings for set and get Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-09-14 12:24:20 UTC (rev 3850) +++ branches/transforms/lib/matplotlib/axes.py 2007-09-14 13:03:31 UTC (rev 3851) @@ -9,7 +9,6 @@ rcParams = matplotlib.rcParams from matplotlib import artist as martist -from matplotlib import affine as maffine from matplotlib import agg from matplotlib import axis as maxis from matplotlib import cbook @@ -29,6 +28,7 @@ from matplotlib import table as mtable from matplotlib import text as mtext from matplotlib import ticker as mticker +from matplotlib import transforms as mtransforms iterable = cbook.iterable is_string_like = cbook.is_string_like @@ -481,7 +481,7 @@ """ martist.Artist.__init__(self) - self._position = maffine.Bbox.from_lbwh(*rect) + self._position = mtransforms.Bbox.from_lbwh(*rect) self._originalPosition = copy.deepcopy(self._position) self.set_axes(self) self.set_aspect('auto') @@ -612,7 +612,7 @@ """ martist.Artist.set_figure(self, fig) - self.bbox = maffine.TransformedBbox(self._position, fig.transFigure) + self.bbox = mtransforms.TransformedBbox(self._position, fig.transFigure) #these will be updated later as data is added self._set_lim_and_transforms() @@ -631,7 +631,7 @@ set the dataLim and viewLim BBox attributes and the transData and transAxes Transformation attributes """ - Bbox = maffine.Bbox + Bbox = mtransforms.Bbox self.viewLim = Bbox.unit() if self._sharex is not None: @@ -647,20 +647,11 @@ self.dataLim = Bbox.unit() - self.transAxes = maffine.BboxTransform( + self.transAxes = mtransforms.BboxTransform( Bbox.unit(), self.bbox) - localTransData = maffine.BboxTransform( + self.transData = mtransforms.BboxTransform( self.viewLim, self.bbox) - if self._sharex: - transDataX = self._sharex.transData - else: - transDataX = localTransData - if self._sharey: - transDataY = self._sharey.transData - else: - transDataY = localTransData - self.transData = localTransData # maffine.blend_xy_sep_transform(transDataX, transDataY) def get_position(self, original=False): @@ -1538,7 +1529,7 @@ # and min(xmin, xmax)<=0): # raise ValueError('Cannot set nonpositive limits with log transform') - xmin, xmax = maffine.nonsingular(xmin, xmax, increasing=False) + xmin, xmax = mtransforms.nonsingular(xmin, xmax, increasing=False) self.viewLim.intervalx = (xmin, xmax) if emit: @@ -1670,7 +1661,7 @@ # and min(ymin, ymax)<=0): # raise ValueError('Cannot set nonpositive limits with log transform') - ymin, ymax = maffine.nonsingular(ymin, ymax, increasing=False) + ymin, ymax = mtransforms.nonsingular(ymin, ymax, increasing=False) self.viewLim.intervaly = (ymin, ymax) if emit: self.callbacks.process('ylim_changed', self) @@ -2167,7 +2158,7 @@ %(Annotation)s """ a = mtext.Annotation(*args, **kwargs) - a.set_transform(maffine.Affine2D()) + a.set_transform(mtransforms.Affine2D()) self._set_artist_props(a) if kwargs.has_key('clip_on'): a.set_clip_box(self.bbox) self.texts.append(a) @@ -2206,7 +2197,7 @@ %(Line2D)s """ - trans = maffine.blend_xy_sep_transform(self.transAxes, self.transData) + trans = mtransforms.blend_xy_sep_transform(self.transAxes, self.transData) l, = self.plot([xmin,xmax], [y,y], transform=trans, scalex=False, **kwargs) return l @@ -2242,7 +2233,7 @@ %(Line2D)s """ - trans = maffine.blend_xy_sep_transform( self.transData, self.transAxes ) + trans = mtransforms.blend_xy_sep_transform( self.transData, self.transAxes ) l, = self.plot([x,x], [ymin,ymax] , transform=trans, scaley=False, **kwargs) return l @@ -2281,7 +2272,7 @@ %(Polygon)s """ # convert y axis units - trans = maffine.blend_xy_sep_transform( self.transAxes, self.transData) + trans = mtransforms.blend_xy_sep_transform( self.transAxes, self.transData) verts = (xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin) p = mpatches.Polygon(verts, **kwargs) p.set_transform(trans) @@ -2321,7 +2312,7 @@ %(Polygon)s """ # convert x axis units - trans = maffine.blend_xy_sep_transform(self.transData, self.transAxes) + trans = mtransforms.blend_xy_sep_transform(self.transData, self.transAxes) verts = [(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)] p = mpatches.Polygon(verts, **kwargs) p.set_transform(trans) @@ -4104,7 +4095,7 @@ offsets = zip(x,y), transOffset = self.transData, ) - collection.set_transform(maffine.Affine2D()) + collection.set_transform(mtransforms.Affine2D()) collection.set_alpha(alpha) collection.update(kwargs) Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-09-14 12:24:20 UTC (rev 3850) +++ branches/transforms/lib/matplotlib/axis.py 2007-09-14 13:03:31 UTC (rev 3851) @@ -15,10 +15,10 @@ from ticker import NullFormatter, FixedFormatter, ScalarFormatter, LogFormatter from ticker import NullLocator, FixedLocator, LinearLocator, LogLocator, AutoLocator -from affine import Affine2D, Bbox, blend_xy_sep_transform, interval_contains, \ - interval_contains_open from font_manager import FontProperties from text import Text, TextWithDash, _process_text_args +from transforms import Affine2D, Bbox, blended_transform_factory, interval_contains, \ + interval_contains_open from patches import bbox_artist import matplotlib.units as units @@ -236,7 +236,7 @@ xaxis=True, ) - trans = blend_xy_sep_transform( + trans = blended_transform_factory( self.axes.transData, self.axes.transAxes) #offset the text downward with a post transformation trans = trans + Affine2D().translate(0, -1 * self._padPixels) @@ -261,7 +261,7 @@ horizontalalignment='center', ) - trans = blend_xy_sep_transform( + trans = blended_transform_factory( self.axes.transData, self.axes.transAxes) # offset the text upward with a post transformation trans = trans + Affine2D().translate(0, self._padPixels) @@ -279,7 +279,7 @@ marker = self._xtickmarkers[0], markersize=self._size, ) - l.set_transform(blend_xy_sep_transform( + l.set_transform(blended_transform_factory( self.axes.transData, self.axes.transAxes) ) self._set_artist_props(l) return l @@ -295,7 +295,7 @@ markersize=self._size, ) - l.set_transform(blend_xy_sep_transform( + l.set_transform(blended_transform_factory( self.axes.transData, self.axes.transAxes) ) self._set_artist_props(l) return l @@ -310,7 +310,7 @@ antialiased=False, ) l.set_transform( - blend_xy_sep_transform( + blended_transform_factory( self.axes.transData, self.axes.transAxes)) l.set_clip_box(self.axes.bbox) self._set_artist_props(l) @@ -359,7 +359,7 @@ dashdirection=0, xaxis=False, ) - trans = blend_xy_sep_transform( + trans = blended_transform_factory( self.axes.transAxes, self.axes.transData) # offset the text leftward with a post transformation trans = trans + Affine2D().translate(-1 * self._padPixels, 0) @@ -382,7 +382,7 @@ xaxis=False, horizontalalignment='left', ) - trans = blend_xy_sep_transform( + trans = blended_transform_factory( self.axes.transAxes, self.axes.transData) # offset the text rightward with a post transformation trans = trans + Affine2D().translate(self._padPixels, 0) @@ -401,7 +401,7 @@ markersize=self._size, ) l.set_transform( - blend_xy_sep_transform( + blended_transform_factory( self.axes.transAxes, self.axes.transData)) self._set_artist_props(l) return l @@ -417,7 +417,7 @@ ) l.set_transform( - blend_xy_sep_transform( + blended_transform_factory( self.axes.transAxes, self.axes.transData)) self._set_artist_props(l) return l @@ -432,7 +432,7 @@ antialiased=False, ) - l.set_transform( blend_xy_sep_transform( + l.set_transform( blended_transform_factory( self.axes.transAxes, self.axes.transData) ) l.set_clip_box(self.axes.bbox) @@ -979,7 +979,7 @@ verticalalignment='top', horizontalalignment='center', ) - label.set_transform( blend_xy_sep_transform( + label.set_transform( blended_transform_factory( self.axes.transAxes, Affine2D() )) self._set_artist_props(label) @@ -994,7 +994,7 @@ verticalalignment='top', horizontalalignment='right', ) - offsetText.set_transform( blend_xy_sep_transform( + offsetText.set_transform( blended_transform_factory( self.axes.transAxes, Affine2D() )) self._set_artist_props(offsetText) self.offset_text_position='bottom' @@ -1169,7 +1169,7 @@ horizontalalignment='right', rotation='vertical', ) - label.set_transform( blend_xy_sep_transform( + label.set_transform( blended_transform_factory( Affine2D(), self.axes.transAxes) ) self._set_artist_props(label) @@ -1184,7 +1184,7 @@ verticalalignment = 'bottom', horizontalalignment = 'left', ) - offsetText.set_transform(blend_xy_sep_transform( + offsetText.set_transform(blended_transform_factory( self.axes.transAxes, Affine2D()) ) self._set_artist_props(offsetText) self.offset_text_position='left' Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-14 12:24:20 UTC (rev 3850) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-14 13:03:31 UTC (rev 3851) @@ -84,7 +84,7 @@ from matplotlib.font_manager import findfont from matplotlib.ft2font import FT2Font, LOAD_DEFAULT from matplotlib.mathtext import MathTextParser -from matplotlib.affine import Bbox +from matplotlib.transforms import Bbox from _backend_agg import RendererAgg as _RendererAgg @@ -115,15 +115,10 @@ 'debug-annoying') # self.draw_polygon = self._renderer.draw_polygon self.draw_rectangle = self._renderer.draw_rectangle - self.draw_path = self._renderer.draw_path # MGDTODO -- remove these lines # self.draw_lines = self._renderer.draw_lines # self.draw_markers = self._renderer.draw_markers self.draw_image = self._renderer.draw_image - self.draw_line_collection = self._renderer.draw_line_collection - self.draw_quad_mesh = self._renderer.draw_quad_mesh - self.draw_poly_collection = self._renderer.draw_poly_collection - self.draw_regpoly_collection = self._renderer.draw_regpoly_collection self.copy_from_bbox = self._renderer.copy_from_bbox self.restore_region = self._renderer.restore_region Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-09-14 12:24:20 UTC (rev 3850) +++ branches/transforms/lib/matplotlib/figure.py 2007-09-14 13:03:31 UTC (rev 3851) @@ -18,8 +18,8 @@ from text import Text, _process_text_args from legend import Legend -from affine import Affine2D, Bbox, BboxTransform, TransformedBbox from ticker import FormatStrFormatter +from transforms import Affine2D, Bbox, BboxTransform, TransformedBbox from cm import ScalarMappable from contour import ContourSet import warnings Modified: branches/transforms/lib/matplotlib/finance.py =================================================================== --- branches/transforms/lib/matplotlib/finance.py 2007-09-14 12:24:20 UTC (rev 3850) +++ branches/transforms/lib/matplotlib/finance.py 2007-09-14 13:03:31 UTC (rev 3851) @@ -22,7 +22,7 @@ from matplotlib.colors import colorConverter from lines import Line2D, TICKLEFT, TICKRIGHT from patches import Rectangle -from matplotlib.affine import Affine2D +from matplotlib.transforms import Affine2D Modified: branches/transforms/lib/matplotlib/legend.py =================================================================== --- branches/transforms/lib/matplotlib/legend.py 2007-09-14 12:24:20 UTC (rev 3850) +++ branches/transforms/lib/matplotlib/legend.py 2007-09-14 13:03:31 UTC (rev 3851) @@ -34,7 +34,7 @@ from patches import Patch, Rectangle, RegularPolygon, Shadow, bbox_artist, draw_bbox from collections import LineCollection, RegularPolyCollection, PatchCollection from text import Text -from affine import Bbox, BboxTransform +from transforms import Bbox, BboxTransform def line_cuts_bbox(line, bbox): """ Return True if and only if line cuts bbox. """ Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-09-14 12:24:20 UTC (rev 3850) +++ branches/transforms/lib/matplotlib/lines.py 2007-09-14 13:03:31 UTC (rev 3851) @@ -14,10 +14,10 @@ import numerix.ma as ma from matplotlib import verbose import artist -from affine import Bbox from artist import Artist, setp from cbook import iterable, is_string_like, is_numlike from colors import colorConverter +from transforms import Bbox from matplotlib import rcParams Modified: branches/transforms/lib/matplotlib/table.py =================================================================== --- branches/transforms/lib/matplotlib/table.py 2007-09-14 12:24:20 UTC (rev 3850) +++ branches/transforms/lib/matplotlib/table.py 2007-09-14 13:03:31 UTC (rev 3851) @@ -29,7 +29,7 @@ from patches import Rectangle from cbook import enumerate, is_string_like, flatten from text import Text -from affine import Bbox +from transforms import Bbox Modified: branches/transforms/lib/matplotlib/text.py =================================================================== --- branches/transforms/lib/matplotlib/text.py 2007-09-14 12:24:20 UTC (rev 3850) +++ branches/transforms/lib/matplotlib/text.py 2007-09-14 13:03:31 UTC (rev 3851) @@ -15,7 +15,7 @@ from cbook import enumerate, is_string_like, maxdict, is_numlike from font_manager import FontProperties from patches import bbox_artist, YAArrow -from affine import Affine2D, Bbox +from transforms import Affine2D, Bbox from lines import Line2D import matplotlib.nxutils as nxutils Modified: branches/transforms/lib/matplotlib/ticker.py =================================================================== --- branches/transforms/lib/matplotlib/ticker.py 2007-09-14 12:24:20 UTC (rev 3850) +++ branches/transforms/lib/matplotlib/ticker.py 2007-09-14 13:03:31 UTC (rev 3851) @@ -109,7 +109,7 @@ import matplotlib as mpl from matplotlib import verbose, rcParams from matplotlib import cbook -from matplotlib import affine as maffine +from matplotlib import transforms as mtransforms @@ -540,7 +540,7 @@ def autoscale(self): 'autoscale the view limits' self.verify_intervals() - return maffine.nonsingular(*self.dataInterval.get_bounds()) + return mtransforms.nonsingular(*self.dataInterval.get_bounds()) def pan(self, numsteps): 'Pan numticks (can be positive or negative)' @@ -682,7 +682,7 @@ vmin = math.floor(scale*vmin)/scale vmax = math.ceil(scale*vmax)/scale - return maffine.nonsingular(vmin, vmax) + return mtransforms.nonsingular(vmin, vmax) def closeto(x,y): @@ -766,7 +766,7 @@ vmin -=1 vmax +=1 - return maffine.nonsingular(vmin, vmax) + return mtransforms.nonsingular(vmin, vmax) def scale_range(vmin, vmax, n = 1, threshold=100): dv = abs(vmax - vmin) @@ -833,12 +833,12 @@ def __call__(self): vmin, vmax = self.axis.get_view_interval() - vmin, vmax = maffine.nonsingular(vmin, vmax, expander = 0.05) + vmin, vmax = mtransforms.nonsingular(vmin, vmax, expander = 0.05) return self.bin_boundaries(vmin, vmax) def autoscale(self): dmin, dmax = self.axis.get_data_interval() - dmin, dmax = maffine.nonsingular(dmin, dmax, expander = 0.05) + dmin, dmax = mtransforms.nonsingular(dmin, dmax, expander = 0.05) return npy.take(self.bin_boundaries(dmin, dmax), [0,-1]) @@ -939,7 +939,7 @@ if vmin==vmax: vmin = decade_down(vmin,self._base) vmax = decade_up(vmax,self._base) - return maffine.nonsingular(vmin, vmax) + return mtransforms.nonsingular(vmin, vmax) class AutoLocator(MaxNLocator): def __init__(self): Copied: branches/transforms/lib/matplotlib/transforms.py (from rev 3849, branches/transforms/lib/matplotlib/affine.py) =================================================================== --- branches/transforms/lib/matplotlib/transforms.py (rev 0) +++ branches/transforms/lib/matplotlib/transforms.py 2007-09-14 13:03:31 UTC (rev 3851) @@ -0,0 +1,852 @@ +""" +A set of classes to handle transformations. + +2007 Michael Droettboom +""" + +import numpy as npy +from numpy.linalg import inv +from sets import Set + +# MGDTODO: This creates a ton of cyclical references. We may want to +# consider using weak references + +# MGDTODO: deep copying is probably incorrect wrt the parent/child +# relationships + +class TransformNode(object): + def __init__(self): + self._parents = Set() + + def invalidate(self): + if not self._do_invalidation(): + for parent in self._parents: + parent.invalidate() + + def _do_invalidation(self): + return False + + def set_children(self, children): + for child in children: + getattr(self, child)._parents.add(self) + self._children = children + + # MGDTODO: decide whether we need this in-place updating and + # remove if not +# def replace_child(self, index, child): +# children = self._children +# getattr(self, children[index])._parents.remove(self) +# setattr(self, children[index], child) +# # We have to reset children in case two or more +# # of the children are the same +# for child in children: +# getattr(self, child)._parents.add(self) +# self.invalidate() + +class BboxBase(TransformNode): + ''' + This is the read-only part of a bounding-box + ''' + + def __init__(self): + TransformNode.__init__(self) + + def __array__(self): + return self.get_points() + + # MGDTODO: Probably a more efficient ways to do this... + def _get_xmin(self): + return self.get_points()[0, 0] + xmin = property(_get_xmin) + + def _get_ymin(self): + return self.get_points()[0, 1] + ymin = property(_get_ymin) + + def _get_xmax(self): + return self.get_points()[1, 0] + xmax = property(_get_xmax) + + def _get_ymax(self): + return self.get_points()[1, 1] + ymax = property(_get_ymax) + + def _get_min(self): + return self.get_points()[0] + min = property(_get_min) + + def _get_max(self): + return self.get_points()[1] + max = property(_get_max) + + def _get_intervalx(self): + return self.get_points()[:, 0] + intervalx = property(_get_intervalx) + + def _get_intervaly(self): + return self.get_points()[:, 1] + intervaly = property(_get_intervaly) + + def _get_width(self): + return self.xmax - self.xmin + width = property(_get_width) + + def _get_height(self): + return self.ymax - self.ymin + height = property(_get_height) + + def _get_bounds(self): + return (self.xmin, self.ymin, + self.xmax - self.xmin, self.ymax - self.ymin) + bounds = property(_get_bounds) + + def get_points(self): + return NotImplementedError() + + # MGDTODO: Optimize + def containsx(self, x): + return x >= self.xmin and x <= self.xmax + + def containsy(self, y): + return y >= self.ymin and y <= self.ymax + + def contains(self, x, y): + return self.containsx(x) and self.containsy(y) + + def overlapsx(self, other): + return self.containsx(other.xmin) \ + or self.containsx(other.xmax) + + def overlapsy(self, other): + return self.containsy(other.ymin) \ + or self.containsx(other.ymax) + + def overlaps(self, other): + return self.overlapsx(other) \ + and self.overlapsy(other) + + def fully_containsx(self, x): + return x > self.xmin and x < self.xmax + + def fully_containsy(self, y): + return y > self.ymin and y < self.ymax + + def fully_contains(self, x, y): + return self.fully_containsx(x) \ + and self.fully_containsy(y) + + def fully_overlapsx(self, other): + return self.fully_containsx(other.xmin) \ + or self.fully_containsx(other.xmax) + + def fully_overlapsy(self, other): + return self.fully_containsy(other.ymin) \ + or self.fully_containsx(other.ymax) + + def fully_overlaps(self, other): + return self.fully_overlapsx(other) and \ + self.fully_overlapsy(other) + + +class Bbox(BboxBase): + def __init__(self, points): + BboxBase.__init__(self) + self._points = npy.asarray(points, npy.float_) + + #@staticmethod + def unit(): + return Bbox.from_lbrt(0., 0., 1., 1.) + unit = staticmethod(unit) + + #@staticmethod + def from_lbwh(left, bottom, width, height): + return Bbox.from_lbrt(left, bottom, left + width, bottom + height) + from_lbwh = staticmethod(from_lbwh) + + #@staticmethod + def from_lbrt(*args): + points = npy.array(args, dtype=npy.float_).reshape(2, 2) + return Bbox(points) + from_lbrt = staticmethod(from_lbrt) + + def __copy__(self): + return Bbox(self._points.copy()) + + def __deepcopy__(self, memo): + return Bbox(self._points.copy()) + + def __cmp__(self, other): + # MGDTODO: Totally suboptimal + if isinstance(other, Bbox) and (self._points == other._points).all(): + return 0 + return -1 + + def __repr__(self): + return 'Bbox(%s)' % repr(self._points) + __str__ = __repr__ + + # JDH: the update method will update the box limits from the + # existing limits and the new data; it appears here you are just + # using the new data. We use an "ignore" flag to specify whether + # you want to include the existing data or not in the update + def update_from_data(self, x, y, ignore=True): + self._points = npy.array( + [[x.min(), y.min()], [x.max(), y.max()]], + npy.float_) + self.invalidate() + + # MGDTODO: Probably a more efficient ways to do this... + def _set_xmin(self, val): + self._points[0, 0] = val + self.invalidate() + xmin = property(BboxBase._get_xmin, _set_xmin) + + def _set_ymin(self, val): + self._points[0, 1] = val + self.invalidate() + ymin = property(BboxBase._get_ymin, _set_ymin) + + def _set_xmax(self, val): + self._points[1, 0] = val + self.invalidate() + xmax = property(BboxBase._get_xmax, _set_xmax) + + def _set_ymax(self, val): + self._points[1, 1] = val + self.invalidate() + ymax = property(BboxBase._get_ymax, _set_ymax) + + def _set_min(self, val): + self._points[0] = val + self.invalidate() + min = property(BboxBase._get_min, _set_min) + + def _set_max(self, val): + self._points[1] = val + self.invalidate() + max = property(BboxBase._get_max, _set_max) + + def _set_intervalx(self, interval): + self._points[:, 0] = interval + self.invalidate() + intervalx = property(BboxBase._get_intervalx, _set_intervalx) + + def _set_intervaly(self, interval): + self._points[:, 1] = interval + self.invalidate() + intervaly = property(BboxBase._get_intervaly, _set_intervaly) + + def _set_bounds(self, bounds): + l,b,w,h = bounds + self._points = npy.array([[l, b], [l+w, b+h]], npy.float_) + self.invalidate() + bounds = property(BboxBase._get_bounds, _set_bounds) + + def get_points(self): + return self._points + + def set_points(self, points): + self._points = points + self.invalidate() + + def set(self, other): + self._points = other.get_points() + self.invalidate() + + def transformed(self, transform): + return Bbox(transform(self._points)) + + def inverse_transformed(self, transform): + return Bbox(transform.inverted()(self._points)) + + def expanded(self, sw, sh): + width = self.width + height = self.height + deltaw = (sw * width - width) / 2.0 + deltah = (sh * height - height) / 2.0 + a = npy.array([[-deltaw, -deltah], [deltaw, deltah]]) + return Bbox(self._points + a) + + #@staticmethod + def union(bboxes): + """ + Return the Bbox that bounds all bboxes + """ + assert(len(bboxes)) + + if len(bboxes) == 1: + return bboxes[0] + + bbox = bboxes[0] + xmin = bbox.xmin + ymin = bbox.ymin + xmax = bbox.xmax + ymax = bbox.ymax + + for bbox in bboxes[1:]: + xmin = min(xmin, bbox.xmin) + ymin = min(ymin, bbox.ymin) + xmax = max(xmax, bbox.xmax) + ymax = max(ymax, bbox.ymax) + + return Bbox.from_lbrt(xmin, ymin, xmax, ymax) + union = staticmethod(union) + +class TransformedBbox(BboxBase): + def __init__(self, bbox, transform): + assert isinstance(bbox, Bbox) + assert isinstance(transform, Transform) + + BboxBase.__init__(self) + self.bbox = bbox + self.transform = transform + self.set_children(['bbox', 'transform']) + self._points = None + + def __repr__(self): + return "TransformedBbox(%s, %s)" % (self.bbox, self.transform) + __str__ = __repr__ + + def _do_invalidation(self): + self._points = None + + def get_points(self): + if self._points is None: + self._points = self.transform(self.bbox.get_points()) + return self._points + +# MGDTODO: This code probably works, but I don't think it's a good idea +# (from a code clarity perspective) +# class BlendedBbox(BboxBase): +# def __init__(self, bbox_x, bbox_y): +# assert isinstance(bbox_x, BboxBase) +# assert isinstance(bbox_y, BboxBase) + +# BboxBase.__init__(self) +# self._x = bbox_x +# self._y = bbox_y +# self.set_children(['_x', '_y']) +# self._points = None + +# def __repr__(self): +# return "TransformedBbox(%s, %s)" % (self.bbox, self.transform) +# __str__ = __repr__ + +# def _do_invalidation(self): +# self._points = None + +# def get_points(self): +# if self._points is None: +# # MGDTODO: Optimize +# if self._x == self._y: +# self._points = self._x.get_points() +# else: +# x_points = self._x.get_points() +# y_points = self._y.get_points() +# self._points = npy.array( +# [[x_points[0,0], y_points[0,1]], +# [x_points[1,0], y_points[1,1]]], +# npy.float_) +# return self._points + +# def _set_intervalx(self, pair): +# # MGDTODO: Optimize +# bbox = Bbox([[pair[0], 0.0], [pair[1], 0.0]]) +# self.replace_child(0, bbox) +# intervalx = property(BboxBase._get_intervalx, _set_intervalx) + +# def _set_intervaly(self, pair): +# # MGDTODO: Optimize +# bbox = Bbox([[0.0, pair[0]], [0.0, pair[1]]]) +# self.replace_child(1, bbox) +# intervaly = property(BboxBase._get_intervaly, _set_intervaly) + +class Transform(TransformNode): + def __init__(self): + TransformNode.__init__(self) + + def __call__(self, points): + raise NotImplementedError() + + def __add__(self, other): + if isinstance(other, Transform): + return composite_transform_factory(self, other) + raise TypeError( + "Can not add Transform to object of type '%s'" % type(other)) + + def __radd__(self, other): + if isinstance(other, Transform): + return composite_transform_factory(other, self) + raise TypeError( + "Can not add Transform to object of type '%s'" % type(other)) + + def transform_point(self, point): + return self.__call__(npy.asarray([point]))[0] + + def has_inverse(self): + raise NotImplementedError() + + def inverted(self): + raise NotImplementedError() + + def is_separable(self): + return False + + def is_affine(self): + return False + +class Affine2DBase(Transform): + input_dims = 2 + output_dims = 2 + + def __init__(self): + Transform.__init__(self) + self._inverted = None + + def _do_invalidation(self): + result = self._inverted is None + self._inverted = None + return result + + #@staticmethod + def _concat(a, b): + return npy.dot(b, a) + _concat = staticmethod(_concat) + + #@staticmethod + def concat(a, b): + return Affine2D(Affine2D._concat(a.get_matrix(), b.get_matrix())) + concat = staticmethod(concat) + + def to_values(self): + mtx = self.get_matrix() + return tuple(mtx[:2].swapaxes(0, 1).flatten()) + + #@staticmethod + def matrix_from_values(a, b, c, d, e, f): + affine = npy.zeros((3, 3), npy.float_) + affine[0, ] = a, c, e + affine[1, ] = b, d, f + affine[2, 2] = 1 + return affine + matrix_from_values = staticmethod(matrix_from_values) + + def get_matrix(self): + raise NotImplementedError() + + def __call__(self, points): + """ + Applies the transformation to an array of 2D points and + returns the result. + + points must be a numpy array of shape (N, 2), where N is the + number of points. + """ + # MGDTODO: The major speed trap here is just converting to + # the points to an array in the first place. If we can use + # more arrays upstream, that should help here. + if not isinstance(points, npy.ndarray): + import traceback + print '-' * 60 + print 'A non-numpy array was passed in for transformation. Please ' + print 'correct this.' + print "".join(traceback.format_stack()) + print points + mtx = self.get_matrix()... [truncated message content] |
From: <md...@us...> - 2007-09-14 18:01:00
|
Revision: 3852 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3852&view=rev Author: mdboom Date: 2007-09-14 10:57:52 -0700 (Fri, 14 Sep 2007) Log Message: ----------- Sends paths to backend only once, and after that uses the "native" path by reference with a changing transform. Started recongfiguring patches.py to use only Paths under the hood (to take advantage of this caching). Removed many methods from backend_agg that should eventually be replaced by draw_path, at least in theory. Modified Paths: -------------- branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h Added Paths: ----------- branches/transforms/lib/matplotlib/path.py Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-09-14 13:03:31 UTC (rev 3851) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-09-14 17:57:52 UTC (rev 3852) @@ -4,7 +4,7 @@ """ from __future__ import division -import os, sys, warnings, copy +import os, sys, warnings, copy, weakref import numpy as npy import matplotlib.numerix.npyma as ma @@ -17,7 +17,10 @@ class RendererBase: """An abstract base class to handle drawing/rendering operations """ - + # This will cache paths across rendering instances + # Each subclass of RenderBase should define this --> + # _paths = weakref.WeakKeyDictionary() + def __init__(self): self._texmanager = None @@ -33,7 +36,35 @@ """ pass + def draw_path(self, gc, path, transform, rgbFace = None): + """ + Handles the caching of the native path associated with the + given path and calls the underlying backend's _draw_path to + actually do the drawing. + """ + native_path = self._native_paths.get(path) + if native_path is None: + import matplotlib.patches + print "CACHE MISS", path + native_path = self.convert_to_native_path(path) + self._native_paths[path] = native_path + self._draw_path(gc, native_path, transform, rgbFace) + def _draw_path(self, gc, native_path, transform, rgbFace): + """ + Draw the native path object with the given GraphicsContext and + transform. The transform passed in will always be affine. + """ + raise NotImplementedError + + def convert_to_native_path(self, path): + """ + Backends will normally will override this, but if they don't need any + special optimizations, they can just have the generic path data + passed to them in draw_path. + """ + return path + def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2, rotation): """ @@ -75,6 +106,9 @@ """ return False + def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): + pass + def _draw_markers(self, bgc, path, rgbFace, x, y, trans): """ This method is currently underscore hidden because the Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-14 13:03:31 UTC (rev 3851) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-14 17:57:52 UTC (rev 3852) @@ -69,7 +69,7 @@ """ from __future__ import division -import os, sys +import os, sys, weakref import numpy as npy @@ -95,7 +95,15 @@ The renderer handles all the drawing primitives using a graphics context instance that controls the colors/styles """ - + # MGDTODO: Renderers seem to get created and destroyed fairly + # often so the paths are cached at the class (not instance) level. + # However, this dictionary is only directly used by RendererBase, + # so it seems funny to define it here. However, if we didn't, the + # native paths would be shared across renderers, which is + # obviously bad. Seems like a good use of metaclasses, but that + # also seems like a heavy solution for a minor problem. + _native_paths = weakref.WeakKeyDictionary() + debug=1 texd = {} # a cache of tex image rasters def __init__(self, width, height, dpi): @@ -129,6 +137,12 @@ if __debug__: verbose.report('RendererAgg.__init__ done', 'debug-annoying') + def convert_to_native_path(self, path): + return self._renderer.convert_to_native_path(path.vertices, path.codes) + + def _draw_path(self, gc, native_path, transform, rgbFace): + return self._renderer.draw_path(gc, native_path, transform.to_values(), rgbFace) + def draw_arc(self, gcEdge, rgbFace, x, y, width, height, angle1, angle2, rotation): """ Draw an arc centered at x,y with width and height and angles Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-09-14 13:03:31 UTC (rev 3851) +++ branches/transforms/lib/matplotlib/lines.py 2007-09-14 17:57:52 UTC (rev 3852) @@ -10,14 +10,14 @@ import numpy as npy -import agg import numerix.ma as ma from matplotlib import verbose import artist from artist import Artist, setp from cbook import iterable, is_string_like, is_numlike from colors import colorConverter -from transforms import Bbox +from path import Path +from transforms import Affine2D, Bbox from matplotlib import rcParams @@ -284,9 +284,6 @@ self.set_data(xdata, ydata) self._logcache = None - # TODO: do we really need 'newstyle' - self._newstyle = False - def contains(self, mouseevent): """Test whether the mouse event occurred on the line. The pick radius determines the precision of the location test (usually within five points of the value). Use @@ -427,6 +424,7 @@ if len(x) != len(y): raise RuntimeError('xdata and ydata must be the same length') + # MGDTODO: Deal with segments mx = ma.getmask(x) my = ma.getmask(y) mask = ma.mask_or(mx, my) @@ -439,7 +437,9 @@ self._x = npy.asarray(x, float) self._y = npy.asarray(y, float) - + self._path = Path(npy.vstack((self._x, self._y)).transpose(), + closed=False) + self._logcache = None @@ -508,30 +508,19 @@ gc.set_joinstyle(join) gc.set_capstyle(cap) - if self._newstyle: - # transform in backend - xt = self._x - yt = self._y - else: - x, y = self._get_plottable() - if len(x)==0: return - xt, yt = self.get_transform().numerix_x_y(x, y) - - - funcname = self._lineStyles.get(self._linestyle, '_draw_nothing') lineFunc = getattr(self, funcname) + # MGDTODO: Deal with self._segments if self._segments is not None: for ii in self._segments: lineFunc(renderer, gc, xt[ii[0]:ii[1]], yt[ii[0]:ii[1]]) else: - lineFunc(renderer, gc, xt, yt) - - - if self._marker is not None: - + lineFunc(renderer, gc, self._path) + + # MGDTODO: Deal with markers + if self._marker is not None and False: gc = renderer.new_gc() self._set_gc_clip(gc) gc.set_foreground(self.get_markeredgecolor()) @@ -539,7 +528,7 @@ gc.set_alpha(self._alpha) funcname = self._markers.get(self._marker, '_draw_nothing') markerFunc = getattr(self, funcname) - markerFunc(renderer, gc, xt, yt) + markerFunc(renderer, gc, self._path) #renderer.close_group('line2d') @@ -720,7 +709,7 @@ self.set_linestyle('--') self._dashSeq = seq # TODO: offset ignored for now - def _draw_nothing(self, renderer, gc, xt, yt): + def _draw_nothing(self, renderer, gc, path): pass def _draw_steps(self, renderer, gc, xt, yt): @@ -737,13 +726,10 @@ else: renderer.draw_lines(gc, xt2, yt2) - def _draw_solid(self, renderer, gc, xt, yt): - if len(xt)<2: return + def _draw_solid(self, renderer, gc, path): + # if len(xt)<2: return gc.set_linestyle('solid') - if self._newstyle: - renderer.draw_lines(gc, xt, yt, self.get_transform()) - else: - renderer.draw_lines(gc, xt, yt) + renderer.draw_path(gc, path, self.get_transform()) def _draw_dashed(self, renderer, gc, xt, yt): @@ -1103,16 +1089,12 @@ for (x,y) in zip(xt, yt): renderer.draw_line(gc, x, y, x+offset, y) + _tickup_path = Path([[-0.5, 0.0], [-0.5, 1.0]]) def _draw_tickup(self, renderer, gc, xt, yt): offset = renderer.points_to_pixels(self._markersize) - if self._newstyle: - path = agg.path_storage() - path.move_to(-0.5, 0) - path.line_to(-0.5, offset) - renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_line(gc, x, y, x, y+offset) + marker_transform = Affine2D().scale(1.0, offset) + renderer.draw_markers(gc, self._tickup_path, marker_transform, + self._path, self.get_transform()) def _draw_tickdown(self, renderer, gc, xt, yt): offset = renderer.points_to_pixels(self._markersize) Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-09-14 13:03:31 UTC (rev 3851) +++ branches/transforms/lib/matplotlib/patches.py 2007-09-14 17:57:52 UTC (rev 3852) @@ -11,8 +11,8 @@ import matplotlib.nxutils as nxutils import matplotlib.mlab as mlab import matplotlib.artist as artist +from matplotlib.path import Path - # these are not available for the object inspector until after the # class is build so we define an initial set here for the init # function and they will be overridden after object defn @@ -73,7 +73,7 @@ self._antialiased = antialiased self._hatch = hatch self.fill = fill - + if len(kwargs): artist.setp(self, **kwargs) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd @@ -84,8 +84,10 @@ Returns T/F, {} """ - if callable(self._contains): return self._contains(self,mouseevent) + # MGDTODO: This will probably need to be implemented in C++ + if callable(self._contains): return self._contains(self,mouseevent) + try: # TODO: make this consistent with patch collection algorithm x, y = self.get_transform().inverse_xy_tup((mouseevent.x, mouseevent.y)) @@ -107,7 +109,6 @@ self.set_figure(other.get_figure()) self.set_alpha(other.get_alpha()) - def get_antialiased(self): return self._antialiased @@ -210,22 +211,16 @@ if self._hatch: gc.set_hatch(self._hatch ) - verts = self.get_verts() - tverts = self.get_transform()(verts) + path = self.get_path() + transform = self.get_transform() - # MGDTODO: This result is an Nx2 numpy array, which could be passed - # directly to renderer.draw_polygon since it currently expects - # a list of tuples so we're converting it to that now. - tverts = [tuple(x) for x in tverts] - - renderer.draw_polygon(gc, rgbFace, tverts) + renderer.draw_path(gc, path, transform, rgbFace) - #renderer.close_group('patch') - def get_verts(self): + def get_path(self): """ - Return the vertices of the patch + Return the path of this patch """ raise NotImplementedError('Derived must override') @@ -286,9 +281,10 @@ %(Patch)s """ Patch.__init__(self) - self.ox, self.oy = ox, oy self.patch = patch self.props = props + self.ox, self.oy = ox, oy + self._shadow_transform = transforms.Affine2D.translate(self.ox, self.oy) self._update() __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd @@ -306,18 +302,13 @@ self.set_facecolor((r,g,b)) self.set_edgecolor((r,g,b)) + + def get_path(self): + return self.patch.get_path() - def get_verts(self): - verts = self.patch.get_verts() - xs = self.convert_xunits([x+self.ox for x,y in verts]) - ys = self.convert_yunits([y+self.oy for x,y in verts]) - return zip(xs, ys) - - def _draw(self, renderer): - 'draw the shadow' - self._update() - Patch.draw(self, renderer) - + def get_transform(self): + return self._transform + self._shadow_transform + class Rectangle(Patch): """ Draw a rectangle with lower left at xy=(x,y) with specified @@ -325,12 +316,16 @@ """ + _path = Path( + [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]) + def __str__(self): return str(self.__class__).split('.')[-1] \ + "(%g,%g;%gx%g)"%(self.xy[0],self.xy[1],self.width,self.height) - def __init__(self, xy, width, height, - **kwargs): + # MGDTODO: Perhaps pass in a Bbox here instead, then the updates will + # happen automatically (without needing to call set_x etc. + def __init__(self, xy, width, height, **kwargs): """ xy is an x,y tuple lower, left @@ -344,38 +339,41 @@ Patch.__init__(self, **kwargs) - self.xy = list(xy) - self.width, self.height = width, height + self._bbox = transforms.Bbox.from_lbwh(xy[0], xy[1], width, height) + self._rect_transform = transforms.BboxTransform( + transforms.Bbox.unit(), self._bbox) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd - - def get_verts(self): + def get_path(self): """ Return the vertices of the rectangle """ - x, y = self.xy - left, right = self.convert_xunits((x, x + self.width)) - bottom, top = self.convert_yunits((y, y + self.height)) + # This is a "class-static" variable, so all rectangles in the plot + # will be shared (and merely have different transforms) + return self._path - return npy.array([[left, bottom], [left, top], - [right, top], [right, bottom]], - npy.float_) + # MGDTODO: Convert units +# left, right = self.convert_xunits((x, x + self.width)) +# bottom, top = self.convert_yunits((y, y + self.height)) + def get_transform(self): + return self._rect_transform + self._transform + def get_x(self): "Return the left coord of the rectangle" - return self.xy[0] + return self._bbox.xmin def get_y(self): "Return the bottom coord of the rectangle" - return self.xy[1] + return self._bbox.ymin def get_width(self): "Return the width of the rectangle" - return self.width + return self._bbox.width def get_height(self): "Return the height of the rectangle" - return self.height + return self._bbox.height def set_x(self, x): """ @@ -383,7 +381,7 @@ ACCEPTS: float """ - self.xy[0] = x + self._bbox.xmin = x def set_y(self, y): """ @@ -391,7 +389,7 @@ ACCEPTS: float """ - self.xy[1] = y + self._bbox.ymin = y def set_width(self, w): """ @@ -399,7 +397,7 @@ ACCEPTS: float """ - self.width = w + self._bbox.width = w def set_height(self, h): """ @@ -407,7 +405,7 @@ ACCEPTS: float """ - self.height = h + self._bbox.height = h def set_bounds(self, *args): """ @@ -419,15 +417,15 @@ l,b,w,h = args[0] else: l,b,w,h = args - self.xy = [l,b] - self.width = w - self.height = h + self._bbox.bounds = l,b,w,h class RegularPolygon(Patch): """ A regular polygon patch. """ + _polygon_cache = {} + def __str__(self): return "Poly%d(%g,%g)"%(self.numVertices,self.xy[0],self.xy[1]) @@ -444,32 +442,27 @@ """ Patch.__init__(self, **kwargs) - self.xy = list(xy) - self.numVertices = numVertices - self.radius = radius - self.orientation = orientation + path = self._polygon_cache[numVertices] + if path is None: + theta = 2*npy.pi/numVertices * npy.arange(numVertices) + verts = npy.hstack((npy.cos(theta), npy.sin(theta))) + path = Path(verts) + self._polygon_cache[numVertices] = path + self._path = path + self._poly_transform = transforms.Affine2D() \ + .scale(radius) \ + .rotate(orientation) \ + .translate(*xy) + __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd + def get_path(self): + return self._path - - def get_verts(self): - theta = 2*npy.pi/self.numVertices*npy.arange(self.numVertices) + \ - self.orientation - r = float(self.radius) - x, y = map(float, self.xy) - - xs = x + r*npy.cos(theta) - ys = y + r*npy.sin(theta) - - #xs = self.convert_xunits(xs) - #ys = self.convert_yunits(ys) - - - self.verts = zip(xs, ys) - - return self.verts - + def get_transform(self): + return self._poly_transform + self._transform + class Polygon(Patch): """ A general polygon patch. @@ -485,22 +478,20 @@ %(Patch)s See Patch documentation for additional kwargs """ - + # MGDTODO: This should encourage the use of numpy arrays of shape Nx2 Patch.__init__(self, **kwargs) if not isinstance(xy, list): xy = list(xy) - self.xy = xy + self._path = Path(xy, closed=False) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd - - def get_verts(self): - xs, ys = zip(*self.xy)[:2] + return self._path + + # MGDTODO: Convert units xs = self.convert_xunits(xs) ys = self.convert_yunits(ys) - return zip(xs, ys) - class Wedge(Polygon): def __str__(self): return "Wedge(%g,%g)"%self.xy[0] @@ -516,6 +507,7 @@ %(Patch)s """ + # MGDTODO: Implement me xc, yc = center rads = (math.pi/180.)*npy.arange(theta1, theta2+0.1*dtheta, dtheta) xs = r*npy.cos(rads)+xc @@ -543,6 +535,7 @@ Valid kwargs are: %(Patch)s """ + # MGDTODO: Implement me arrow = npy.array( [ [ 0.0, 0.1 ], [ 0.0, -0.1], [ 0.8, -0.1 ], [ 0.8, -0.3], @@ -586,6 +579,7 @@ %(Patch)s """ + # MGDTODO: Implement me if head_width is None: head_width = 3 * width if head_length is None: @@ -659,6 +653,7 @@ %(Patch)s """ + # MGDTODO: Implement me self.dpi = dpi self.xytip = xytip self.xybase = xybase @@ -731,6 +726,7 @@ %(Patch)s """ + # MGDTODO: Implement me self.center = xy self.radius = radius RegularPolygon.__init__(self, xy, @@ -767,6 +763,7 @@ Valid kwargs are: %(Patch)s """ + # MGDTODO: Implement me Patch.__init__(self, **kwargs) # self.center = npy.array(xy, npy.float) @@ -833,6 +830,7 @@ %(Patch)s """ + # MGDTODO: Implement me if kwargs.has_key('resolution'): import warnings warnings.warn('Circle is now scale free. Use CirclePolygon instead!', DeprecationWarning) Added: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py (rev 0) +++ branches/transforms/lib/matplotlib/path.py 2007-09-14 17:57:52 UTC (rev 3852) @@ -0,0 +1,50 @@ +import numpy as npy + +class Path: + # Path codes + STOP = 0 + MOVETO = 1 # 1 vertex + LINETO = 2 # 1 vertex + CURVE3 = 3 # 2 vertices + CURVE4 = 4 # 3 vertices + ### + # MGDTODO: I'm not sure these are supported by PS/PDF/SVG, + # so if they don't, we probably shouldn't + CURVEN = 5 + CATROM = 6 + UBSPLINE = 7 + #### + CLOSEPOLY = 0x0F # 0 vertices + + code_type = npy.uint8 + + def __init__(self, vertices, codes=None, closed=True): + self._vertices = npy.asarray(vertices, npy.float_) + assert self._vertices.ndim == 2 + assert self._vertices.shape[1] == 2 + + if codes is None: + if closed: + codes = self.LINETO * npy.ones( + self._vertices.shape[0] + 1, self.code_type) + codes[0] = self.MOVETO + codes[-1] = self.CLOSEPOLY + else: + codes = self.LINETO * npy.ones( + self._vertices.shape[0], self.code_type) + codes[0] = self.MOVETO + else: + codes = npy.asarray(codes, self.code_type) + self._codes = codes + + assert self._codes.ndim == 1 + # MGDTODO: Maybe we should add some quick-and-dirty check that + # the number of vertices is correct for the code array + + def _get_codes(self): + return self._codes + codes = property(_get_codes) + + def _get_vertices(self): + return self._vertices + vertices = property(_get_vertices) Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-09-14 13:03:31 UTC (rev 3851) +++ branches/transforms/lib/matplotlib/transforms.py 2007-09-14 17:57:52 UTC (rev 3852) @@ -403,6 +403,9 @@ Transform.__init__(self) self._inverted = None + def __array__(self): + return self.get_matrix() + def _do_invalidation(self): result = self._inverted is None self._inverted = None Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-09-14 13:03:31 UTC (rev 3851) +++ branches/transforms/src/_backend_agg.cpp 2007-09-14 17:57:52 UTC (rev 3852) @@ -341,6 +341,7 @@ } +// MGDTODO: Remove this method (it has been conglomerated into draw_path template <class VS> void RendererAgg::_fill_and_stroke(VS& path, @@ -1399,68 +1400,6 @@ } - - -// Py::Object -// RendererAgg::draw_path(const Py::Tuple& args) { -// //draw_path(gc, rgbFace, path, transform) -// theRasterizer->reset_clipping(); - -// _VERBOSE("RendererAgg::draw_path"); -// args.verify_length(4); - -// GCAgg gc = GCAgg(args[0], dpi); -// facepair_t face = _get_rgba_face(args[1], gc.alpha); - -// agg::path_storage *path; -// swig_type_info * descr = SWIG_TypeQuery("agg::path_storage *"); -// assert(descr); -// if (SWIG_ConvertPtr(args[2].ptr(),(void **)(&path), descr, 0) == -1) -// throw Py::TypeError("Could not convert path_storage"); - - -// Transformation* mpltransform = static_cast<Transformation*>(args[3].ptr()); - -// double a, b, c, d, tx, ty; -// try { -// mpltransform->affine_params_api(&a, &b, &c, &d, &tx, &ty); -// } -// catch(...) { -// throw Py::ValueError("Domain error on affine_params_api in RendererAgg::draw_path"); -// } - -// agg::trans_affine xytrans = agg::trans_affine(a,b,c,d,tx,ty); - -// double heightd = double(height); -// agg::path_storage tpath; // the mpl transformed path -// bool needNonlinear = mpltransform->need_nonlinear_api(); -// size_t Nx = path->total_vertices(); -// double x, y; -// unsigned cmd; -// bool curvy = false; -// for (size_t i=0; i<Nx; i++) { -// cmd = path->vertex(i, &x, &y); -// if (cmd==agg::path_cmd_curve3 || cmd==agg::path_cmd_curve4) curvy=true; -// if (needNonlinear) -// try { -// mpltransform->nonlinear_only_api(&x, &y); -// } -// catch (...) { -// throw Py::ValueError("Domain error on nonlinear_only_api in RendererAgg::draw_path"); - -// } - -// //use agg's transformer? -// xytrans.transform(&x, &y); -// y = heightd - y; //flipy -// tpath.add_vertex(x,y,cmd); -// } - -// _fill_and_stroke(tpath, gc, face, curvy); -// return Py::Object(); - -// } - /** * This is a custom span generator that converts spans in the * 8-bit inverted greyscale font buffer to rgba that agg can use. @@ -1613,8 +1552,172 @@ } +inline void get_next_vertex(const char* & vertex_i, const char* vertex_end, + double& x, double& y, + size_t next_vertex_stride, + size_t next_axis_stride) { + if (vertex_i + next_axis_stride >= vertex_end) + throw Py::ValueError("Error parsing path. Read past end of vertices"); + x = *(double*)vertex_i; + y = *(double*)(vertex_i + next_axis_stride); + vertex_i += next_vertex_stride; +} +#define GET_NEXT_VERTEX(x, y) get_next_vertex(vertex_i, vertex_end, x, y, next_vertex_stride, next_axis_stride) + + + Py::Object +RendererAgg::convert_to_native_path(const Py::Tuple& args) { + _VERBOSE("RendererAgg::draw_image"); + args.verify_length(2); + + Py::Object vertices_obj = args[0]; + Py::Object codes_obj = args[1]; + + PyArrayObject* vertices = NULL; + PyArrayObject* codes = NULL; + PathAgg* path = NULL; + + try { + vertices = (PyArrayObject*)PyArray_ContiguousFromObject + (vertices_obj.ptr(), PyArray_DOUBLE, 2, 2); + if (!vertices || vertices->nd != 2 || vertices->dimensions[1] != 2) + throw Py::ValueError("Invalid vertices array."); + codes = (PyArrayObject*)PyArray_ContiguousFromObject + (codes_obj.ptr(), PyArray_UINT8, 1, 1); + if (!codes) + throw Py::ValueError("Invalid codes array."); + + path = new PathAgg(); + + size_t next_vertex_stride = vertices->strides[0]; + size_t next_axis_stride = vertices->strides[1]; + size_t code_stride = codes->strides[0]; + + const char* vertex_i = vertices->data; + const char* code_i = codes->data; + const char* vertex_end = vertex_i + (vertices->dimensions[0] * vertices->strides[0]); + + size_t N = codes->dimensions[0]; + double x0, y0, x1, y1, x2, y2; + + for (size_t i = 0; i < N; ++i) { + switch (*(unsigned char*)(code_i)) { + case MOVETO: + GET_NEXT_VERTEX(x0, y0); + path->move_to(x0, y0); + _VERBOSE("MOVETO"); + break; + case LINETO: + GET_NEXT_VERTEX(x0, y0); + path->line_to(x0, y0); + _VERBOSE("LINETO"); + break; + case CURVE3: + GET_NEXT_VERTEX(x0, y0); + GET_NEXT_VERTEX(x1, y1); + path->curve3(x0, y0, x1, y1); + path->curvy = true; + _VERBOSE("CURVE3"); + break; + case CURVE4: + GET_NEXT_VERTEX(x0, y0); + GET_NEXT_VERTEX(x1, y1); + GET_NEXT_VERTEX(x2, y2); + path->curve4(x0, y0, x1, y1, x2, y2); + path->curvy = true; + _VERBOSE("CURVE4"); + break; + case CLOSEPOLY: + path->close_polygon(); + _VERBOSE("CLOSEPOLY"); + break; + } + code_i += code_stride; + } + } catch(...) { + Py_XDECREF(vertices); + Py_XDECREF(codes); + delete path; + throw; + } + + Py_XDECREF(vertices); + Py_XDECREF(codes); + + return Py::asObject(path); +} + +Py::Object +RendererAgg::draw_path(const Py::Tuple& args) { + typedef agg::conv_transform<agg::path_storage> transformed_path_t; + typedef agg::conv_curve<transformed_path_t> curve_t; + typedef agg::conv_stroke<curve_t> stroke_t; + typedef agg::conv_dash<curve_t> dash_t; + typedef agg::conv_stroke<dash_t> stroke_dash_t; + //draw_path(gc, rgbFace, path, transform) + theRasterizer->reset_clipping(); + + _VERBOSE("RendererAgg::draw_path"); + args.verify_length(4); + + GCAgg gc = GCAgg(args[0], dpi); + Py::Object path_obj = args[1]; + if (!PathAgg::check(path_obj)) + throw Py::TypeError("Native path object is not of correct type"); + PathAgg* path = static_cast<PathAgg*>(path_obj.ptr()); + agg::trans_affine trans = py_sequence_to_agg_transformation_matrix(args[2]); + facepair_t face = _get_rgba_face(args[3], gc.alpha); + + trans *= agg::trans_affine_scaling(1.0, -1.0); + trans *= agg::trans_affine_translation(0.0, (double)height); + + transformed_path_t tpath(*path, trans); + // MGDTODO: See if there is any advantage to only curving if necessary + curve_t curve(tpath); + + set_clipbox_rasterizer(gc.cliprect); + + if (face.first) { + rendererAA->color(face.second); + theRasterizer->add_path(curve); + agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); + } + + if (gc.linewidth) { + if (gc.dasha == NULL) { + stroke_t stroke(curve); + stroke.width(gc.linewidth); + stroke.line_cap(gc.cap); + stroke.line_join(gc.join); + theRasterizer->add_path(stroke); + } else { + dash_t dash(curve); + for (size_t i = 0; i < (gc.Ndash / 2); ++i) + dash.add_dash(gc.dasha[2 * i], gc.dasha[2 * i + 1]); + stroke_dash_t stroke(dash); + stroke.line_cap(gc.cap); + stroke.line_join(gc.join); + stroke.width(gc.linewidth); + theRasterizer->add_path(stroke); //boyle freeze is herre + } + + if ( gc.isaa ) { + rendererAA->color(gc.color); + agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); + } + else { + rendererBin->color(gc.color); + agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin); + } + } + + return Py::Object(); +} + + +Py::Object RendererAgg::write_rgba(const Py::Tuple& args) { _VERBOSE("RendererAgg::write_rgba"); @@ -1949,6 +2052,10 @@ "draw_ellipse(gc, rgbFace, x, y, w, h)\n"); add_varargs_method("draw_polygon", &RendererAgg::draw_polygon, "draw_polygon(gc, rgbFace, points)\n"); + add_varargs_method("draw_path", &RendererAgg::draw_path, + "draw_path(gc, rgbFace, native_path, transform)\n"); + add_varargs_method("convert_to_native_path", &RendererAgg::convert_to_native_path, + "convert_to_native_path(vertices, codes)\n"); add_varargs_method("draw_lines", &RendererAgg::draw_lines, "draw_lines(gc, x, y,)\n"); add_varargs_method("draw_markers", &RendererAgg::draw_markers, @@ -1976,10 +2083,13 @@ add_varargs_method("restore_region", &RendererAgg::restore_region, "restore_region(region)"); - - } +void PathAgg::init_type() +{ + behaviors().name("PathAgg"); + behaviors().doc("A native Agg path object"); +} extern "C" DL_EXPORT(void) Modified: branches/transforms/src/_backend_agg.h =================================================================== --- branches/transforms/src/_backend_agg.h 2007-09-14 13:03:31 UTC (rev 3851) +++ branches/transforms/src/_backend_agg.h 2007-09-14 17:57:52 UTC (rev 3852) @@ -39,6 +39,14 @@ #include "agg_scanline_p.h" #include "agg_vcgen_markers_term.h" +// These are copied directly from path.py, and must be kept in sync +#define STOP 0 +#define MOVETO 1 +#define LINETO 2 +#define CURVE3 3 +#define CURVE4 4 +#define CLOSEPOLY 0x0F + typedef agg::pixfmt_rgba32 pixfmt; typedef agg::renderer_base<pixfmt> renderer_base; typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_aa; @@ -163,6 +171,8 @@ Py::Object draw_markers(const Py::Tuple & args); Py::Object draw_text_image(const Py::Tuple & args); Py::Object draw_image(const Py::Tuple & args); + Py::Object draw_path(const Py::Tuple & args); + Py::Object convert_to_native_path(const Py::Tuple & args); Py::Object write_rgba(const Py::Tuple & args); Py::Object write_png(const Py::Tuple & args); @@ -229,7 +239,22 @@ agg::path_storage *lastclippath; }; +// A completely opaque data type used only to pass native path +// data to/from Python. Python can't do anything with the data +// other than create and then use it. +class PathAgg : + public agg::path_storage, + public Py::PythonExtension<PathAgg> { +public: + PathAgg() : curvy(false) {} + + static void init_type(void); + + bool curvy; +}; + + // the extension module class _backend_agg_module : public Py::ExtensionModule<_backend_agg_module> { @@ -240,6 +265,7 @@ BufferRegion::init_type(); RendererAgg::init_type(); + PathAgg::init_type(); add_keyword_method("RendererAgg", &_backend_agg_module::new_renderer, "RendererAgg(width, height, dpi)"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-17 13:41:58
|
Revision: 3854 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3854&view=rev Author: mdboom Date: 2007-09-17 06:41:38 -0700 (Mon, 17 Sep 2007) Log Message: ----------- Transferring work-in-progress Modified Paths: -------------- branches/transforms/examples/shared_axis_demo.py branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/path.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h Modified: branches/transforms/examples/shared_axis_demo.py =================================================================== --- branches/transforms/examples/shared_axis_demo.py 2007-09-15 04:01:56 UTC (rev 3853) +++ branches/transforms/examples/shared_axis_demo.py 2007-09-17 13:41:38 UTC (rev 3854) @@ -36,12 +36,12 @@ s2 = exp(-t) s3 = sin(4*pi*t) ax1 = subplot(311) -plot(t,s1) +plot(t,s1, "bH") setp( ax1.get_xticklabels(), fontsize=6) ## share x only ax2 = subplot(312, sharex=ax1) -plot(t, s2) +plot(t, s2, "b<") # make these tick labels invisible setp( ax2.get_xticklabels(), visible=False) Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-09-15 04:01:56 UTC (rev 3853) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-09-17 13:41:38 UTC (rev 3854) @@ -36,21 +36,25 @@ """ pass + def _get_cached_native_path(self, path): + native_path = self._native_paths.get(path) + if native_path is None: + import matplotlib.patches + print "CACHE MISS", path + native_path = self.convert_to_native_path(path) + self._native_paths[path] = native_path + return native_path + def draw_path(self, gc, path, transform, rgbFace = None): """ Handles the caching of the native path associated with the given path and calls the underlying backend's _draw_path to actually do the drawing. """ - native_path = self._native_paths.get(path) - if native_path is None: - import matplotlib.patches - print "CACHE MISS", path - native_path = self.convert_to_native_path(path) - self._native_paths[path] = native_path - self._draw_path(gc, native_path, transform, rgbFace) + native_path = self._get_cached_native_path(path) + self._draw_native_path(gc, native_path, transform, rgbFace) - def _draw_path(self, gc, native_path, transform, rgbFace): + def _draw_native_path(self, gc, native_path, transform, rgbFace): """ Draw the native path object with the given GraphicsContext and transform. The transform passed in will always be affine. @@ -107,9 +111,10 @@ return False def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): - pass - - def _draw_markers(self, bgc, path, rgbFace, x, y, trans): + native_marker_path = self._get_cached_native_path(marker_path) + self._draw_native_markers(gc, native_marker_path, marker_trans, path, trans, rgbFace) + + def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None): """ This method is currently underscore hidden because the draw_markers method is being used as a sentinel for newstyle @@ -130,7 +135,7 @@ vec6 = transform.as_vec6_val() ...backend dependent affine... """ - pass + raise NotImplementedError def draw_line_collection(self, segments, transform, clipbox, colors, linewidths, linestyle, antialiaseds, Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-15 04:01:56 UTC (rev 3853) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-17 13:41:38 UTC (rev 3854) @@ -140,7 +140,7 @@ def convert_to_native_path(self, path): return self._renderer.convert_to_native_path(path.vertices, path.codes) - def _draw_path(self, gc, native_path, transform, rgbFace): + def _draw_native_path(self, gc, native_path, transform, rgbFace): return self._renderer.draw_path(gc, native_path, transform.to_values(), rgbFace) def draw_arc(self, gcEdge, rgbFace, x, y, width, height, angle1, angle2, rotation): @@ -172,8 +172,12 @@ def draw_lines(self, gc, x, y, transform): return self._renderer.draw_lines(gc, x, y, transform.to_values()) - def draw_markers(self, gc, path, color, x, y, transform): - return self._renderer.draw_markers(gc, path, color, x, y, transform.to_values()) + def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None): + return self._renderer.draw_markers( + gc, + native_marker_path, marker_trans.to_values(), + path.vertices, path.codes, trans.to_values(), + rgbFace) def draw_polygon(self, *args): return self._renderer.draw_polygon(*args) Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-09-15 04:01:56 UTC (rev 3853) +++ branches/transforms/lib/matplotlib/lines.py 2007-09-17 13:41:38 UTC (rev 3854) @@ -520,7 +520,7 @@ lineFunc(renderer, gc, self._path) # MGDTODO: Deal with markers - if self._marker is not None and False: + if self._marker is not None: gc = renderer.new_gc() self._set_gc_clip(gc) gc.set_foreground(self.get_markeredgecolor()) @@ -713,6 +713,9 @@ pass def _draw_steps(self, renderer, gc, xt, yt): + # MGDTODO: This is a quirky one. The step-plotting part + # should probably be moved to where the path is generated + # in recache, and then just drawn with _draw_solid siz=len(xt) if siz<2: return xt2=npy.ones((2*siz,), xt.dtype) @@ -727,323 +730,132 @@ renderer.draw_lines(gc, xt2, yt2) def _draw_solid(self, renderer, gc, path): - # if len(xt)<2: return gc.set_linestyle('solid') renderer.draw_path(gc, path, self.get_transform()) - def _draw_dashed(self, renderer, gc, xt, yt): - if len(xt)<2: return + def _draw_dashed(self, renderer, gc, path): gc.set_linestyle('dashed') if self._dashSeq is not None: gc.set_dashes(0, self._dashSeq) - if self._newstyle: - renderer.draw_lines(gc, xt, yt, self.get_transform()) - else: - renderer.draw_lines(gc, xt, yt) + renderer.draw_path(gc, path, self.get_transform()) - def _draw_dash_dot(self, renderer, gc, xt, yt): - if len(xt)<2: return + def _draw_dash_dot(self, renderer, gc, path): gc.set_linestyle('dashdot') - if self._newstyle: - renderer.draw_lines(gc, xt, yt, self.get_transform()) - else: - renderer.draw_lines(gc, xt, yt) + renderer.draw_path(gc, path, self.get_transform()) - def _draw_dotted(self, renderer, gc, xt, yt): - - if len(xt)<2: return + + def _draw_dotted(self, renderer, gc, path): gc.set_linestyle('dotted') - if self._newstyle: - renderer.draw_lines(gc, xt, yt, self.get_transform()) - else: - renderer.draw_lines(gc, xt, yt) + renderer.draw_path(gc, path, self.get_transform()) - def _draw_point(self, renderer, gc, xt, yt): + + def _draw_point(self, renderer, gc, path): + self._draw_circle(renderer, gc, path, point = True) - r = 0.5 * renderer.points_to_pixels(self._markersize) - r *= self._point_size_reduction - gc.set_linewidth(0) - if r <= 0.5: - self._draw_pixel(renderer, gc, xt, yt) - elif r <= 2: - self._draw_hexagon1(renderer, gc, xt, yt, point=True) - else: - self._draw_circle(renderer, gc, xt, yt, point=True) - - def _draw_pixel(self, renderer, gc, xt, yt): - if self._newstyle: - rgbFace = self._get_rgb_face() - path = agg.path_storage() - path.move_to(-0.5, -0.5) - path.line_to(-0.5, 0.5) - path.line_to(0.5, 0.5) - path.line_to(0.5, -0.5) - renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_point(gc, x, y) - - - def _draw_circle(self, renderer, gc, xt, yt, point=False): - + def _draw_pixel(self, renderer, gc, path): + rgbFace = self._get_rgb_face() + transform = Affine2D().translate(-0.5, -0.5) + renderer.draw_markers(gc, Path.unit_rectangle, transform, + path, self.get_transform(), rgbFace) + + + def _draw_circle(self, renderer, gc, path, point=False): w = renderer.points_to_pixels(self._markersize) if point: w *= self._point_size_reduction + w *= 0.5 - rgbFace = self._get_rgb_face() + transform = Affine2D().scale(w, w) + renderer.draw_markers( + gc, Path.unit_circle(), transform, path, self.get_transform(), + rgbFace) - if self._newstyle: - N = 50.0 - r = w/2. - rads = (2*math.pi/N)*npy.arange(N) - xs = r*npy.cos(rads) - ys = r*npy.sin(rads) - # todo: use curve3! - path = agg.path_storage() - path.move_to(xs[0], ys[0]) - for x, y in zip(xs[1:], ys[1:]): - path.line_to(x, y) - path.end_poly() - renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt,yt): - renderer.draw_arc(gc, rgbFace, - x, y, w, w, 0.0, 360.0, 0.0) - - - - def _draw_triangle_up(self, renderer, gc, xt, yt): - - + _triangle_path = Path([[0.0, 1.0], [-1.0, -1.0], [1.0, -1.0]]) + def _draw_triangle_up(self, renderer, gc, path): offset = 0.5*renderer.points_to_pixels(self._markersize) + transform = Affine2D().scale(offset, offset) rgbFace = self._get_rgb_face() + renderer.draw_markers(gc, self._triangle_path, transform, + path, self.get_transform(), rgbFace) - if self._newstyle: - path = agg.path_storage() - path.move_to(0, offset) - path.line_to(-offset, -offset) - path.line_to(offset, -offset) - path.end_poly() - renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - verts = ( (x, y+offset), - (x-offset, y-offset), - (x+offset, y-offset) ) - renderer.draw_polygon(gc, rgbFace, verts) - - def _draw_triangle_down(self, renderer, gc, xt, yt): + def _draw_triangle_down(self, renderer, gc, path): offset = 0.5*renderer.points_to_pixels(self._markersize) + transform = Affine2D().scale(offset, -offset) rgbFace = self._get_rgb_face() + renderer.draw_markers(gc, self._triangle_path, transform, + path, self.get_transform(), rgbFace) - if self._newstyle: - - path = agg.path_storage() - path.move_to(-offset, offset) - path.line_to(offset, offset) - path.line_to(0, -offset) - path.end_poly() - - renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - verts = ( (x-offset, y+offset), - (x+offset, y+offset), - (x, y-offset)) - renderer.draw_polygon(gc, rgbFace, verts) - - def _draw_triangle_left(self, renderer, gc, xt, yt): + + def _draw_triangle_left(self, renderer, gc, path): offset = 0.5*renderer.points_to_pixels(self._markersize) + transform = Affine2D().scale(offset, offset).rotate_deg(90) rgbFace = self._get_rgb_face() + renderer.draw_markers(gc, self._triangle_path, transform, + path, self.get_transform(), rgbFace) - if self._newstyle: - path = agg.path_storage() - path.move_to(-offset, 0) - path.line_to(offset, -offset) - path.line_to(offset, offset) - path.end_poly() - - renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - verts = ( (x-offset, y), - (x+offset, y-offset), - (x+offset, y+offset)) - renderer.draw_polygon(gc, rgbFace, verts) - - - def _draw_triangle_right(self, renderer, gc, xt, yt): + def _draw_triangle_right(self, renderer, gc, path): offset = 0.5*renderer.points_to_pixels(self._markersize) + transform = Affine2D().scale(offset, offset).rotate_deg(-90) rgbFace = self._get_rgb_face() - if self._newstyle: - path = agg.path_storage() - path.move_to(offset, 0) - path.line_to(-offset, -offset) - path.line_to(-offset, offset) - path.end_poly() - renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - verts = ( (x+offset, y), - (x-offset, y-offset), - (x-offset, y+offset)) - renderer.draw_polygon(gc, rgbFace, verts) + renderer.draw_markers(gc, self._triangle_path, transform, + path, self.get_transform(), rgbFace) - - def _draw_square(self, renderer, gc, xt, yt): + def _draw_square(self, renderer, gc, path): side = renderer.points_to_pixels(self._markersize) - offset = side*0.5 + transform = Affine2D().translate(-0.5, -0.5).scale(side) rgbFace = self._get_rgb_face() + renderer.draw_markers(gc, Path.unit_rectangle(), transform, + path, self.get_transform(), rgbFace) - if self._newstyle: - - path = agg.path_storage() - path.move_to(-offset, -offset) - path.line_to(-offset, offset) - path.line_to(offset, offset) - path.line_to(offset, -offset) - path.end_poly() - - renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform()) - else: - - for (x,y) in zip(xt, yt): - renderer.draw_rectangle( - gc, rgbFace, - x-offset, y-offset, side, side) - - def _draw_diamond(self, renderer, gc, xt, yt): - offset = 0.6*renderer.points_to_pixels(self._markersize) + + def _draw_diamond(self, renderer, gc, path): + side = renderer.points_to_pixels(self._markersize) + transform = Affine2D().translate(0.5, 0.5).rotate_deg(45).scale(side) rgbFace = self._get_rgb_face() - if self._newstyle: - path = agg.path_storage() - path.move_to(offset, 0) - path.line_to(0, -offset) - path.line_to(-offset, 0) - path.line_to(0, offset) - path.end_poly() + renderer.draw_markers(gc, Path.unit_rectangle(), transform, + path, self.get_transform(), rgbFace) - renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform()) - else: - - - for (x,y) in zip(xt, yt): - verts = ( (x+offset, y), - (x, y-offset), - (x-offset, y), - (x, y+offset)) - renderer.draw_polygon(gc, rgbFace, verts) - - def _draw_thin_diamond(self, renderer, gc, xt, yt): - offset = 0.7*renderer.points_to_pixels(self._markersize) - xoffset = 0.6*offset + + def _draw_thin_diamond(self, renderer, gc, path): + offset = renderer.points_to_pixels(self._markersize) + transform = Affine2D().translate(0.5, 0.5).rotate_deg(45).scale(offset * 0.8, offset) rgbFace = self._get_rgb_face() + renderer.draw_markers(gc, Path.unit_rectangle(), transform, + path, self.get_transform(), rgbFace) - if self._newstyle: - path = agg.path_storage() - path.move_to(xoffset, 0) - path.line_to(0, -offset) - path.line_to(-xoffset, 0) - path.line_to(0, offset) - path.end_poly() - renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - verts = ( (x+xoffset, y), - (x, y-offset), - (x-xoffset, y), - (x, y+offset)) - renderer.draw_polygon(gc, rgbFace, verts) + + def _draw_pentagon(self, renderer, gc, path): + offset = 0.5 * renderer.points_to_pixels(self._markersize) + transform = Affine2D().scale(offset) + rgbFace = self._get_rgb_face() + renderer.draw_markers(gc, Path.unit_regular_polygon(5), transform, + path, self.get_transform(), rgbFace) - def _draw_pentagon(self, renderer, gc, xt, yt): - offset = 0.6*renderer.points_to_pixels(self._markersize) - offsetX1 = offset*0.95 - offsetY1 = offset*0.31 - offsetX2 = offset*0.59 - offsetY2 = offset*0.81 - rgbFace = self._get_rgb_face() + + def _draw_hexagon1(self, renderer, gc, path, point=False): + offset = 0.5 * renderer.points_to_pixels(self._markersize) + transform = Affine2D().scale(offset) + rgbFace = self._get_rgb_face() + renderer.draw_markers(gc, Path.unit_regular_polygon(6), transform, + path, self.get_transform(), rgbFace) - if self._newstyle: - path = agg.path_storage() - path.move_to(0, offset) - path.line_to(-offsetX1, offsetY1) - path.line_to(-offsetX2, -offsetY2) - path.line_to(+offsetX2, -offsetY2) - path.line_to(+offsetX1, offsetY1) - path.end_poly() - - renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - verts = ( (x, y+offset), - (x-offsetX1, y+offsetY1), - (x-offsetX2, y-offsetY2), - (x+offsetX2, y-offsetY2), - (x+offsetX1, y+offsetY1)) - renderer.draw_polygon(gc, rgbFace, verts) - - def _draw_hexagon1(self, renderer, gc, xt, yt, point=False): - offset = 0.6*renderer.points_to_pixels(self._markersize) - if point: - offset *= self._point_size_reduction - offsetX1 = offset*0.87 - offsetY1 = offset*0.5 - rgbFace = self._get_rgb_face() - - if self._newstyle: - path = agg.path_storage() - path.move_to(0, offset) - path.line_to(-offsetX1, offsetY1) - path.line_to(-offsetX1, -offsetY1) - path.line_to(0, -offset) - path.line_to(offsetX1, -offsetY1) - path.line_to(offsetX1, offsetY1) - path.end_poly() - renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - verts = ( (x, y+offset), - (x-offsetX1, y+offsetY1), - (x-offsetX1, y-offsetY1), - (x, y-offset), - (x+offsetX1, y-offsetY1), - (x+offsetX1, y+offsetY1)) - renderer.draw_polygon(gc, rgbFace, verts) - + def _draw_hexagon2(self, renderer, gc, xt, yt): - offset = 0.6*renderer.points_to_pixels(self._markersize) - offsetX1 = offset*0.5 - offsetY1 = offset*0.87 - rgbFace = self._get_rgb_face() - if self._newstyle: - path = agg.path_storage() - path.move_to(offset, 0) - path.line_to(offsetX1, offsetY1) - path.line_to(-offsetX1, offsetY1) - path.line_to(-offset, 0) - path.line_to(-offsetX1, -offsetY1) - path.line_to(offsetX1, -offsetY1) - path.end_poly() + offset = 0.5 * renderer.points_to_pixels(self._markersize) + transform = Affine2D().scale(offset).rotate_deg(30) + rgbFace = self._get_rgb_face() + renderer.draw_markers(gc, Path.unit_regular_polygon(6), transform, + path, self.get_transform(), rgbFace) - renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - verts = ( (x+offset, y), - (x+offsetX1, y+offsetY1), - (x-offsetX1, y+offsetY1), - (x-offset, y), - (x-offsetX1, y-offsetY1), - (x+offsetX1, y-offsetY1)) - renderer.draw_polygon(gc, rgbFace, verts) - + def _draw_vline(self, renderer, gc, xt, yt): offset = 0.5*renderer.points_to_pixels(self._markersize) if self._newstyle: @@ -1055,6 +867,7 @@ for (x,y) in zip(xt, yt): renderer.draw_line(gc, x, y-offset, x, y+offset) + def _draw_hline(self, renderer, gc, xt, yt): offset = 0.5*renderer.points_to_pixels(self._markersize) if self._newstyle: @@ -1066,46 +879,31 @@ for (x,y) in zip(xt, yt): renderer.draw_line(gc, x-offset, y, x+offset, y) - def _draw_tickleft(self, renderer, gc, xt, yt): + _tickhoriz_path = Path([[0.0, 0.5], [1.0, 0.5]]) + def _draw_tickleft(self, renderer, gc, path): offset = renderer.points_to_pixels(self._markersize) - if self._newstyle: - path = agg.path_storage() - path.move_to(-offset, 0.5) - path.line_to(0, 0.5) - renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_line(gc, x-offset, y, x, y) + marker_transform = Affine2D().scale(offset, 1.0) + renderer.draw_markers(gc, self._tickhoriz_path, marker_transform, + path, self.get_transform()) - def _draw_tickright(self, renderer, gc, xt, yt): - + def _draw_tickright(self, renderer, gc, path): offset = renderer.points_to_pixels(self._markersize) - if self._newstyle: - path = agg.path_storage() - path.move_to(0, 0.5) - path.line_to(offset, 0.5) - renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_line(gc, x, y, x+offset, y) + marker_transform = Affine2D().scale(-offset, 1.0) + renderer.draw_markers(gc, self._tickhoriz_path, marker_transform, + path, self.get_transform()) - _tickup_path = Path([[-0.5, 0.0], [-0.5, 1.0]]) - def _draw_tickup(self, renderer, gc, xt, yt): + _tickvert_path = Path([[-0.5, 0.0], [-0.5, 1.0]]) + def _draw_tickup(self, renderer, gc, path): offset = renderer.points_to_pixels(self._markersize) marker_transform = Affine2D().scale(1.0, offset) - renderer.draw_markers(gc, self._tickup_path, marker_transform, - self._path, self.get_transform()) + renderer.draw_markers(gc, self._tickvert_path, marker_transform, + path, self.get_transform()) - def _draw_tickdown(self, renderer, gc, xt, yt): + def _draw_tickdown(self, renderer, gc, path): offset = renderer.points_to_pixels(self._markersize) - if self._newstyle: - path = agg.path_storage() - path.move_to(-0.5, -offset) - path.line_to(-0.5, 0) - renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_line(gc, x, y-offset, x, y) + marker_transform = Affine2D().scale(1.0, -offset) + renderer.draw_markers(gc, self._tickvert_path, marker_transform, + path, self.get_transform()) def _draw_plus(self, renderer, gc, xt, yt): offset = 0.5*renderer.points_to_pixels(self._markersize) Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-09-15 04:01:56 UTC (rev 3853) +++ branches/transforms/lib/matplotlib/patches.py 2007-09-17 13:41:38 UTC (rev 3854) @@ -288,7 +288,6 @@ self._update() __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd - def _update(self): self.update_from(self.patch) if self.props is not None: @@ -316,8 +315,7 @@ """ - _path = Path( - [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]) + _path = Path.unit_rectangle() def __str__(self): return str(self.__class__).split('.')[-1] \ @@ -424,8 +422,6 @@ """ A regular polygon patch. """ - _polygon_cache = {} - def __str__(self): return "Poly%d(%g,%g)"%(self.numVertices,self.xy[0],self.xy[1]) @@ -442,14 +438,7 @@ """ Patch.__init__(self, **kwargs) - path = self._polygon_cache[numVertices] - if path is None: - theta = 2*npy.pi/numVertices * npy.arange(numVertices) - verts = npy.hstack((npy.cos(theta), npy.sin(theta))) - path = Path(verts) - self._polygon_cache[numVertices] = path - - self._path = path + self._path = Path.unit_regular_polygon(numVertices) self._poly_transform = transforms.Affine2D() \ .scale(radius) \ .rotate(orientation) \ Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-09-15 04:01:56 UTC (rev 3853) +++ branches/transforms/lib/matplotlib/path.py 2007-09-17 13:41:38 UTC (rev 3854) @@ -1,21 +1,25 @@ import numpy as npy -class Path: +VALIDATE_PATHS = True + +class Path(object): # Path codes STOP = 0 MOVETO = 1 # 1 vertex LINETO = 2 # 1 vertex CURVE3 = 3 # 2 vertices CURVE4 = 4 # 3 vertices + CLOSEPOLY = 5 ### # MGDTODO: I'm not sure these are supported by PS/PDF/SVG, # so if they don't, we probably shouldn't - CURVEN = 5 - CATROM = 6 - UBSPLINE = 7 + CURVEN = 6 + CATROM = 7 + UBSPLINE = 8 #### - CLOSEPOLY = 0x0F # 0 vertices + NUM_VERTICES = [0, 1, 1, 2, 3, 0] + code_type = npy.uint8 def __init__(self, vertices, codes=None, closed=True): @@ -38,9 +42,14 @@ self._codes = codes assert self._codes.ndim == 1 - # MGDTODO: Maybe we should add some quick-and-dirty check that - # the number of vertices is correct for the code array + if VALIDATE_PATHS: + i = 0 + NUM_VERTICES = self.NUM_VERTICES + for code in codes: + i += NUM_VERTICES[code] + assert i == len(self.vertices) + def _get_codes(self): return self._codes codes = property(_get_codes) @@ -48,3 +57,74 @@ def _get_vertices(self): return self._vertices vertices = property(_get_vertices) + + def iter_endpoints(self): + i = 0 + NUM_VERTICES = self.NUM_VERTICES + vertices = self.vertices + for code in self.codes: + num_vertices = NUM_VERTICES[code] + if num_vertices >= 1: + i += num_vertices - 1 + yield vertices[i] + i += 1 + + _unit_rectangle = None + #@classmethod + def unit_rectangle(cls): + if cls._unit_rectangle is None: + cls._unit_rectangle = \ + Path([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]) + return cls._unit_rectangle + unit_rectangle = classmethod(unit_rectangle) + + _unit_regular_polygons = {} + #@classmethod + def unit_regular_polygon(cls, numVertices): + path = cls._unit_regular_polygons.get(numVertices) + if path is None: + theta = 2*npy.pi/numVertices * npy.arange(numVertices) + # This is to make sure the polygon always "points-up" + theta += npy.pi / 2.0 + verts = npy.vstack((npy.cos(theta), npy.sin(theta))).transpose() + path = Path(verts) + cls._unit_regular_polygons[numVertices] = path + return path + unit_regular_polygon = classmethod(unit_regular_polygon) + + _unit_circle = None + #@classmethod + def unit_circle(cls): + # MGDTODO: Optimize? + if cls._unit_circle is None: + offset = 4.0 * (npy.sqrt(2) - 1) / 3.0 + vertices = npy.array( + [[-1.0, 0.0], + + [-1.0, offset], + [-offset, 1.0], + [0.0, 1.0], + + [offset, 1.0], + [1.0, offset], + [1.0, 0.0], + + [1.0, -offset], + [offset, -1.0], + [0.0, -1.0], + + [-offset, -1.0], + [-1.0, -offset], + [-1.0, 0.0]], + npy.float_) + codes = npy.array( + [cls.MOVETO, + cls.CURVE4, + cls.CURVE4, + cls.CURVE4, + cls.CURVE4, + cls.CLOSEPOLY], + cls.code_type) + cls._unit_circle = Path(vertices, codes) + return cls._unit_circle + unit_circle = classmethod(unit_circle) Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-09-15 04:01:56 UTC (rev 3853) +++ branches/transforms/src/_backend_agg.cpp 2007-09-17 13:41:38 UTC (rev 3854) @@ -64,6 +64,20 @@ Py::Float(seq[5])); } +// MGDTODO: Implement this as a nice iterator +inline void get_next_vertex(const char* & vertex_i, const char* vertex_end, + double& x, double& y, + size_t next_vertex_stride, + size_t next_axis_stride) { + if (vertex_i + next_axis_stride >= vertex_end) + throw Py::ValueError("Error parsing path. Read past end of vertices"); + x = *(double*)vertex_i; + y = *(double*)(vertex_i + next_axis_stride); + vertex_i += next_vertex_stride; +} + +#define GET_NEXT_VERTEX(x, y) get_next_vertex(vertex_i, vertex_end, x, y, next_vertex_stride, next_axis_stride) + GCAgg::GCAgg(const Py::Object &gc, double dpi, bool snapto) : dpi(dpi), snapto(snapto), isaa(true), linewidth(1.0), alpha(1.0), cliprect(NULL), clippath(NULL), @@ -1255,146 +1269,134 @@ Py::Object RendererAgg::draw_markers(const Py::Tuple& args) { + typedef agg::conv_transform<agg::path_storage> transformed_path_t; + typedef agg::conv_curve<transformed_path_t> curve_t; + typedef agg::conv_stroke<curve_t> stroke_t; + typedef agg::conv_dash<curve_t> dash_t; + typedef agg::conv_stroke<dash_t> stroke_dash_t; + theRasterizer->reset_clipping(); - _VERBOSE("RendererAgg::_draw_markers_cache"); - args.verify_length(6); + args.verify_length(7); - _VERBOSE("RendererAgg::_draw_markers_cache setting gc"); GCAgg gc = GCAgg(args[0], dpi); + Py::Object marker_path_obj = args[1]; + if (!PathAgg::check(marker_path_obj)) + throw Py::TypeError("Native path object is not of correct type"); + PathAgg* marker_path = static_cast<PathAgg*>(marker_path_obj.ptr()); + agg::trans_affine marker_trans = py_sequence_to_agg_transformation_matrix(args[2]); + Py::Object vertices_obj = args[3]; + Py::Object codes_obj = args[4]; + agg::trans_affine trans = py_sequence_to_agg_transformation_matrix(args[5]); + facepair_t face = _get_rgba_face(args[6], gc.alpha); + + // Deal with the difference in y-axis direction + marker_trans *= agg::trans_affine_scaling(1.0, -1.0); + trans *= agg::trans_affine_scaling(1.0, -1.0); + trans *= agg::trans_affine_translation(0.0, (double)height); + marker_path->rewind(0); + transformed_path_t marker_path_transformed(*marker_path, marker_trans); + curve_t marker_path_curve(marker_path_transformed); - agg::path_storage *ppath; - - swig_type_info * descr = SWIG_TypeQuery("agg::path_storage *"); - assert(descr); - if (SWIG_ConvertPtr(args[1].ptr(),(void **)(&ppath), descr, 0) == -1) { - throw Py::TypeError("Could not convert path_storage"); - } - facepair_t face = _get_rgba_face(args[2], gc.alpha); - - Py::Object xo = args[3]; - Py::Object yo = args[4]; - - PyArrayObject *xa = (PyArrayObject *) PyArray_ContiguousFromObject(xo.ptr(), PyArray_DOUBLE, 1, 1); - - if (xa==NULL) - throw Py::TypeError("RendererAgg::_draw_markers_cache expected numerix array"); - - - PyArrayObject *ya = (PyArrayObject *) PyArray_ContiguousFromObject(yo.ptr(), PyArray_DOUBLE, 1, 1); - - if (ya==NULL) - throw Py::TypeError("RendererAgg::_draw_markers_cache expected numerix array"); - - agg::trans_affine xytrans = py_sequence_to_agg_transformation_matrix(args[5]); - - size_t Nx = xa->dimensions[0]; - size_t Ny = ya->dimensions[0]; - - if (Nx!=Ny) - throw Py::ValueError(Printf("x and y must be equal length arrays; found %d and %d", Nx, Ny).str()); - - - double heightd = double(height); - - - ppath->rewind(0); - ppath->flip_y(0,0); - typedef agg::conv_curve<agg::path_storage> curve_t; - curve_t curve(*ppath); - //maxim's suggestions for cached scanlines agg::scanline_storage_aa8 scanlines; theRasterizer->reset(); agg::int8u* fillCache = NULL; - unsigned fillSize = 0; - if (face.first) { - theRasterizer->add_path(curve); + agg::int8u* strokeCache = NULL; + PyArrayObject* vertices = NULL; + PyArrayObject* codes = NULL; + + try { + vertices = (PyArrayObject*)PyArray_ContiguousFromObject + (vertices_obj.ptr(), PyArray_DOUBLE, 2, 2); + if (!vertices || vertices->nd != 2 || vertices->dimensions[1] != 2) + throw Py::ValueError("Invalid vertices array."); + codes = (PyArrayObject*)PyArray_ContiguousFromObject + (codes_obj.ptr(), PyArray_UINT8, 1, 1); + if (!codes) + throw Py::ValueError("Invalid codes array."); + + unsigned fillSize = 0; + if (face.first) { + theRasterizer->add_path(marker_path_curve); + agg::render_scanlines(*theRasterizer, *slineP8, scanlines); + fillSize = scanlines.byte_size(); + fillCache = new agg::int8u[fillSize]; // or any container + scanlines.serialize(fillCache); + } + + stroke_t stroke(marker_path_curve); + stroke.width(gc.linewidth); + stroke.line_cap(gc.cap); + stroke.line_join(gc.join); + theRasterizer->reset(); + theRasterizer->add_path(stroke); agg::render_scanlines(*theRasterizer, *slineP8, scanlines); - fillSize = scanlines.byte_size(); - fillCache = new agg::int8u[fillSize]; // or any container - scanlines.serialize(fillCache); - } + unsigned strokeSize = scanlines.byte_size(); + strokeCache = new agg::int8u[strokeSize]; // or any container + scanlines.serialize(strokeCache); - agg::conv_stroke<curve_t> stroke(curve); - stroke.width(gc.linewidth); - stroke.line_cap(gc.cap); - stroke.line_join(gc.join); - theRasterizer->reset(); - theRasterizer->add_path(stroke); - agg::render_scanlines(*theRasterizer, *slineP8, scanlines); - unsigned strokeSize = scanlines.byte_size(); - agg::int8u* strokeCache = new agg::int8u[strokeSize]; // or any container - scanlines.serialize(strokeCache); - - theRasterizer->reset_clipping(); - - - if (gc.cliprect==NULL) { - rendererBase->reset_clipping(true); - } - else { - int l = (int)(gc.cliprect[0]) ; - int b = (int)(gc.cliprect[1]) ; - int w = (int)(gc.cliprect[2]) ; - int h = (int)(gc.cliprect[3]) ; - rendererBase->clip_box(l, height-(b+h),l+w, height-b); - } - - - double thisx, thisy; - for (size_t i=0; i<Nx; i++) { - thisx = *(double *)(xa->data + i*xa->strides[0]); - thisy = *(double *)(ya->data + i*ya->strides[0]); - - // MGDTODO -// if (mpltransform->need_nonlinear_api()) -// try { -// mpltransform->nonlinear_only_api(&thisx, &thisy); -// } -// catch(...) { -// continue; -// } + theRasterizer->reset_clipping(); + if (gc.cliprect==NULL) { + rendererBase->reset_clipping(true); + } + else { + int l = (int)(gc.cliprect[0]) ; + int b = (int)(gc.cliprect[1]) ; + int w = (int)(gc.cliprect[2]) ; + int h = (int)(gc.cliprect[3]) ; + rendererBase->clip_box(l, height-(b+h),l+w, height-b); + } - xytrans.transform(&thisx, &thisy); - - thisy = heightd - thisy; //flipy - - thisx = (int)thisx + 0.5; - thisy = (int)thisy + 0.5; - if (thisx<0) continue; - if (thisy<0) continue; - if (thisx>width) continue; - if (thisy>height) continue; - + size_t next_vertex_stride = vertices->strides[0]; + size_t next_axis_stride = vertices->strides[1]; + size_t code_stride = codes->strides[0]; + + const char* vertex_i = vertices->data; + const char* code_i = codes->data; + const char* vertex_end = vertex_i + (vertices->dimensions[0] * vertices->strides[0]); + + size_t N = codes->dimensions[0]; + double x, y; + agg::serialized_scanlines_adaptor_aa8 sa; agg::serialized_scanlines_adaptor_aa8::embedded_scanline sl; - - if (face.first) { - //render the fill - sa.init(fillCache, fillSize, thisx, thisy); - rendererAA->color(face.second); - agg::render_scanlines(sa, sl, *rendererAA); + + for (size_t i=0; i < N; i++) { + size_t num_vertices = NUM_VERTICES[(int)(*code_i)]; + if (num_vertices) { + for (size_t j=0; j<num_vertices; ++j) + GET_NEXT_VERTEX(x, y); + trans.transform(&x, &y); + + if (face.first) { + //render the fill + sa.init(fillCache, fillSize, x, y); + rendererAA->color(face.second); + agg::render_scanlines(sa, sl, *rendererAA); + } + + //render the stroke + sa.init(strokeCache, strokeSize, x, y); + rendererAA->color(gc.color); + agg::render_scanlines(sa, sl, *rendererAA); + } + code_i += code_stride; } - - //render the stroke - sa.init(strokeCache, strokeSize, thisx, thisy); - rendererAA->color(gc.color); - agg::render_scanlines(sa, sl, *rendererAA); - - } //for each marker + } catch(...) { + Py_XDECREF(vertices); + Py_XDECREF(codes); + delete[] fillCache; + delete[] strokeCache; + } - Py_XDECREF(xa); - Py_XDECREF(ya); - - if (face.first) - delete [] fillCache; + Py_XDECREF(vertices); + Py_XDECREF(codes); + delete [] fillCache; delete [] strokeCache; - //jdh - _VERBOSE("RendererAgg::_draw_markers_cache done"); return Py::Object(); } @@ -1552,21 +1554,6 @@ } -inline void get_next_vertex(const char* & vertex_i, const char* vertex_end, - double& x, double& y, - size_t next_vertex_stride, - size_t next_axis_stride) { - if (vertex_i + next_axis_stride >= vertex_end) - throw Py::ValueError("Error parsing path. Read past end of vertices"); - x = *(double*)vertex_i; - y = *(double*)(vertex_i + next_axis_stride); - vertex_i += next_vertex_stride; -} - -#define GET_NEXT_VERTEX(x, y) get_next_vertex(vertex_i, vertex_end, x, y, next_vertex_stride, next_axis_stride) - - - Py::Object RendererAgg::convert_to_native_path(const Py::Tuple& args) { _VERBOSE("RendererAgg::draw_image"); @@ -2059,7 +2046,7 @@ add_varargs_method("draw_lines", &RendererAgg::draw_lines, "draw_lines(gc, x, y,)\n"); add_varargs_method("draw_markers", &RendererAgg::draw_markers, - "draw_markers(gc, path, x, y)\n"); + "draw_markers(gc, marker_path, marker_trans, vertices, codes, rgbFace)\n"); add_varargs_method("draw_text_image", &RendererAgg::draw_text_image, "draw_text_image(font_image, x, y, r, g, b, a)\n"); add_varargs_method("draw_image", &RendererAgg::draw_image, Modified: branches/transforms/src/_backend_agg.h =================================================================== --- branches/transforms/src/_backend_agg.h 2007-09-15 04:01:56 UTC (rev 3853) +++ branches/transforms/src/_backend_agg.h 2007-09-17 13:41:38 UTC (rev 3854) @@ -45,8 +45,10 @@ #define LINETO 2 #define CURVE3 3 #define CURVE4 4 -#define CLOSEPOLY 0x0F +#define CLOSEPOLY 5 +const size_t NUM_VERTICES[] = { 0, 1, 1, 2, 3, 0 }; + typedef agg::pixfmt_rgba32 pixfmt; typedef agg::renderer_base<pixfmt> renderer_base; typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_aa; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-18 16:21:40
|
Revision: 3855 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3855&view=rev Author: mdboom Date: 2007-09-18 09:21:37 -0700 (Tue, 18 Sep 2007) Log Message: ----------- More code using new transformation framework. Lots of dead code removed from backend_agg.cpp/h Modified Paths: -------------- branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/path.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/lib/matplotlib/type1font.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-09-17 13:41:38 UTC (rev 3854) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-09-18 16:21:37 UTC (rev 3855) @@ -39,8 +39,7 @@ def _get_cached_native_path(self, path): native_path = self._native_paths.get(path) if native_path is None: - import matplotlib.patches - print "CACHE MISS", path + # print "CACHE MISS", path native_path = self.convert_to_native_path(path) self._native_paths[path] = native_path return native_path Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-17 13:41:38 UTC (rev 3854) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-18 16:21:37 UTC (rev 3855) @@ -121,13 +121,9 @@ debug=False) if __debug__: verbose.report('RendererAgg.__init__ _RendererAgg done', 'debug-annoying') - # self.draw_polygon = self._renderer.draw_polygon - self.draw_rectangle = self._renderer.draw_rectangle - # MGDTODO -- remove these lines - # self.draw_lines = self._renderer.draw_lines - # self.draw_markers = self._renderer.draw_markers - self.draw_image = self._renderer.draw_image + self.convert_to_native_path = self._renderer.convert_to_native_path + self.draw_image = self._renderer.draw_image self.copy_from_bbox = self._renderer.copy_from_bbox self.restore_region = self._renderer.restore_region self.mathtext_parser = MathTextParser('Agg') @@ -137,12 +133,9 @@ if __debug__: verbose.report('RendererAgg.__init__ done', 'debug-annoying') - def convert_to_native_path(self, path): - return self._renderer.convert_to_native_path(path.vertices, path.codes) - - def _draw_native_path(self, gc, native_path, transform, rgbFace): - return self._renderer.draw_path(gc, native_path, transform.to_values(), rgbFace) - + def _draw_native_path(self, gc, path, transform, rgbFace): + return self._renderer.draw_path(gc, path, transform.get_matrix(), rgbFace) + def draw_arc(self, gcEdge, rgbFace, x, y, width, height, angle1, angle2, rotation): """ Draw an arc centered at x,y with width and height and angles @@ -175,8 +168,8 @@ def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None): return self._renderer.draw_markers( gc, - native_marker_path, marker_trans.to_values(), - path.vertices, path.codes, trans.to_values(), + native_marker_path, marker_trans.get_matrix(), + path.vertices, path.codes, trans.get_matrix(), rgbFace) def draw_polygon(self, *args): Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-09-17 13:41:38 UTC (rev 3854) +++ branches/transforms/lib/matplotlib/lines.py 2007-09-18 16:21:37 UTC (rev 3855) @@ -712,6 +712,7 @@ def _draw_nothing(self, renderer, gc, path): pass + def _draw_steps(self, renderer, gc, xt, yt): # MGDTODO: This is a quirky one. The step-plotting part # should probably be moved to where the path is generated @@ -729,6 +730,7 @@ else: renderer.draw_lines(gc, xt2, yt2) + def _draw_solid(self, renderer, gc, path): gc.set_linestyle('solid') renderer.draw_path(gc, path, self.get_transform()) @@ -753,8 +755,15 @@ def _draw_point(self, renderer, gc, path): - self._draw_circle(renderer, gc, path, point = True) + w = renderer.points_to_pixels(self._markersize) * \ + self._point_size_reduction * 0.5 + rgbFace = self._get_rgb_face() + transform = Affine2D().scale(w) + renderer.draw_markers( + gc, Path.unit_circle(), transform, path, self.get_transform(), + rgbFace) + def _draw_pixel(self, renderer, gc, path): rgbFace = self._get_rgb_face() transform = Affine2D().translate(-0.5, -0.5) @@ -762,12 +771,8 @@ path, self.get_transform(), rgbFace) - def _draw_circle(self, renderer, gc, path, point=False): - w = renderer.points_to_pixels(self._markersize) - if point: - w *= self._point_size_reduction - w *= 0.5 - + def _draw_circle(self, renderer, gc, path): + w = renderer.points_to_pixels(self._markersize) * 0.5 rgbFace = self._get_rgb_face() transform = Affine2D().scale(w, w) renderer.draw_markers( @@ -826,7 +831,8 @@ def _draw_thin_diamond(self, renderer, gc, path): offset = renderer.points_to_pixels(self._markersize) - transform = Affine2D().translate(0.5, 0.5).rotate_deg(45).scale(offset * 0.8, offset) + transform = Affine2D().translate(0.5, 0.5) \ + .rotate_deg(45).scale(offset * 0.8, offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_rectangle(), transform, path, self.get_transform(), rgbFace) @@ -840,7 +846,7 @@ path, self.get_transform(), rgbFace) - def _draw_hexagon1(self, renderer, gc, path, point=False): + def _draw_hexagon1(self, renderer, gc, path): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) rgbFace = self._get_rgb_face() @@ -848,50 +854,44 @@ path, self.get_transform(), rgbFace) - def _draw_hexagon2(self, renderer, gc, xt, yt): + def _draw_hexagon2(self, renderer, gc, path): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(30) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_regular_polygon(6), transform, path, self.get_transform(), rgbFace) - - def _draw_vline(self, renderer, gc, xt, yt): + + _line_marker_path = Path([[0.0, -1.0], [0.0, 1.0]], closed=False) + def _draw_vline(self, renderer, gc, path): offset = 0.5*renderer.points_to_pixels(self._markersize) - if self._newstyle: - path = agg.path_storage() - path.move_to(0, -offset) - path.line_to(0, offset) - renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_line(gc, x, y-offset, x, y+offset) + transform = Affine2D().scale(offset) + renderer.draw_markers(gc, self._line_marker_path, transform, + path, self.get_transform()) - def _draw_hline(self, renderer, gc, xt, yt): + def _draw_hline(self, renderer, gc, path): offset = 0.5*renderer.points_to_pixels(self._markersize) - if self._newstyle: - path = agg.path_storage() - path.move_to(-offset, 0) - path.line_to(offset, 0) - renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_line(gc, x-offset, y, x+offset, y) + transform = Affine2D().scale(offset).rotate_deg(90) + renderer.draw_markers(gc, self._line_marker_path, transform, + path, self.get_transform()) + _tickhoriz_path = Path([[0.0, 0.5], [1.0, 0.5]]) def _draw_tickleft(self, renderer, gc, path): offset = renderer.points_to_pixels(self._markersize) - marker_transform = Affine2D().scale(offset, 1.0) + marker_transform = Affine2D().scale(-offset, 1.0) renderer.draw_markers(gc, self._tickhoriz_path, marker_transform, path, self.get_transform()) + def _draw_tickright(self, renderer, gc, path): offset = renderer.points_to_pixels(self._markersize) - marker_transform = Affine2D().scale(-offset, 1.0) + marker_transform = Affine2D().scale(offset, 1.0) renderer.draw_markers(gc, self._tickhoriz_path, marker_transform, path, self.get_transform()) + _tickvert_path = Path([[-0.5, 0.0], [-0.5, 1.0]]) def _draw_tickup(self, renderer, gc, path): offset = renderer.points_to_pixels(self._markersize) @@ -899,174 +899,99 @@ renderer.draw_markers(gc, self._tickvert_path, marker_transform, path, self.get_transform()) + def _draw_tickdown(self, renderer, gc, path): offset = renderer.points_to_pixels(self._markersize) marker_transform = Affine2D().scale(1.0, -offset) renderer.draw_markers(gc, self._tickvert_path, marker_transform, path, self.get_transform()) - def _draw_plus(self, renderer, gc, xt, yt): + + _plus_path = Path([[-1.0, 0.0], [1.0, 0.0], + [0.0, -1.0], [0.0, 1.0]], + [Path.MOVETO, Path.LINETO, + Path.MOVETO, Path.LINETO]) + def _draw_plus(self, renderer, gc, path): offset = 0.5*renderer.points_to_pixels(self._markersize) - if self._newstyle: + transform = Affine2D().scale(offset) + renderer.draw_markers(gc, self._plus_path, transform, + path, self.get_transform()) - path = agg.path_storage() - path.move_to(-offset, 0) - path.line_to( offset, 0) - path.move_to( 0, -offset) - path.line_to( 0, offset) - renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_line(gc, x-offset, y, x+offset, y) - renderer.draw_line(gc, x, y-offset, x, y+offset) - def _draw_tri_down(self, renderer, gc, xt, yt): + _tri_path = Path([[0.0, 0.0], [0.0, -1.0], + [0.0, 0.0], [0.8, 0.5], + [0.0, 0.0], [-0.8, 0.5]], + [Path.MOVETO, Path.LINETO, + Path.MOVETO, Path.LINETO, + Path.MOVETO, Path.LINETO]) + def _draw_tri_down(self, renderer, gc, path): offset = 0.5*renderer.points_to_pixels(self._markersize) - offset1 = offset*0.8 - offset2 = offset*0.5 - if self._newstyle: - path = agg.path_storage() - path.move_to(0, 0) - path.line_to(0, -offset) - path.move_to(0, 0) - path.line_to(offset1, offset2) - path.move_to(0, 0) - path.line_to(-offset1, offset2) - renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_line(gc, x, y, x, y-offset) - renderer.draw_line(gc, x, y, x+offset1, y+offset2) - renderer.draw_line(gc, x, y, x-offset1, y+offset2) + transform = Affine2D().scale(offset) + renderer.draw_markers(gc, self._tri_path, transform, + path, self.get_transform()) - def _draw_tri_up(self, renderer, gc, xt, yt): + + def _draw_tri_up(self, renderer, gc, path): offset = 0.5*renderer.points_to_pixels(self._markersize) - offset1 = offset*0.8 - offset2 = offset*0.5 - if self._newstyle: - path = agg.path_storage() - path.move_to(0, 0) - path.line_to(0, offset) - path.move_to(0, 0) - path.line_to(offset1, -offset2) - path.move_to(0, 0) - path.line_to(-offset1, -offset2) - renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_line(gc, x, y, x, y+offset) - renderer.draw_line(gc, x, y, x+offset1, y-offset2) - renderer.draw_line(gc, x, y, x-offset1, y-offset2) + transform = Affine2D().scale(offset).rotate_deg(180) + renderer.draw_markers(gc, self._tri_path, transform, + path, self.get_transform()) - def _draw_tri_left(self, renderer, gc, xt, yt): - offset = 0.5*renderer.points_to_pixels(self._markersize) - offset1 = offset*0.8 - offset2 = offset*0.5 - if self._newstyle: - path = agg.path_storage() - path.move_to(0, 0) - path.line_to(-offset, 0) - path.move_to(0, 0) - path.line_to(offset2, offset1) - path.move_to(0, 0) - path.line_to(offset2, -offset1) - renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_line(gc, x, y, x-offset, y) - renderer.draw_line(gc, x, y, x+offset2, y+offset1) - renderer.draw_line(gc, x, y, x+offset2, y-offset1) + + def _draw_tri_left(self, renderer, gc, path): + offset = 0.5*renderer.points_to_pixels(self._markersize) + transform = Affine2D().scale(offset).rotate_deg(90) + renderer.draw_markers(gc, self._tri_path, transform, + path, self.get_transform()) - def _draw_tri_right(self, renderer, gc, xt, yt): - offset = 0.5*renderer.points_to_pixels(self._markersize) - offset1 = offset*0.8 - offset2 = offset*0.5 - if self._newstyle: - path = agg.path_storage() - path.move_to(0, 0) - path.line_to(offset, 0) - path.move_to(0, 0) - path.line_to(-offset2, offset1) - path.move_to(0, 0) - path.line_to(-offset2, -offset1) - renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_line(gc, x, y, x+offset, y) - renderer.draw_line(gc, x, y, x-offset2, y+offset1) - renderer.draw_line(gc, x, y, x-offset2, y-offset1) + + def _draw_tri_right(self, renderer, gc, path): + offset = 0.5*renderer.points_to_pixels(self._markersize) + transform = Affine2D().scale(offset).rotate_deg(270) + renderer.draw_markers(gc, self._tri_path, transform, + path, self.get_transform()) - def _draw_caretdown(self, renderer, gc, xt, yt): + + _caret_path = Path([[-1.0, 1.5], [0.0, 0.0], [1.0, 1.5]], closed=False) + def _draw_caretdown(self, renderer, gc, path): offset = 0.5*renderer.points_to_pixels(self._markersize) - offset1 = 1.5*offset - if self._newstyle: - path = agg.path_storage() - path.move_to(-offset, offset1) - path.line_to(0, 0) - path.line_to(+offset, offset1) - renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_line(gc, x-offset, y+offset1, x, y) - renderer.draw_line(gc, x, y, x+offset, y+offset1) + transform = Affine2D().scale(offset) + renderer.draw_markers(gc, self._caret_path, transform, + path, self.get_transform()) - def _draw_caretup(self, renderer, gc, xt, yt): + + def _draw_caretup(self, renderer, gc, path): offset = 0.5*renderer.points_to_pixels(self._markersize) - offset1 = 1.5*offset - if self._newstyle: - path = agg.path_storage() - path.move_to(-offset, -offset1) - path.line_to(0, 0) - path.line_to(+offset, -offset1) - renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_line(gc, x-offset, y-offset1, x, y) - renderer.draw_line(gc, x, y, x+offset, y-offset1) + transform = Affine2D().scale(offset).rotate_deg(180) + renderer.draw_markers(gc, self._caret_path, transform, + path, self.get_transform()) - def _draw_caretleft(self, renderer, gc, xt, yt): + + def _draw_caretleft(self, renderer, gc, path): offset = 0.5*renderer.points_to_pixels(self._markersize) - offset1 = 1.5*offset - if self._newstyle: - path = agg.path_storage() - path.move_to(offset1, -offset) - path.line_to(0, 0) - path.line_to(offset1, offset) - renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_line(gc, x+offset1, y-offset, x, y) - renderer.draw_line(gc, x, y, x+offset1, y+offset) + transform = Affine2D().scale(offset).rotate_deg(90) + renderer.draw_markers(gc, self._caret_path, transform, + path, self.get_transform()) - def _draw_caretright(self, renderer, gc, xt, yt): + + def _draw_caretright(self, renderer, gc, path): offset = 0.5*renderer.points_to_pixels(self._markersize) - offset1 = 1.5*offset - if self._newstyle: - path = agg.path_storage() - path.move_to(-offset1, -offset) - path.line_to(0, 0) - path.line_to(-offset1, offset) - renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_line(gc, x-offset1, y-offset, x, y) - renderer.draw_line(gc, x, y, x-offset1, y+offset) + transform = Affine2D().scale(offset).rotate_deg(270) + renderer.draw_markers(gc, self._caret_path, transform, + path, self.get_transform()) + + _x_path = Path([[-1.0, -1.0], [1.0, 1.0], + [-1.0, 1.0], [1.0, -1.0]], + [Path.MOVETO, Path.LINETO, + Path.MOVETO, Path.LINETO]) def _draw_x(self, renderer, gc, xt, yt): offset = 0.5*renderer.points_to_pixels(self._markersize) + transform = Affine2D().scale(offset) + renderer.draw_markers(gc, self._x_path, transform, + path, self.get_transform()) - if self._newstyle: - path = agg.path_storage() - path.move_to(-offset, -offset) - path.line_to(offset, offset) - path.move_to(-offset, offset) - path.line_to(offset, -offset) - renderer.draw_markers(gc, path, None, xt, yt, self.get_transform()) - else: - for (x,y) in zip(xt, yt): - renderer.draw_line(gc, x-offset, y-offset, x+offset, y+offset) - renderer.draw_line(gc, x-offset, y+offset, x+offset, y-offset) - + def update_from(self, other): 'copy properties from other to self' Artist.update_from(self, other) Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-09-17 13:41:38 UTC (rev 3854) +++ branches/transforms/lib/matplotlib/path.py 2007-09-18 16:21:37 UTC (rev 3855) @@ -50,6 +50,9 @@ i += NUM_VERTICES[code] assert i == len(self.vertices) + def __repr__(self): + return "Path(%s, %s)" % (self.vertices, self.codes) + def _get_codes(self): return self._codes codes = property(_get_codes) Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-09-17 13:41:38 UTC (rev 3854) +++ branches/transforms/lib/matplotlib/transforms.py 2007-09-18 16:21:37 UTC (rev 3855) @@ -88,11 +88,13 @@ intervaly = property(_get_intervaly) def _get_width(self): - return self.xmax - self.xmin + points = self.get_points() + return points[1, 0] - points[0, 0] width = property(_get_width) def _get_height(self): - return self.ymax - self.ymin + points = self.get_points() + return points[1, 1] - points[0, 1] height = property(_get_height) def _get_bounds(self): Modified: branches/transforms/lib/matplotlib/type1font.py =================================================================== --- branches/transforms/lib/matplotlib/type1font.py 2007-09-17 13:41:38 UTC (rev 3854) +++ branches/transforms/lib/matplotlib/type1font.py 2007-09-18 16:21:37 UTC (rev 3855) @@ -1,15 +1,15 @@ """ A class representing a Type 1 font. -This version merely allows reading in pfa and pfb files, stores the -data in pfa format, and allows reading the parts of the data in a -format suitable for embedding in pdf files. A more complete class -might support subsetting. +This version merely reads pfa and pfb files and splits them for +embedding in pdf files. There is no support yet for subsetting or +anything like that. -Usage: font = Type1Font(filename) - somefile.write(font.data) # writes out font in pfa format - len1, len2, len3 = font.lengths() # needed for pdf embedding +Usage (subject to change): + font = Type1Font(filename) + clear_part, encrypted_part, finale = font.parts + Source: Adobe Technical Note #5040, Supporting Downloadable PostScript Language Fonts. @@ -32,8 +32,7 @@ def _read(self, file): rawdata = file.read() if not rawdata.startswith(chr(128)): - self.data = rawdata - return + return rawdata data = '' while len(rawdata) > 0: @@ -101,4 +100,6 @@ if __name__ == '__main__': import sys font = Type1Font(sys.argv[1]) - sys.stdout.write(font.data) + parts = font.parts + print len(parts[0]), len(parts[1]), len(parts[2]) + Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-09-17 13:41:38 UTC (rev 3854) +++ branches/transforms/src/_backend_agg.cpp 2007-09-18 16:21:37 UTC (rev 3855) @@ -10,7 +10,6 @@ #include <time.h> #include <algorithm> - #include "agg_conv_transform.h" #include "agg_conv_curve.h" #include "agg_scanline_storage_aa.h" @@ -43,28 +42,48 @@ #define M_PI_2 1.57079632679489661923 #endif -agg::trans_affine py_sequence_to_agg_transformation_matrix(const Py::Object& obj) { - Py::SeqBase<Py::Float> seq; +/** A helper function to convert from a Numpy affine transformation matrix + * to an agg::trans_affine. + */ +agg::trans_affine py_to_agg_transformation_matrix(const Py::Object& obj) { + PyArrayObject* matrix = NULL; + + double a = 1.0, b = 0.0, c = 0.0, d = 1.0, e = 0.0, f = 0.0; + try { - seq = obj; - } catch(...) { - throw Py::ValueError("Transformation matrix must be given as a 6-element list."); - } + matrix = (PyArrayObject*) PyArray_ContiguousFromObject(obj.ptr(), PyArray_DOUBLE, 2, 2); + if (!matrix || matrix->nd != 2 || matrix->dimensions[0] != 3 || matrix->dimensions[1] != 3) { + throw Py::ValueError("Invalid affine transformation matrix."); + } - if (seq.size() != 6) { - throw Py::ValueError("Transformation matrix must be given as a 6-element list."); + size_t stride0 = matrix->strides[0]; + size_t stride1 = matrix->strides[1]; + char* row0 = matrix->data; + char* row1 = row0 + stride0; + + a = *(double*)(row0); + row0 += stride1; + c = *(double*)(row0); + row0 += stride1; + e = *(double*)(row0); + + b = *(double*)(row1); + row1 += stride1; + d = *(double*)(row1); + row1 += stride1; + f = *(double*)(row1); + } catch (...) { + Py_XDECREF(matrix); } - return agg::trans_affine - (Py::Float(seq[0]), - Py::Float(seq[1]), - Py::Float(seq[2]), - Py::Float(seq[3]), - Py::Float(seq[4]), - Py::Float(seq[5])); + Py_XDECREF(matrix); + + return agg::trans_affine(a, b, c, d, e, f); } -// MGDTODO: Implement this as a nice iterator +/** Helper function to get the next vertex in a Numpy array of vertices. + * Will generally be used through the GET_NEXT_VERTEX macro. + */ inline void get_next_vertex(const char* & vertex_i, const char* vertex_end, double& x, double& y, size_t next_vertex_stride, @@ -78,12 +97,18 @@ #define GET_NEXT_VERTEX(x, y) get_next_vertex(vertex_i, vertex_end, x, y, next_vertex_stride, next_axis_stride) +Py::Object BufferRegion::to_string(const Py::Tuple &args) { + + // owned=true to prevent memory leak + return Py::String(PyString_FromStringAndSize((const char*)aggbuf.data,aggbuf.height*aggbuf.stride), true); +} + + GCAgg::GCAgg(const Py::Object &gc, double dpi, bool snapto) : dpi(dpi), snapto(snapto), isaa(true), linewidth(1.0), alpha(1.0), cliprect(NULL), clippath(NULL), Ndash(0), dashOffset(0.0), dasha(NULL) { - _VERBOSE("GCAgg::GCAgg"); linewidth = points_to_pixels ( gc.getAttr("_linewidth") ) ; alpha = Py::Float( gc.getAttr("_alpha") ); @@ -100,7 +125,6 @@ GCAgg::_set_antialiased(const Py::Object& gc) { _VERBOSE("GCAgg::antialiased"); isaa = Py::Int( gc.getAttr( "_antialiased") ); - } agg::rgba @@ -123,13 +147,12 @@ return p * dpi/72.0; } - void GCAgg::_set_linecap(const Py::Object& gc) { _VERBOSE("GCAgg::_set_linecap"); std::string capstyle = Py::String( gc.getAttr( "_capstyle" ) ); - + if (capstyle=="butt") cap = agg::butt_cap; else if (capstyle=="round") @@ -138,7 +161,6 @@ cap = agg::square_cap; else throw Py::ValueError(Printf("GC _capstyle attribute must be one of butt, round, projecting; found %s", capstyle.c_str()).str()); - } void @@ -155,7 +177,6 @@ join = agg::bevel_join; else throw Py::ValueError(Printf("GC _joinstyle attribute must be one of butt, round, projecting; found %s", joinstyle.c_str()).str()); - } void @@ -193,7 +214,7 @@ } } - +// MGDTODO: Convert directly from Bbox object (numpy) void GCAgg::_set_clip_rectangle( const Py::Object& gc) { //set the clip rectangle from the gc @@ -204,7 +225,7 @@ cliprect = NULL; Py::Object o ( gc.getAttr( "_cliprect" ) ); - if (o.ptr()==Py_None) { + if (o.ptr() == Py_None) { return; } @@ -229,38 +250,18 @@ _VERBOSE("GCAgg::_set_clip_path"); - delete clippath; + Py_XINCREF(clippath); clippath = NULL; - Py::Object o = gc.getAttr( "_clippath" ); + Py::Object o = gc.getAttr("_clippath"); if (o.ptr()==Py_None) { return; } - agg::path_storage *tmppath; - swig_type_info * descr = SWIG_TypeQuery("agg::path_storage *"); - assert(descr); - if (SWIG_ConvertPtr(o.ptr(),(void **)(&tmppath), descr, 0) == -1) { - throw Py::TypeError("Could not convert gc path_storage"); - } - - tmppath->rewind(0); - clippath = new agg::path_storage(); - clippath->copy_from(*tmppath); - clippath->rewind(0); - tmppath->rewind(0); + clippath = new PathAgg(o); } -Py::Object BufferRegion::to_string(const Py::Tuple &args) { - - // owned=true to prevent memory leak - return Py::String(PyString_FromStringAndSize((const char*)aggbuf.data,aggbuf.height*aggbuf.stride), true); -} - - - - const size_t RendererAgg::PIXELS_PER_INCH(96); @@ -311,19 +312,14 @@ void -RendererAgg::set_clipbox_rasterizer( double *cliprect) { +RendererAgg::set_clipbox_rasterizer(double *cliprect) { //set the clip rectangle from the gc _VERBOSE("RendererAgg::set_clipbox_rasterizer"); - theRasterizer->reset_clipping(); rendererBase->reset_clipping(true); - //if (cliprect==NULL) { - // theRasterizer->reset_clipping(); - // rendererBase->reset_clipping(true); - //} if (cliprect!=NULL) { double l = cliprect[0] ; @@ -355,273 +351,10 @@ } -// MGDTODO: Remove this method (it has been conglomerated into draw_path -template <class VS> -void -RendererAgg::_fill_and_stroke(VS& path, - const GCAgg& gc, - const facepair_t& face, - bool curvy) { - typedef agg::conv_curve<VS> curve_t; - - //bool isclippath(gc.clippath!=NULL); - //if (isclippath) _process_alpha_mask(gc); - - if (face.first) { - rendererAA->color(face.second); - if (curvy) { - curve_t curve(path); - theRasterizer->add_path(curve); - } - else - theRasterizer->add_path(path); - - /* - if (isclippath) { - typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type; - typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type; - pixfmt_amask_type pfa(*pixFmt, *alphaMask); - amask_ren_type r(pfa); - typedef agg::renderer_scanline_aa_solid<amask_ren_type> renderer_type; - renderer_type ren(r); - ren.color(gc.color); - //std::cout << "render clippath" << std::endl; - - agg::render_scanlines(*theRasterizer, *slineP8, ren); - } - else { - rendererAA->color(gc.color); - agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); - } - */ - agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); - } - - //now stroke the edge - if (gc.linewidth) { - if (curvy) { - curve_t curve(path); - agg::conv_stroke<curve_t> stroke(curve); - stroke.width(gc.linewidth); - stroke.line_cap(gc.cap); - stroke.line_join(gc.join); - theRasterizer->add_path(stroke); - } - else { - agg::conv_stroke<VS> stroke(path); - stroke.width(gc.linewidth); - stroke.line_cap(gc.cap); - stroke.line_join(gc.join); - theRasterizer->add_path(stroke); - } - - - /* - if ( gc.isaa ) { - if (isclippath) { - typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type; - typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type; - pixfmt_amask_type pfa(*pixFmt, *alphaMask); - amask_ren_type r(pfa); - typedef agg::renderer_scanline_aa_solid<amask_ren_type> renderer_type; - renderer_type ren(r); - ren.color(gc.color); - //std::cout << "render clippath" << std::endl; - - agg::render_scanlines(*theRasterizer, *slineP8, ren); - } - else { - rendererAA->color(gc.color); - agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); - } - } - else { - if (isclippath) { - typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type; - typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type; - pixfmt_amask_type pfa(*pixFmt, *alphaMask); - amask_ren_type r(pfa); - typedef agg::renderer_scanline_bin_solid<amask_ren_type> renderer_type; - renderer_type ren(r); - ren.color(gc.color); - agg::render_scanlines(*theRasterizer, *slineP8, ren); - } - else{ - rendererBin->color(gc.color); - agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin); - } - } - - */ - - if ( gc.isaa ) { - rendererAA->color(gc.color); - agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); - } - else { - rendererBin->color(gc.color); - agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin); - } - } - - -} - -Py::Object -RendererAgg::draw_rectangle(const Py::Tuple & args) { - _VERBOSE("RendererAgg::draw_rectangle"); - args.verify_length(6); - - - GCAgg gc = GCAgg(args[0], dpi); - facepair_t face = _get_rgba_face(args[1], gc.alpha); - - - double l = Py::Float( args[2] ); - double b = Py::Float( args[3] ); - double w = Py::Float( args[4] ); - double h = Py::Float( args[5] ); - - b = height - (b+h); - double r = l + w; - double t = b + h; - - //snapto pixel centers - l = (int)l + 0.5; - b = (int)b + 0.5; - r = (int)r + 0.5; - t = (int)t + 0.5; - - - set_clipbox_rasterizer(gc.cliprect); - - agg::path_storage path; - - - path.move_to(l, t); - path.line_to(r, t); - path.line_to(r, b); - path.line_to(l, b); - path.close_polygon(); - - _fill_and_stroke(path, gc, face, false); - - return Py::Object(); - -} - -Py::Object -RendererAgg::draw_ellipse(const Py::Tuple& args) { - _VERBOSE("RendererAgg::draw_ellipse"); - args.verify_length(7); - - GCAgg gc = GCAgg(args[0], dpi); - facepair_t face = _get_rgba_face(args[1], gc.alpha); - - double x = Py::Float( args[2] ); - double y = Py::Float( args[3] ); - double w = Py::Float( args[4] ); - double h = Py::Float( args[5] ); - double rot = Py::Float( args[6] ); - - double r; // rot in radians - - set_clipbox_rasterizer(gc.cliprect); - - // Approximate the ellipse with 4 bezier paths - agg::path_storage path; - if (rot == 0.0) // simple case - { - path.move_to(x, height-(y+h)); - path.arc_to(w, h, 0.0, false, true, x+w, height-y); - path.arc_to(w, h, 0.0, false, true, x, height-(y-h)); - path.arc_to(w, h, 0.0, false, true, x-w, height-y); - path.arc_to(w, h, 0.0, false, true, x, height-(y+h)); - path.close_polygon(); - } - else // rotate by hand :( - { - // deg to rad - r = rot * (M_PI/180.0); - path.move_to( x+(cos(r)*w), height-(y+(sin(r)*w))); - path.arc_to(w, h, -r, false, true, x+(cos(r+M_PI_2*3)*h), height-(y+(sin(r+M_PI_2*3)*h))); - path.arc_to(w, h, -r, false, true, x+(cos(r+M_PI)*w), height-(y+(sin(r+M_PI)*w))); - path.arc_to(w, h, -r, false, true, x+(cos(r+M_PI_2)*h), height-(y+(sin(r+M_PI_2)*h))); - path.arc_to(w, h, -r, false, true, x+(cos(r)*w), height-(y+(sin(r)*w))); - path.close_polygon(); - } - - _fill_and_stroke(path, gc, face); - return Py::Object(); - -} - -Py::Object -RendererAgg::draw_polygon(const Py::Tuple& args) { - _VERBOSE("RendererAgg::draw_polygon"); - - args.verify_length(3); - - GCAgg gc = GCAgg(args[0], dpi); - facepair_t face = _get_rgba_face(args[1], gc.alpha); - - Py::SeqBase<Py::Object> points( args[2] ); - - set_clipbox_rasterizer(gc.cliprect); - - size_t Npoints = points.length(); - if (Npoints<=0) - return Py::Object(); - - - // dump the x.y vertices into a double array for faster look ahead - // and behind access - double *xs = new double[Npoints]; - double *ys = new double[Npoints]; - - for (size_t i=0; i<Npoints; i++) { - Py::SeqBase<Py::Object> xy(points[i]); - xy = Py::Tuple(points[i]); - xs[i] = Py::Float(xy[0]); - ys[i] = Py::Float(xy[1]); - ys[i] = height - ys[i]; - } - - - - agg::path_storage path; - for (size_t j=0; j<Npoints; j++) { - - double x = xs[j]; - double y = ys[j]; - - //snapto pixel centers - x = (int)x + 0.5; - y = (int)y + 0.5; - - if (j==0) path.move_to(x,y); - else path.line_to(x,y); - } - path.close_polygon(); - - _fill_and_stroke(path, gc, face, false); - - delete [] xs; - delete [] ys; - - _VERBOSE("RendererAgg::draw_polygon DONE"); - return Py::Object(); - -} - - - SnapData SafeSnap::snap (const float& x, const float& y) { xsnap = (int)x + 0.5; ysnap = (int)y + 0.5; - - if ( first || ( (xsnap!=lastxsnap) || (ysnap!=lastysnap) ) ) { lastxsnap = xsnap; @@ -690,9 +423,6 @@ rb.copy_from(*renderingBuffer, &r, -r.x1, -r.y1); BufferRegion* reg = new BufferRegion(buf, r, true); return Py::asObject(reg); - - - } Py::Object @@ -715,25 +445,20 @@ rendererBase->copy_from(rbuf, 0, region->rect.x1, region->rect.y1); return Py::Object(); - - - } - +/** + * Helper function to convert a Python Bbox object to an agg rectangle + */ template<class T> agg::rect_base<T> RendererAgg::bbox_to_rect(const Py::Object& o) { //return the agg::rect for bbox, flipping y PyArrayObject *bbox = (PyArrayObject *) PyArray_ContiguousFromObject(o.ptr(), PyArray_DOUBLE, 2, 2); - if (!bbox) + if (!bbox || bbox->nd != 2 bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2) throw Py::TypeError ("Expected a Bbox object."); - - if (bbox->nd != 2 || bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2) - throw Py::TypeError - ("Expected a Bbox object."); double l = bbox->data[0]; double b = bbox->data[1]; @@ -805,469 +530,8 @@ return numIntersect; } -void RendererAgg::DrawQuadMesh(int meshWidth, int meshHeight, const agg::rgba8 colorArray[], const double xCoords[], const double yCoords[]) -{ - /* draw each quadrilateral */ - // agg::renderer_primitives<agg::renderer_base<agg::pixfmt_rgba32> > lineRen(*rendererBase); - int i = 0; - int j = 0; - int k = 0; - double xs[4]; - double ys[4]; - int col[4]; - int numCol; - double ymin; - int firstRow; - double ymax; - int lastRow; - for(i=0; i < meshHeight; i++) - { - for(j=0; j < meshWidth; j++) - { - //currTime = clock(); - xs[0] = xCoords[(i * (meshWidth + 1)) + j]; - ys[0] = yCoords[(i * (meshWidth + 1)) + j]; - xs[1] = xCoords[(i * (meshWidth + 1)) + j+1]; - ys[1] = yCoords[(i * (meshWidth + 1)) + j+1]; - xs[3] = xCoords[((i+1) * (meshWidth + 1)) + j]; - ys[3] = yCoords[((i+1) * (meshWidth + 1)) + j]; - xs[2] = xCoords[((i+1) * (meshWidth + 1)) + j+1]; - ys[2] = yCoords[((i+1) * (meshWidth + 1)) + j+1]; - ymin = std::min(std::min(std::min(ys[0], ys[1]), ys[2]), ys[3]); - ymax = std::max(std::max(std::max(ys[0], ys[1]), ys[2]), ys[3]); - firstRow = (int)(ymin); - lastRow = (int)(ymax); - //timer1 += (clock() - currTime); - //currTime = clock(); - //timer2 += (clock() - currTime); - //currTime = clock(); - for(k = firstRow; k <= lastRow; k++) - { - numCol = inPolygon(k, xs, ys, col); - if (numCol >= 2) rendererBase->copy_hline(col[0], k, col[1] - 1, colorArray[(i * meshWidth) + j]); - if (numCol == 4) rendererBase->copy_hline(col[2], k, col[3] - 1, colorArray[(i * meshWidth) + j]); - } - } - } - return; -} -void RendererAgg::DrawQuadMeshEdges(int meshWidth, int meshHeight, const agg::rgba8 colorArray[], const double xCoords[], const double yCoords[]) -{ - int i, j; - agg::renderer_primitives<agg::renderer_base<agg::pixfmt_rgba32> > lineRen(*rendererBase); - agg::rgba8 lc(0, 0, 0, 32); - lineRen.line_color(lc); - /* show the vertical edges */ - for(i=0; i <= meshWidth; i++) - { - lineRen.move_to((int)(256.0 * (xCoords[i])), (int)(256.0 * (yCoords[i]))); - for(j=1; j <= meshHeight; j++) - lineRen.line_to((int)(256.0 *(xCoords[(j * (meshWidth + 1))+i])), (int)(256.0 * (yCoords[(j * (meshWidth + 1))+i]))); - } - /* show the horizontal edges */ - for(i=0; i <= meshHeight; i++) - { - lineRen.move_to((int)(256.0 * (xCoords[i * (meshWidth + 1)])), (int)(256.0 * (yCoords[i * (meshWidth + 1)]))); - for(j=1; j <= meshWidth; j++) - lineRen.line_to((int)(256.0 * (xCoords[(i * (meshWidth + 1))+j])), (int)(256.0 * (yCoords[(i * (meshWidth + 1))+j]))); - } -} - - - Py::Object -RendererAgg::draw_lines(const Py::Tuple& args) { - - _VERBOSE("RendererAgg::draw_lines"); - args.verify_length(4); - - Py::Object xo = args[1]; - Py::Object yo = args[2]; - - PyArrayObject *xa = (PyArrayObject *) PyArray_ContiguousFromObject(xo.ptr(), PyArray_DOUBLE, 1, 1); - - if (xa==NULL) - throw Py::TypeError("RendererAgg::draw_lines expected numerix array"); - - - PyArrayObject *ya = (PyArrayObject *) PyArray_ContiguousFromObject(yo.ptr(), PyArray_DOUBLE, 1, 1); - - if (ya==NULL) - throw Py::TypeError("RendererAgg::draw_lines expected numerix array"); - - - size_t Nx = xa->dimensions[0]; - size_t Ny = ya->dimensions[0]; - - if (Nx!=Ny) - throw Py::ValueError(Printf("x and y must be equal length arrays; found %d and %d", Nx, Ny).str()); - - // call gc with snapto==True if line len is 2 to fix grid line - // problem - bool snapto = false; - if (Nx==2) { - // disable subpiel rendering for len(2) horizontal or vertical - // lines - double x0 = *(double *)(xa->data + 0*xa->strides[0]); - double x1 = *(double *)(xa->data + 1*xa->strides[0]); - double y0 = *(double *)(ya->data + 0*ya->strides[0]); - double y1 = *(double *)(ya->data + 1*ya->strides[0]); - snapto = (x0==x1) || (y0==y1); - - } - GCAgg gc = GCAgg(args[0], dpi, snapto); - - set_clipbox_rasterizer(gc.cliprect); - //path_t transpath(path, xytrans); - _process_alpha_mask(gc); - - agg::trans_affine xytrans = py_sequence_to_agg_transformation_matrix(args[3]); - - agg::path_storage path; - - // MGDTODO - bool needNonlinear = false; - // mpltransform->need_nonlinear_api(); - - double thisx(0.0), thisy(0.0); - double origdx(0.0), origdy(0.0), origdNorm2(0); - bool moveto = true; - double heightd = height; - - double lastx(0), lasty(0); - double lastWrittenx(0), lastWritteny(0); - bool clipped = false; - - bool haveMin = false, lastMax = true; - double dnorm2Min(0), dnorm2Max(0); - double maxX(0), maxY(0), minX(0), minY(0); - - double totdx, totdy, totdot; - double paradx, parady, paradNorm2; - double perpdx, perpdy, perpdNorm2; - - int counter = 0; - //idea: we can skip drawing many lines: lines < 1 pixel in length, lines - //outside of the drawing area, and we can combine sequential parallel lines - //into a single line instead of redrawing lines over the same points. - //The loop below works a bit like a state machine, where what it does depends - //on what it did in the last looping. To test whether sequential lines - //are close to parallel, I calculate the distance moved perpendicular to the - //last line. Once it gets too big, the lines cannot be combined. - for (size_t i=0; i<Nx; i++) { - - thisx = *(double *)(xa->data + i*xa->strides[0]); - thisy = *(double *)(ya->data + i*ya->strides[0]); - - if (needNonlinear) - try { - // MGDTODO - // mpltransform->nonlinear_only_api(&thisx, &thisy); - } - catch (...) { - moveto = true; - continue; - } - if (MPL_isnan64(thisx) || MPL_isnan64(thisy)) { - moveto = true; - continue; - } - - //use agg's transformer? - xytrans.transform(&thisx, &thisy); - thisy = heightd - thisy; //flipy - - if (snapto) { - //disable subpixel rendering for horizontal or vertical lines of len=2 - //because it causes irregular line widths for grids and ticks - thisx = (int)thisx + 0.5; - thisy = (int)thisy + 0.5; - } - - //if we are starting a new path segment, move to the first point + init - if(moveto){ - path.move_to(thisx, thisy); - lastx = thisx; - lasty = thisy; - origdNorm2 = 0; //resets the orig-vector variables (see if-statement below) - moveto = false; - continue; - } - - //don't render line segments less that on pixel long! - if (fabs(thisx-lastx) < 1.0 && fabs(thisy-lasty) < 1.0 ){ - continue; //don't update lastx this time! - } - - //skip any lines that are outside the drawing area. Note: More lines - //could be clipped, but a more involved calculation would be needed - if( (thisx < 0 && lastx < 0 ) || - (thisx > width && lastx > width ) || - (thisy < 0 && lasty < 0 ) || - (thisy > height && lasty > height) ){ - lastx = thisx; - lasty = thisy; - clipped = true; - continue; - } - - //if we have no orig vector, set it to this vector and continue. - //this orig vector is the reference vector we will build up the line to - if(origdNorm2 == 0){ - //if we clipped after the moveto but before we got here, redo the moveto - if(clipped){ - path.move_to(lastx, lasty); - clipped = false; - } - - origdx = thisx - lastx; - origdy = thisy - lasty; - origdNorm2 = origdx*origdx + origdy*origdy; - - //set all the variables to reflect this new orig vecor - dnorm2Max = origdNorm2; - dnorm2Min = 0; - haveMin = false; - lastMax = true; - maxX = thisx; - maxY = thisy; - minX = lastx; - minY = lasty; - - lastWrittenx = lastx; - lastWritteny = lasty; - - //set the last point seen - lastx = thisx; - lasty = thisy; - continue; - } - - //if got to here, then we have an orig vector and we just got - //a vector in the sequence. - - //check that the perpendicular distance we have moved from the - //last written point compared to the line we are building is not too - //much. If o is the orig vector (we are building on), and v is the vector - //from the last written point to the current point, then the perpendicular - //vector is p = v - (o.v)o, and we normalize o (by dividing the - //second term by o.o). - - //get the v vector - totdx = thisx - lastWrittenx; - totdy = thisy - lastWritteny; - totdot = origdx*totdx + origdy*totdy; - - //get the para vector ( = (o.v)o/(o.o) ) - paradx = totdot*origdx/origdNorm2; - parady = totdot*origdy/origdNorm2; - paradNorm2 = paradx*paradx + parady*parady; - - //get the perp vector ( = v - para ) - perpdx = totdx - paradx; - perpdy = totdy - parady; - perpdNorm2 = perpdx*perpdx + perpdy*perpdy; - - //if the perp vector is less than some number of (squared) pixels in size, - //then merge the current vector - if(perpdNorm2 < 0.25 ){ - //check if the current vector is parallel or - //anti-parallel to the orig vector. If it is parallel, test - //if it is the longest of the vectors we are merging in that direction. - //If anti-p, test if it is the longest in the opposite direction (the - //min of our final line) - - lastMax = false; - if(totdot >= 0){ - if(paradNorm2 > dnorm2Max){ - lastMax = true; - dnorm2Max = paradNorm2; - maxX = lastWrittenx + paradx; - maxY = lastWritteny + parady; - } - } - else{ - - haveMin = true; - if(paradNorm2 > dnorm2Min){ - dnorm2Min = paradNorm2; - minX = lastWrittenx + paradx; - minY = lastWritteny + parady; - } - } - - lastx = thisx; - lasty = thisy; - continue; - } - - //if we get here, then this vector was not similar enough to the line - //we are building, so we need to draw that line and start the next one. - - //if the line needs to extend in the opposite direction from the direction - //we are drawing in, move back to we start drawing from back there. - if(haveMin){ - path.line_to(minX, minY); //would be move_to if not for artifacts - } - - path.line_to(maxX, maxY); - - //if we clipped some segments between this line and the next line - //we are starting, we also need to move to the last point. - if(clipped){ - path.move_to(lastx, lasty); - } - else if(!lastMax){ - //if the last line was not the longest line, then move back to the end - //point of the last line in the sequence. Only do this if not clipped, - //since in that case lastx,lasty is not part of the line just drawn. - path.line_to(lastx, lasty); //would be move_to if not for artifacts - } - - //std::cout << "draw lines (" << lastx << ", " << lasty << ")" << std::endl; - - //now reset all the variables to get ready for the next line - - origdx = thisx - lastx; - origdy = thisy - lasty; - origdNorm2 = origdx*origdx + origdy*origdy; - - dnorm2Max = origdNorm2; - dnorm2Min = 0; - haveMin = false; - lastMax = true; - maxX = thisx; - maxY = thisy; - minX = lastx; - minY = lasty; - - lastWrittenx = lastx; - lastWritteny = lasty; - - clipped = false; - - lastx = thisx; - lasty = thisy; - - counter++; - } - - //draw the last line, which is usually not drawn in the loop - if(origdNorm2 != 0){ - if(haveMin){ - path.line_to(minX, minY); //would be move_to if not for artifacts - } - - path.line_to(maxX, maxY); - } - - //std::cout << "drew " << counter+1 << " lines" << std::endl; - - Py_XDECREF(xa); - Py_XDECREF(ya); - - //typedef agg::conv_transform<agg::path_storage, agg::trans_affine> path_t; - //path_t transpath(path, xytrans); - _VERBOSE("RendererAgg::draw_lines rendering lines path"); - _render_lines_path(path, gc); - - _VERBOSE("RendererAgg::draw_lines DONE"); - return Py::Object(); - -} - -bool -RendererAgg::_process_alpha_mask(const GCAgg& gc) - //if gc has a clippath set, process the alpha mask and return True, - //else return False -{ - if (gc.clippath==NULL) { - return false; - } - if (0 &(gc.clippath==lastclippath)) { - //std::cout << "seen it" << std::endl; - return true; - } - rendererBaseAlphaMask->clear(agg::gray8(0, 0)); - gc.clippath->rewind(0); - theRasterizer->add_path(*(gc.clippath)); - rendererAlphaMask->color(agg::gray8(255,255)); - agg::render_scanlines(*theRasterizer, *scanlineAlphaMask, *rendererAlphaMask); - lastclippath = gc.clippath; - return true; -} - -template<class PathSource> -void -RendererAgg::_render_lines_path(PathSource &path, const GCAgg& gc) { - _VERBOSE("RendererAgg::_render_lines_path"); - typedef PathSource path_t; - //typedef agg::conv_transform<agg::path_storage, agg::trans_affine> path_t; - typedef agg::conv_stroke<path_t> stroke_t; - typedef agg::conv_dash<path_t> dash_t; - - bool isclippath(gc.clippath!=NULL); - - if (gc.dasha==NULL ) { //no dashes - stroke_t stroke(path); - stroke.width(gc.linewidth); - stroke.line_cap(gc.cap); - stroke.line_join(gc.join); - theRasterizer->add_path(stroke); - } - else { - dash_t dash(path); - - //todo: dash.dash_start(gc.dashOffset); - for (size_t i=0; i<gc.Ndash/2; i+=1) - dash.add_dash(gc.dasha[2*i], gc.dasha[2*i+1]); - - agg::conv_stroke<dash_t> stroke(dash); - stroke.line_cap(gc.cap); - stroke.line_join(gc.join); - stroke.width(gc.linewidth); - theRasterizer->add_path(stroke); //boyle freeze is herre - } - - - if ( gc.isaa ) { - if (isclippath) { - typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type; - typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type; - pixfmt_amask_type pfa(*pixFmt, *alphaMask); - amask_ren_type r(pfa); - typedef agg::renderer_scanline_aa_solid<amask_ren_type> renderer_type; - renderer_type ren(r); - ren.color(gc.color); - //std::cout << "render clippath" << std::endl; - - agg::render_scanlines(*theRasterizer, *slineP8, ren); - } - else { - rendererAA->color(gc.color); - agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); - } - } - else { - if (isclippath) { - typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type; - typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type; - pixfmt_amask_type pfa(*pixFmt, *alphaMask); - amask_ren_type r(pfa); - typedef agg::renderer_scanline_bin_solid<amask_ren_type> renderer_type; - renderer_type ren(r); - ren.color(gc.color); - agg::render_scanlines(*theRasterizer, *slineP8, ren); - } - else{ - rendererBin->color(gc.color); - agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin); - } - } -} - -Py::Object RendererAgg::draw_markers(const Py::Tuple& args) { typedef agg::conv_transform<agg::path_storage> transformed_path_t; typedef agg::conv_curve<transformed_path_t> curve_t; @@ -1284,10 +548,10 @@ if (!PathAgg::check(marker_path_obj)) throw Py::TypeError("Native path object is not of correct type"); PathAgg* marker_path = static_cast<PathAgg*>(marker_path_obj.ptr()); - agg::trans_affine marker_trans = py_sequence_to_agg_transformation_matrix(args[2]); + agg::trans_affine marker_trans = py_to_agg_transformation_matrix(args[2]); Py::Object vertices_obj = args[3]; Py::Object codes_obj = args[4]; - agg::trans_affine trans = py_sequence_to_agg_transformation_matrix(args[5]); + agg::trans_affine trans = py_to_agg_transformation_matrix(args[5]); facepair_t face = _get_rgba_face(args[6], gc.alpha); // Deal with the difference in y-axis direction @@ -1337,7 +601,8 @@ unsigned strokeSize = scanlines.byte_size(); strokeCache = new agg::int8u[strokeSize]; // or any container scanlines.serialize(strokeCache); - + + // MGDTODO: Clean this up and support clippaths as well theRasterizer->reset_clipping(); if (gc.cliprect==NULL) { rendererBase->reset_clipping(true); @@ -1557,14 +822,20 @@ Py::Object RendererAgg::convert_to_native_path(const Py::Tuple& args) { _VERBOSE("RendererAgg::draw_image"); - args.verify_length(2); + args.verify_length(1); - Py::Object vertices_obj = args[0]; - Py::Object codes_obj = args[1]; + Py::Object path = args[0]; + + return Py::asObject(new PathAgg(path)); +} + +PathAgg::PathAgg(const Py::Object& path_obj) : curvy(false) { + Py::Object vertices_obj = path_obj.getAttr("vertices"); + Py::Object codes_obj = path_obj.getAttr("codes"); + PyArrayObject* vertices = NULL; PyArrayObject* codes = NULL; - PathAgg* path = NULL; try { vertices = (PyArrayObject*)PyArray_ContiguousFromObject @@ -1576,8 +847,6 @@ if (!codes) throw Py::ValueError("Invalid codes array."); - path = new PathAgg(); - size_t next_vertex_stride = vertices->strides[0]; size_t next_axis_stride = vertices->strides[1]; size_t code_stride = codes->strides[0]; @@ -1593,31 +862,31 @@ switch (*(unsigned char*)(code_i)) { case MOVETO: GET_NEXT_VERTEX(x0, y0); - path->move_to(x0, y0); + move_to(x0, y0); _VERBOSE("MOVETO"); break; case LINETO: GET_NEXT_VERTEX(x0, y0); - path->line_to(x0, y0); + line_to(x0, y0); _VERBOSE("LINETO"); break; case CURVE3: GET_NEXT_VERTEX(x0, y0); GET_NEXT_VERTEX(x1, y1); - path->curve3(x0, y0, x1, y1); - path->curvy = true; + curve3(x0, y0, x1, y1); + curvy = true; _VERBOSE("CURVE3"); break; case CURVE4: GET_NEXT_VERTEX(x0, y0); GET_NEXT_VERTEX(x1, y1); GET_NEXT_VERTEX(x2, y2); - path->curve4(x0, y0, x1, y1, x2, y2); - path->curvy = true; + curve4(x0, y0, x1, y1, x2, y2); + curvy = true; _VERBOSE("CURVE4"); break; case CLOSEPOLY: - path->close_polygon(); + close_polygon(); _VERBOSE("CLOSEPOLY"); break; } @@ -1626,14 +895,11 @@ } catch(...) { Py_XDECREF(vertices); Py_XDECREF(codes); - delete path; throw; } Py_XDECREF(vertices); Py_XDECREF(codes); - - return Py::asObject(path); } Py::Object @@ -1643,7 +909,11 @@ typedef agg::conv_stroke<curve_t> stroke_t; typedef agg::conv_dash<curve_t> dash_t; typedef agg::conv_stroke<dash_t> stroke_dash_t; - //draw_path(gc, rgbFace, path, transform) + typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type; + typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type; + typedef agg::renderer_scanline_aa_solid<amask_ren_type> amask_aa_renderer_type; + typedef agg::renderer_scanline_bin_solid<amask_ren_type> amask_bin_renderer_type; + theRasterizer->reset_clipping(); _VERBOSE("RendererAgg::draw_path"); @@ -1654,52 +924,118 @@ if (!PathAgg::check(path_obj)) throw Py::TypeError("Native path object is not of correct type"); PathAgg* path = static_cast<PathAgg*>(path_obj.ptr()); - agg::trans_affine trans = py_sequence_to_agg_transformation_matrix(args[2]); + agg::trans_affine trans = py_to_agg_transformation_matrix(args[2]); facepair_t face = _get_rgba_face(args[3], gc.alpha); trans *= agg::trans_affine_scaling(1.0, -1.0); trans *= agg::trans_affine_translation(0.0, (double)height); - transformed_path_t tpath(*path, trans); - // MGDTODO: See if there is any advantage to only curving if necessary - curve_t curve(tpath); + transformed_path_t* tpath = NULL; + agg::path_storage new_path; - set_clipbox_rasterizer(gc.cliprect); - - if (face.first) { - rendererAA->color(face.second); - theRasterizer->add_path(curve); - agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); + bool has_clippath = (gc.clippath != NULL); + + if (has_clippath && (gc.clippath != lastclippath || trans != lastclippath_transform)) { + rendererBaseAlphaMask->clear(agg::gray8(0, 0)); + gc.clippath->rewind(0); + transformed_path_t transformed_clippath(*(gc.clippath), trans); + theRasterizer->add_path(transformed_clippath); + rendererAlphaMask->color(agg::gray8(255, 255)); + agg::render_scanlines(*theRasterizer, *scanlineAlphaMask, *rendererAlphaMask); + lastclippath = gc.clippath; + lastclippath_transform = trans; } - if (gc.linewidth) { - if (gc.dasha == NULL) { - stroke_t stroke(curve); - stroke.width(gc.linewidth); - stroke.line_cap(gc.cap); - stroke.line_join(gc.join); - theRasterizer->add_path(stroke); - } else { - dash_t dash(curve); - for (size_t i = 0; i < (gc.Ndash / 2); ++i) - dash.add_dash(gc.dasha[2 * i], gc.dasha[2 * i + 1]); - stroke_dash_t stroke(dash); - stroke.line_cap(gc.cap); - stroke.line_join(gc.join); - stroke.width(gc.linewidth); - theRasterizer->add_path(stroke); //boyle freeze is herre + try { + // If this is a straight horizontal or vertical line, quantize to nearest + // pixels + if (path->total_vertices() == 2) { + double x0, y0, x1, y1; + path->vertex(0, &x0, &y0); + trans.transform(&x0, &y0); + path->vertex(1, &x1, &y1); + trans.transform(&x1, &y1); + if (((int)x0 == (int)x1) || ((int)y0 == (int)y1)) { + new_path.move_to((int)x0 + 0.5, (int)y0 + 0.5); + new_path.line_to((int)x1 + 0.5, (int)y1 + 0.5); + tpath = new transformed_path_t(new_path, agg::trans_affine()); + } } + + if (!tpath) { + tpath = new transformed_path_t(*path, trans); + } + + // Benchmarking shows that there is no noticable slowdown to always + // treating paths as having curved segments. Doing so greatly + // simplifies the code + curve_t curve(*tpath); - if ( gc.isaa ) { - rendererAA->color(gc.color); - agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); + set_clipbox_rasterizer(gc.cliprect); + + if (face.first) { + if (has_clippath) { + pixfmt_amask_type pfa(*pixFmt, *alphaMask); + amask_ren_type r(pfa); + amask_aa_renderer_type ren(r); + ren.color(gc.color); + agg::render_scanlines(*theRasterizer, *slineP8, ren); + } else{ + rendererAA->color(face.second); + theRasterizer->add_path(curve); + agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); + } } - else { - rendererBin->color(gc.color); - agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin); + + if (gc.linewidth) { + if (gc.dasha == NULL) { + stroke_t stroke(curve); + stroke.width(gc.linewidth); + stroke.line_cap(gc.cap); + stroke.line_join(gc.join); + theRasterizer->add_path(stroke); + } else { + dash_t dash(curve); + for (size_t i = 0; i < (gc.Ndash / 2); ++i) + dash.add_dash(gc.dasha[2 * i], gc.dasha[2 * i + 1]); + stroke_dash_t stroke(dash); + stroke.line_cap(gc.cap); + stroke.line_join(gc.join); + stroke.width(gc.linewidth); + theRasterizer->add_path(stroke); + } + + if (gc.isaa) { + if (has_clippath) { + pixfmt_amask_type pfa(*pixFmt, *alphaMask); + amask_ren_type r(pfa); + amask_aa_renderer_type ren(r); + ren.color(gc.color); + agg::render_scanlines(*theRasterizer, *slineP8, ren); + } else { + rendererAA->color(gc.color); + agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); + } + } else { + if (has_clippath) { + pixfmt_amask_type pfa(*pixFmt, *alphaMask); + amask_ren_type r(pfa); + amask_bin_renderer_type ren(r); + ren.color(gc.color); + agg::render_scanlines(*theRasterizer, *slineP8, ren); + } else { + rendererBin->color(gc.color); + agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin); + } + } } + } catch (...) { + delete tpath; + throw; } + delete tpath; + return Py::Object(); } @@ -2033,18 +1369,10 @@ behaviors().name("RendererAgg"); behaviors().doc("The agg backend extension module"); - add_varargs_method("draw_rectangle", &RendererAgg::draw_rectangle, - "draw_rectangle(gc, rgbFace, l, b, w, h)\n"); - add_varargs_method("draw_ellipse", &RendererAgg::draw_ellipse, - "draw_ellipse(gc, rgbFace, x, y, w, h)\n"); - add_varargs_method("draw_polygon", &RendererAgg::draw_polygon, - "draw_polygon(gc, rgbFace, points)\n"); add_varargs_method("draw_path",... [truncated message content] |
From: <md...@us...> - 2007-09-18 19:29:24
|
Revision: 3856 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3856&view=rev Author: mdboom Date: 2007-09-18 12:29:21 -0700 (Tue, 18 Sep 2007) Log Message: ----------- Optimize shared axes (to prevent calling set_xlim/set_ylim more than once per axes per update). Save figure at correct dpi. General cleanup and optimizations. Modified Paths: -------------- branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/axis.py branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/backends/backend_gtkagg.py branches/transforms/lib/matplotlib/backends/backend_tkagg.py branches/transforms/lib/matplotlib/cbook.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/legend.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/src/_backend_agg.cpp Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/axes.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -435,6 +435,9 @@ 1 : 'log', } + _shared_x_axes = cbook.Grouper() + _shared_y_axes = cbook.Grouper() + def __str__(self): return "Axes(%g,%g;%gx%g)" % tuple(self._position.bounds) def __init__(self, fig, rect, @@ -491,6 +494,10 @@ # must be set before set_figure self._sharex = sharex self._sharey = sharey + if sharex is not None: + self._shared_x_axes.join(self, sharex) + if sharey is not None: + self._shared_y_axes.join(self, sharey) # Flag: True if some other Axes instance is sharing our x or y axis self._masterx = False self._mastery = False @@ -502,7 +509,6 @@ # this call may differ for non-sep axes, eg polar self._init_axis() - if axisbg is None: axisbg = rcParams['axes.facecolor'] self._axisbg = axisbg self._frameon = frameon @@ -616,55 +622,28 @@ #these will be updated later as data is added self._set_lim_and_transforms() - def _shared_xlim_callback(self, ax): - xmin, xmax = ax.get_xlim() - self.set_xlim(xmin, xmax, emit=False) - self.figure.canvas.draw_idle() - - def _shared_ylim_callback(self, ax): - ymin, ymax = ax.get_ylim() - self.set_ylim(ymin, ymax, emit=False) - self.figure.canvas.draw_idle() - def _set_lim_and_transforms(self): """ set the dataLim and viewLim BBox attributes and the transData and transAxes Transformation attributes """ - Bbox = mtransforms.Bbox - self.viewLim = Bbox.unit() + self.viewLim = mtransforms.Bbox.unit() + self.dataLim = mtransforms.Bbox.unit() - if self._sharex is not None: - # MGDTODO: This may be doing at least one too many updates - # than necessary - self._sharex.callbacks.connect( - 'xlim_changed', self._shared_xlim_callback) - self.viewLim.intervalx = self._sharex.viewLim.intervalx - if self._sharey is not None: - self._sharey.callbacks.connect( - 'ylim_changed', self._shared_ylim_callback) - self.viewLim.intervaly = self._sharex.viewLim.intervaly - - self.dataLim = Bbox.unit() - self.transAxes = mtransforms.BboxTransform( - Bbox.unit(), self.bbox) - + mtransforms.Bbox.unit(), self.bbox) self.transData = mtransforms.BboxTransform( self.viewLim, self.bbox) def get_position(self, original=False): 'Return the axes rectangle left, bottom, width, height' - # MGDTODO: This changed from returning a list to returning a Bbox - # If you get any errors with the result of this function, please - # update the calling code if original: - return copy.copy(self._originalPosition) + return self._originalPosition else: - return copy.copy(self._position) - # return [val.get() for val in self._position] + return self._position + def set_position(self, pos, which='both'): """ Set the axes position with pos = [left, bottom, width, height] @@ -699,8 +678,7 @@ self.xaxis.cla() self.yaxis.cla() - # MGDTODO - # self.dataLim.ignore(1) + self.ignore_existing_data_limits = True self.callbacks = cbook.CallbackRegistry(('xlim_changed', 'ylim_changed')) if self._sharex is not None: @@ -886,7 +864,7 @@ return - l,b,w,h = self.get_position(original=True) + l,b,w,h = self.get_position(original=True).bounds box_aspect = fig_aspect * (h/w) data_ratio = box_aspect / A @@ -1152,7 +1130,7 @@ # Otherwise, it will compute the bounds of it's current data # and the data in xydata xys = npy.asarray(xys) - self.dataLim.update_numerix_xy(xys, -1) + self.update_datalim_numerix(xys[:, 0], xys[:, 1]) def update_datalim_numerix(self, x, y): @@ -1161,10 +1139,9 @@ # limits and set the bound to be the bounds of the xydata. # Otherwise, it will compute the bounds of it's current data # and the data in xydata - #print type(x), type(y) - # MGDTODO ## self.dataLim.update_numerix(x, y, -1) - self.dataLim.update_from_data(x, y) + self.dataLim.update_from_data(x, y, self.ignore_existing_data_limits) + self.ignore_existing_data_limits = False def _get_verts_in_data_coords(self, trans, xys): if trans == self.transData: @@ -1264,9 +1241,7 @@ if not self.get_visible(): return renderer.open_group('axes') self.apply_aspect() - # MGDTODO -- this is where we can finalize all of the transforms - # self.transData.freeze() # eval the lazy objects - # self.transAxes.freeze() + if self.axison and self._frameon: self.axesPatch.draw(renderer) artists = [] @@ -1314,17 +1289,13 @@ if self.axison and self._frameon: artists.append(self.axesFrame) - # keep track of i to guarantee stable sort for python 2.2 - dsu = [ (a.zorder, i, a) for i, a in enumerate(artists) - if not a.get_animated()] + dsu = [ (a.zorder, a) for a in artists + if not a.get_animated() ] dsu.sort() - for zorder, i, a in dsu: + for zorder, a in dsu: a.draw(renderer) - # MGDTODO - # self.transData.thaw() # release the lazy objects - # self.transAxes.thaw() # release the lazy objects renderer.close_group('axes') self._cachedRenderer = renderer @@ -1509,7 +1480,6 @@ ACCEPTS: len(2) sequence of floats """ - if xmax is None and iterable(xmin): xmin,xmax = xmin @@ -1534,11 +1504,10 @@ self.viewLim.intervalx = (xmin, xmax) if emit: self.callbacks.process('xlim_changed', self) - # MGDTODO: It would be nice to do this is in the above callback list, - # but it's difficult to tell how to initialize this at the - # right time - if self._sharex: - self._sharex.set_xlim(*self.viewLim.intervalx) + # Call all of the other x-axes that are shared with this one + for other in self._shared_x_axes.get_siblings(self): + if other is not self: + other.set_xlim(self.viewLim.xmin, self.viewLim.xmax, emit=False) return xmin, xmax @@ -1665,11 +1634,10 @@ self.viewLim.intervaly = (ymin, ymax) if emit: self.callbacks.process('ylim_changed', self) - # MGDTODO: It would be nice to do this is in the above callback list, - # but it's difficult to tell how to initialize this at the - # right time - if self._sharey: - self._sharey.set_ylim(*self.viewLim.intervaly) + # Call all of the other y-axes that are shared with this one + for other in self._shared_y_axes.get_siblings(self): + if other is not self: + other.set_ylim(self.viewLim.ymin, self.viewLim.ymax, emit=False) return ymin, ymax Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/axis.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -1033,8 +1033,7 @@ bbox = Bbox.union(bboxes) bottom = bbox.ymin - self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi/72.0)) -# self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi.get()/72.0)) MGDTODO + self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi / 72.0)) else: if not len(bboxes2): @@ -1057,7 +1056,6 @@ bbox = Bbox.union(bboxes) bottom = bbox.ymin self.offsetText.set_position((x, bottom-self.OFFSETTEXTPAD*self.figure.dpi/72.0)) -# self.offsetText.set_position((x, bottom-self.OFFSETTEXTPAD*self.figure.dpi.get()/72.0)) MGDTODO def set_ticks_position(self, position): """ @@ -1225,7 +1223,6 @@ left = bbox.xmin self.label.set_position( (left-self.LABELPAD*self.figure.dpi/72.0, y)) - # self.label.set_position( (left-self.LABELPAD*self.figure.dpi.get()/72.0, y)) MGDTODO else: if not len(bboxes2): @@ -1245,7 +1242,6 @@ x,y = self.offsetText.get_position() top = self.axes.bbox.ymax self.offsetText.set_position((x, top+self.OFFSETTEXTPAD*self.figure.dpi/72.0)) -# self.offsetText.set_position((x, top+self.OFFSETTEXTPAD*self.figure.dpi.get()/72.0)) MGDTODO def set_offset_position(self, position): assert position == 'left' or position == 'right' Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -18,8 +18,9 @@ """An abstract base class to handle drawing/rendering operations """ # This will cache paths across rendering instances - # Each subclass of RenderBase should define this --> - # _paths = weakref.WeakKeyDictionary() + # Each subclass of RenderBase should define this a weak-keyed + # dictionary to hold native paths + # _native_paths = weakref.WeakKeyDictionary() def __init__(self): self._texmanager = None @@ -44,7 +45,7 @@ self._native_paths[path] = native_path return native_path - def draw_path(self, gc, path, transform, rgbFace = None): + def draw_path(self, gc, path, transform, rgbFace=None): """ Handles the caching of the native path associated with the given path and calls the underlying backend's _draw_path to @@ -67,17 +68,31 @@ passed to them in draw_path. """ return path + + def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): + native_marker_path = self._get_cached_native_path(marker_path) + self._draw_native_markers(gc, native_marker_path, marker_trans, path, trans, rgbFace) - def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2, - rotation): + def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None): """ - Draw an arc using GraphicsContext instance gcEdge, centered at x,y, - with width and height and angles from 0.0 to 360.0 - 0 degrees is at 3-o'clock - positive angles are anti-clockwise - draw rotated 'rotation' degrees anti-clockwise about x,y + This method is currently underscore hidden because the + draw_markers method is being used as a sentinel for newstyle + backend drawing - If the color rgbFace is not None, fill the arc with it. + path - a matplotlib.agg.path_storage instance + + Draw the marker specified in path with graphics context gc at + each of the locations in arrays x and y. trans is a + matplotlib.transforms.Transformation instance used to + transform x and y to display coords. It consists of an + optional nonlinear component and an affine. You can access + these two components as + + if transform.need_nonlinear(): + x,y = transform.nonlinear_only_numerix(x, y) + # the a,b,c,d,tx,ty affine which transforms x and y + vec6 = transform.as_vec6_val() + ...backend dependent affine... """ raise NotImplementedError @@ -109,30 +124,21 @@ """ return False - def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): - native_marker_path = self._get_cached_native_path(marker_path) - self._draw_native_markers(gc, native_marker_path, marker_trans, path, trans, rgbFace) - - def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None): + ###################################################################### + ## OLD API IS BELOW + ## These functions no longer need to be implemented in the backends -- + ## they now perform all of their functions in terms of the new API. + + def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2, + rotation): """ - This method is currently underscore hidden because the - draw_markers method is being used as a sentinel for newstyle - backend drawing + Draw an arc using GraphicsContext instance gcEdge, centered at x,y, + with width and height and angles from 0.0 to 360.0 + 0 degrees is at 3-o'clock + positive angles are anti-clockwise + draw rotated 'rotation' degrees anti-clockwise about x,y - path - a matplotlib.agg.path_storage instance - - Draw the marker specified in path with graphics context gc at - each of the locations in arrays x and y. trans is a - matplotlib.transforms.Transformation instance used to - transform x and y to display coords. It consists of an - optional nonlinear component and an affine. You can access - these two components as - - if transform.need_nonlinear(): - x,y = transform.nonlinear_only_numerix(x, y) - # the a,b,c,d,tx,ty affine which transforms x and y - vec6 = transform.as_vec6_val() - ...backend dependent affine... + If the color rgbFace is not None, fill the arc with it. """ raise NotImplementedError @@ -346,8 +352,10 @@ If rgbFace is not None, fill the rectangle with it. """ - raise NotImplementedError - + warnings.warn("draw_rectangle called", warnings.PendingDeprecationWarning) + transform = transforms.Affine2D().scale(width, height).translate(x, y) + self.draw_path(gcEdge, Path.unit_rectangle(), transform, rgbFace) + def draw_regpoly_collection( self, clipbox, offsets, transOffset, verts, sizes, facecolors, edgecolors, linewidths, antialiaseds): @@ -1221,8 +1229,6 @@ origfacecolor = self.figure.get_facecolor() origedgecolor = self.figure.get_edgecolor() - # MGDTODO - # self.figure.dpi.set(dpi) self.figure.dpi = dpi self.figure.set_facecolor(facecolor) self.figure.set_edgecolor(edgecolor) @@ -1236,12 +1242,12 @@ orientation=orientation, **kwargs) finally: - # MGDTODO - # self.figure.dpi.set(origDPI) self.figure.dpi = origDPI self.figure.set_facecolor(origfacecolor) self.figure.set_edgecolor(origedgecolor) self.figure.set_canvas(self) + + self.draw() return result @@ -1623,8 +1629,8 @@ lims.append( (xmin, xmax, ymin, ymax) ) # Store both the original and modified positions pos.append( ( - a.get_position(True), - a.get_position() ) ) + copy.copy(a.get_position(True)), + copy.copy(a.get_position() )) ) self._views.push(lims) self._positions.push(pos) self.set_history_buttons() Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -114,9 +114,6 @@ self.height = height if __debug__: verbose.report('RendererAgg.__init__ width=%s, \ height=%s'%(width, height), 'debug-annoying') - # MGDTODO -# self._renderer = _RendererAgg(int(width), int(height), dpi.get(), -# debug=False) self._renderer = _RendererAgg(int(width), int(height), dpi, debug=False) if __debug__: verbose.report('RendererAgg.__init__ _RendererAgg done', @@ -136,35 +133,6 @@ def _draw_native_path(self, gc, path, transform, rgbFace): return self._renderer.draw_path(gc, path, transform.get_matrix(), rgbFace) - def draw_arc(self, gcEdge, rgbFace, x, y, width, height, angle1, angle2, rotation): - """ - Draw an arc centered at x,y with width and height and angles - from 0.0 to 360.0 - - If rgbFace is not None, fill the rectangle with that color. gcEdge - is a GraphicsContext instance - - Currently, I'm only supporting ellipses, ie angle args are - ignored - """ - if __debug__: verbose.report('RendererAgg.draw_arc', 'debug-annoying') - self._renderer.draw_ellipse( - gcEdge, rgbFace, x, y, width/2, height/2, rotation) # ellipse takes radius - - - def draw_line(self, gc, x1, y1, x2, y2): - """ - x and y are equal length arrays, draw lines connecting each - point in x, y - """ - if __debug__: verbose.report('RendererAgg.draw_line', 'debug-annoying') - x = npy.array([x1,x2], float) - y = npy.array([y1,y2], float) - self._renderer.draw_lines(gc, x, y) - - def draw_lines(self, gc, x, y, transform): - return self._renderer.draw_lines(gc, x, y, transform.to_values()) - def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None): return self._renderer.draw_markers( gc, @@ -172,18 +140,6 @@ path.vertices, path.codes, trans.get_matrix(), rgbFace) - def draw_polygon(self, *args): - return self._renderer.draw_polygon(*args) - - def draw_point(self, gc, x, y): - """ - Draw a single point at x,y - """ - if __debug__: verbose.report('RendererAgg.draw_point', 'debug-annoying') - rgbFace = gc.get_rgb() - self._renderer.draw_ellipse( - gc, rgbFace, x, y, 0.5, 0.5, 0.0) - def draw_mathtext(self, gc, x, y, s, prop, angle): """ Draw the math text using matplotlib.mathtext @@ -192,8 +148,6 @@ 'debug-annoying') ox, oy, width, height, descent, font_image, used_characters = \ self.mathtext_parser.parse(s, self.dpi, prop) -# ox, oy, width, height, descent, font_image, used_characters = \ -# self.mathtext_parser.parse(s, self.dpi.get(), prop) MGDTODO x = int(x) + ox y = int(y) - oy @@ -227,7 +181,6 @@ # (in vector space) in the above call to font.set_text. self._renderer.draw_text_image(font.get_image(), int(x), int(y) + 1, angle, gc) - def get_text_width_height_descent(self, s, prop, ismath, rgb=(0,0,0)): """ get the width and height in display coords of the string s @@ -241,7 +194,7 @@ # todo: handle props size = prop.get_size_in_points() texmanager = self.get_texmanager() - Z = texmanager.get_rgba(s, size, self.dpi.get(), rgb) + Z = texmanager.get_rgba(s, size, self.dpi, rgb) m,n,tmp = Z.shape # TODO: descent of TeX text (I am imitating backend_ps here -JKS) return n, m, 0 @@ -249,8 +202,6 @@ if ismath: ox, oy, width, height, descent, fonts, used_characters = \ self.mathtext_parser.parse(s, self.dpi, prop) -# ox, oy, width, height, descent, fonts, used_characters = \ -# self.mathtext_parser.parse(s, self.dpi.get(), prop) MGDTODO return width, height, descent font = self._get_agg_font(prop) font.set_text(s, 0.0, flags=LOAD_DEFAULT) # the width and height of unrotated string @@ -265,7 +216,7 @@ # todo, handle props, angle, origins rgb = gc.get_rgb() size = prop.get_size_in_points() - dpi = self.dpi.get() + dpi = self.dpi flip = angle==90 w,h,d = self.get_text_width_height_descent(s, prop, 'TeX', rgb) @@ -306,7 +257,6 @@ 'return the canvas width and height in display coords' return self.width, self.height - def _get_agg_font(self, prop): """ Get the font for text instance t, cacheing for efficiency @@ -325,11 +275,9 @@ font.clear() size = prop.get_size_in_points() font.set_size(size, self.dpi) - # font.set_size(size, self.dpi.get()) MGDTODO return font - def points_to_pixels(self, points): """ convert point measures to pixes using dpi and the pixels per @@ -337,8 +285,6 @@ """ if __debug__: verbose.report('RendererAgg.points_to_pixels', 'debug-annoying') - # MGDTODO - # return points*self.dpi.get()/72.0 return points*self.dpi/72.0 def tostring_rgb(self): @@ -404,9 +350,7 @@ self.figure.draw(self.renderer) def get_renderer(self): - l,b,w,h = self.figure.bbox.bounds - # MGDTODO - # key = w, h, self.figure.dpi.get() + l, b, w, h = self.figure.bbox.bounds key = w, h, self.figure.dpi try: self._lastKey, self.renderer except AttributeError: need_new_renderer = True Modified: branches/transforms/lib/matplotlib/backends/backend_gtkagg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_gtkagg.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/backends/backend_gtkagg.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -60,7 +60,6 @@ w,h = widget.window.get_size() if w==1 or h==1: return # empty fig - # dpival = self.figure.dpi.get() MGDTODO # compute desired figure size in inches dpival = self.figure.dpi winch = w/dpival Modified: branches/transforms/lib/matplotlib/backends/backend_tkagg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_tkagg.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/backends/backend_tkagg.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -175,7 +175,6 @@ self._resize_callback(event) # compute desired figure size in inches - # dpival = self.figure.dpi.get() MGDTODO dpival = self.figure.dpi winch = width/dpival hinch = height/dpival Modified: branches/transforms/lib/matplotlib/cbook.py =================================================================== --- branches/transforms/lib/matplotlib/cbook.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/cbook.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -955,6 +955,84 @@ outstream.write("Examining: %r\n" % (obj,)) recurse(obj, obj, { }, []) +class Grouper(object): + """ + This class provides a lightweight way to group arbitrary objects + together into disjoint sets when a full-blown graph data structure + would be overkill. + + Objects can be joined using .join(), tested for connectedness + using .joined(), and all disjoint sets can be retreived using + .get(). + + The objects being joined must be hashable. + + For example: + + >>> g = grouper.Grouper() + >>> g.join('a', 'b') + >>> g.join('b', 'c') + >>> g.join('d', 'e') + >>> list(g.get()) + [['a', 'b', 'c'], ['d', 'e']] + >>> g.joined('a', 'b') + True + >>> g.joined('a', 'c') + True + >>> g.joined('a', 'd') + False""" + def __init__(self, init=[]): + mapping = self._mapping = {} + for x in init: + mapping[x] = [x] + + def join(self, a, *args): + """ + Join given arguments into the same set. + Accepts one or more arguments. + """ + mapping = self._mapping + set_a = mapping.setdefault(a, [a]) + + for arg in args: + set_b = mapping.get(arg) + if set_b is None: + set_a.append(arg) + mapping[arg] = set_a + elif set_b is not set_a: + if len(set_b) > len(set_a): + set_a, set_b = set_b, set_a + set_a.extend(set_b) + for elem in set_b: + mapping[elem] = set_a + + def joined(self, a, b): + """ + Returns True if a and b are members of the same set. + """ + mapping = self._mapping + try: + return mapping[a] is mapping[b] + except KeyError: + return False + + def __iter__(self): + """ + Returns an iterator returning each of the disjoint sets as a list. + """ + seen = set() + for elem, group in self._mapping.iteritems(): + if elem not in seen: + yield group + seen.update(group) + + def get_siblings(self, a): + """ + Returns all of the items joined with the given item, including + itself. + """ + return self._mapping.get(a, [a]) + if __name__=='__main__': assert( allequal([1,1,1]) ) assert(not allequal([1,1,0]) ) Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/figure.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -161,10 +161,8 @@ def _get_dpi(self): return self._dpi def _set_dpi(self, dpi): - print "setting dpi" self._dpi = dpi self._dpi_scale_trans.clear().scale(dpi, dpi) - print self._dpi_scale_trans dpi = property(_get_dpi, _set_dpi) def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'): @@ -178,10 +176,7 @@ bottom : the bottom of the subplots for subplots_adjust rotation: the rotation of the xtick labels ha : the horizontal alignment of the xticklabels - - """ - for ax in self.get_axes(): if not hasattr(ax, 'is_last_row'): raise RuntimeError('Axes must be subplot instances; found %s'%type(ax)) @@ -333,11 +328,8 @@ dpival = self.dpi self.bbox_inches.max = w, h - # self.figwidth.set(w) MGDTODO - # self.figheight.set(h) if forward: - # dpival = self.dpi.get() dpival = self.dpi canvasw = w*dpival canvash = h*dpival @@ -347,7 +339,6 @@ def get_size_inches(self): return self.bbox_inches.max - # return self.figwidth.get(), self.figheight.get() MGDTODO def get_edgecolor(self): 'Get the edge color of the Figure rectangle' @@ -360,7 +351,6 @@ def get_figwidth(self): 'Return the figwidth as a float' return self.bbox_inches.xmax - # return self.figwidth.get() MGDTODO def get_figheight(self): 'Return the figheight as a float' @@ -369,7 +359,6 @@ def get_dpi(self): 'Return the dpi as a float' return self.dpi - # return self.dpi.get() MGDTODO def get_frameon(self): 'get the boolean indicating frameon' @@ -397,7 +386,6 @@ ACCEPTS: float """ - # self.dpi.set(val) MGDTODO self.dpi = val def set_figwidth(self, val): @@ -406,7 +394,6 @@ ACCEPTS: float """ - # self.figwidth.set(val) MGDTODO self.bbox_inches.xmax = val def set_figheight(self, val): @@ -415,7 +402,6 @@ ACCEPTS: float """ - # MGDTODO (set()) self.bbox_inches.ymax = val def set_frameon(self, b): @@ -598,8 +584,6 @@ #print 'figure draw' if not self.get_visible(): return renderer.open_group('figure') - # MGDTODO - # self.transFigure.freeze() # eval the lazy objects if self.frameon: self.figurePatch.draw(renderer) @@ -633,8 +617,6 @@ for legend in self.legends: legend.draw(renderer) - # MGDTODO - # self.transFigure.thaw() # release the lazy objects renderer.close_group('figure') self._cachedRenderer = renderer Modified: branches/transforms/lib/matplotlib/legend.py =================================================================== --- branches/transforms/lib/matplotlib/legend.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/legend.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -21,7 +21,7 @@ up the legend """ from __future__ import division -import sys, warnings +import copy, sys, warnings import numpy as npy @@ -558,9 +558,7 @@ handle.set_height(h/2) # Set the data for the legend patch - # MGDTODO: This copy may no longer be needed now that Bboxes are - # essentially immutable - bbox = self._get_handle_text_bbox(renderer).copy() + bbox = copy.copy(self._get_handle_text_bbox(renderer)) bbox = bbox.scaled(1 + self.pad, 1 + self.pad) l,b,w,h = bbox.get_bounds() Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/lines.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -352,32 +352,18 @@ self._picker = p def get_window_extent(self, renderer): - self._newstyle = hasattr(renderer, 'draw_markers') - if self._newstyle: - x = self._x - y = self._y - else: - x, y = self._get_plottable() + xys = self.get_transform()(self._xys) - # MGDTODO: Put this in a single Nx2 array, rather than these - # separate ones - #### Conversion code - a = npy.vstack((x, y)).swapaxes(0, 1) - #### - x, y = self.get_transform()(a) - print "get_window_extent", self.get_transform() - - #x, y = self.get_transform().seq_x_y(x, y) + x = xys[:, 0] + y = xys[:, 1] + left = x.min() + bottom = y.min() + width = x.max() - left + height = y.max() - bottom - left = min(x) - bottom = min(y) - width = max(x) - left - height = max(y) - bottom - # correct for marker size, if any if self._marker is not None: - ms = self._markersize/72.0*self.figure.dpi - # ms = self._markersize/72.0*self.figure.dpi.get() MGDTODO + ms = self._markersize / 72.0 * self.figure.dpi left -= ms/2 bottom -= ms/2 width += ms @@ -411,6 +397,7 @@ def recache(self): #if self.axes is None: print 'recache no axes' #else: print 'recache units', self.axes.xaxis.units, self.axes.yaxis.units + # MGDTODO: Deal with units x = ma.asarray(self.convert_xunits(self._xorig), float) y = ma.asarray(self.convert_yunits(self._yorig), float) @@ -435,15 +422,15 @@ else: self._segments = None - self._x = npy.asarray(x, float) - self._y = npy.asarray(y, float) - self._path = Path(npy.vstack((self._x, self._y)).transpose(), - closed=False) + self._xy = npy.vstack((npy.asarray(x, npy.float_), + npy.asarray(y, npy.float_))).transpose() + self._x = self._xy[:, 0] + self._y = self._xy[:, 1] + self._path = Path(self._xy, closed=False) self._logcache = None - def _is_sorted(self, x): "return true if x is sorted" if len(x)<2: return 1 Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/transforms.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -19,9 +19,9 @@ self._parents = Set() def invalidate(self): - if not self._do_invalidation(): - for parent in self._parents: - parent.invalidate() + self._do_invalidation() + for parent in self._parents: + parent.invalidate() def _do_invalidation(self): return False @@ -187,14 +187,16 @@ return 'Bbox(%s)' % repr(self._points) __str__ = __repr__ - # JDH: the update method will update the box limits from the - # existing limits and the new data; it appears here you are just - # using the new data. We use an "ignore" flag to specify whether - # you want to include the existing data or not in the update def update_from_data(self, x, y, ignore=True): - self._points = npy.array( - [[x.min(), y.min()], [x.max(), y.max()]], - npy.float_) + if ignore: + self._points = npy.array( + [[x.min(), y.min()], [x.max(), y.max()]], + npy.float_) + else: + self._points = npy.array( + [[min(x.min(), self.xmin), min(y.min(), self.ymin)], + [max(x.max(), self.xmax), max(y.max(), self.ymax)]], + npy.float_) self.invalidate() # MGDTODO: Probably a more efficient ways to do this... @@ -409,9 +411,7 @@ return self.get_matrix() def _do_invalidation(self): - result = self._inverted is None self._inverted = None - return result #@staticmethod def _concat(a, b): @@ -494,6 +494,7 @@ if matrix is None: matrix = npy.identity(3) else: + matrix = npy.asarray(matrix, npy.float_) assert matrix.shape == (3, 3) self._mtx = matrix self._inverted = None @@ -629,8 +630,6 @@ if self._mtx is not None: self._mtx = None Affine2DBase._do_invalidation(self) - return False - return True def is_separable(self): return True @@ -684,7 +683,7 @@ def _do_invalidation(self): self._mtx = None - Affine2DBase._do_invalidation(self) + return Affine2DBase._do_invalidation(self) def get_matrix(self): if self._mtx is None: @@ -718,8 +717,6 @@ if self._mtx is not None: self._mtx = None Affine2DBase._do_invalidation(self) - return False - return True def is_separable(self): return True Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/src/_backend_agg.cpp 2007-09-18 19:29:21 UTC (rev 3856) @@ -456,7 +456,7 @@ //return the agg::rect for bbox, flipping y PyArrayObject *bbox = (PyArrayObject *) PyArray_ContiguousFromObject(o.ptr(), PyArray_DOUBLE, 2, 2); - if (!bbox || bbox->nd != 2 bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2) + if (!bbox || bbox->nd != 2 || bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2) throw Py::TypeError ("Expected a Bbox object."); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-19 16:18:56
|
Revision: 3858 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3858&view=rev Author: mdboom Date: 2007-09-19 09:18:51 -0700 (Wed, 19 Sep 2007) Log Message: ----------- Got steps_demo.py working Modified Paths: -------------- branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/path.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-09-19 13:28:11 UTC (rev 3857) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-09-19 16:18:51 UTC (rev 3858) @@ -40,7 +40,7 @@ def _get_cached_native_path(self, path): native_path = self._native_paths.get(path) if native_path is None: - # print "CACHE MISS", path + print "CACHE MISS", path native_path = self.convert_to_native_path(path) self._native_paths[path] = native_path return native_path Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-09-19 13:28:11 UTC (rev 3857) +++ branches/transforms/lib/matplotlib/lines.py 2007-09-19 16:18:51 UTC (rev 3858) @@ -25,53 +25,6 @@ (TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN, CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN) = range(8) -def unmasked_index_ranges(mask, compressed = True): - ''' - Calculate the good data ranges in a masked 1-D npy.array, based on mask. - - Returns Nx2 npy.array with each row the start and stop indices - for slices of the compressed npy.array corresponding to each of N - uninterrupted runs of unmasked values. - If optional argument compressed is False, it returns the - start and stop indices into the original npy.array, not the - compressed npy.array. - Returns None if there are no unmasked values. - - Example: - - y = ma.array(npy.arange(5), mask = [0,0,1,0,0]) - #ii = unmasked_index_ranges(y.mask()) - ii = unmasked_index_ranges(ma.getmask(y)) - # returns [[0,2,] [2,4,]] - - y.compressed().filled()[ii[1,0]:ii[1,1]] - # returns npy.array [3,4,] - # (The 'filled()' method converts the masked npy.array to a numerix npy.array.) - - #i0, i1 = unmasked_index_ranges(y.mask(), compressed=False) - i0, i1 = unmasked_index_ranges(ma.getmask(y), compressed=False) - # returns [[0,3,] [2,5,]] - - y.filled()[ii[1,0]:ii[1,1]] - # returns npy.array [3,4,] - - ''' - m = npy.concatenate(((1,), mask, (1,))) - indices = npy.arange(len(mask) + 1) - mdif = m[1:] - m[:-1] - i0 = npy.compress(mdif == -1, indices) - i1 = npy.compress(mdif == 1, indices) - assert len(i0) == len(i1) - if len(i1) == 0: - return None - if not compressed: - return npy.concatenate((i0[:, npy.newaxis], i1[:, npy.newaxis]), axis=1) - seglengths = i1 - i0 - breakpoints = npy.cumsum(seglengths) - ic0 = npy.concatenate(((0,), breakpoints[:-1])) - ic1 = breakpoints - return npy.concatenate((ic0[:, npy.newaxis], ic1[:, npy.newaxis]), axis=1) - def segment_hits(cx,cy,x,y,radius): """Determine if any line segments are within radius of a point. Returns the list of line segments that are within that radius. @@ -117,7 +70,7 @@ '--' : '_draw_dashed', '-.' : '_draw_dash_dot', ':' : '_draw_dotted', - 'steps': '_draw_solid', + 'steps': '_draw_steps', 'None' : '_draw_nothing', ' ' : '_draw_nothing', '' : '_draw_nothing', @@ -394,6 +347,8 @@ self._yorig = y self.recache() + _masked_array_to_path_code_mapping = npy.array( + [Path.LINETO, Path.IGNORE, Path.MOVETO], Path.code_type) def recache(self): #if self.axes is None: print 'recache no axes' #else: print 'recache units', self.axes.xaxis.units, self.axes.yaxis.units @@ -411,36 +366,28 @@ if len(x) != len(y): raise RuntimeError('xdata and ydata must be the same length') - # MGDTODO: Deal with segments + self._xy = npy.vstack((npy.asarray(x, npy.float_), + npy.asarray(y, npy.float_))).transpose() + self._x = self._xy[:, 0] # just a view + self._y = self._xy[:, 1] # just a view + self._logcache = None + mx = ma.getmask(x) my = ma.getmask(y) mask = ma.mask_or(mx, my) + codes = None if mask is not ma.nomask: - x = ma.masked_array(x, mask=mask).compressed() - y = ma.masked_array(y, mask=mask).compressed() - self._segments = unmasked_index_ranges(mask) - else: - self._segments = None - - self._xy = npy.vstack((npy.asarray(x, npy.float_), - npy.asarray(y, npy.float_))).transpose() - self._x = self._xy[:, 0] - self._y = self._xy[:, 1] - self._logcache = None + m = npy.concatenate(((1,), mask, (1,))) + mdif = m[1:] - m[:-1] + mdif = npy.maximum((mdif[:-1] * -2), mask) + codes = npy.take( + self._masked_array_to_path_code_mapping, + mdif) + self._path = Path(self._xy, codes, closed=False) + # MGDTODO: If _draw_steps is removed, remove the following line also + self._step_path = None - if self._linestyle == 'steps': - siz=len(xt) - if siz<2: return - xt, yt = self._x, self._y - xt2=npy.ones((2*siz,), xt.dtype) - xt2[0:-1:2], xt2[1:-1:2], xt2[-1] = xt, xt[1:], xt[-1] - yt2=npy.ones((2*siz,), yt.dtype) - yt2[0:-1:2], yt2[1::2] = yt, yt - self._path = Path(npy.vstack((xt2, yt2)).transpose(), closed=False) - else: - self._path = Path(self._xy, closed=False) - def _is_sorted(self, x): "return true if x is sorted" if len(x)<2: return 1 @@ -507,14 +454,7 @@ funcname = self._lineStyles.get(self._linestyle, '_draw_nothing') lineFunc = getattr(self, funcname) - - # MGDTODO: Deal with self._segments - if self._segments is not None: - for ii in self._segments: - lineFunc(renderer, gc, xt[ii[0]:ii[1]], yt[ii[0]:ii[1]]) - - else: - lineFunc(renderer, gc, self._path) + lineFunc(renderer, gc, self._path) # MGDTODO: Deal with markers if self._marker is not None: @@ -709,7 +649,29 @@ def _draw_nothing(self, renderer, gc, path): pass - + + def _draw_steps(self, renderer, gc, path): + # We generate the step function path on-the-fly, and then cache it. + # The cache may be later invalidated when the data changes + # (in self.recache()) + + # MGDTODO: Untested -- using pylab.step doesn't actually trigger + # this code -- the path is "stepped" before even getting to this + # class. Perhaps this should be removed here, since it is not as + # powerful as what is in axes.step() anyway. + if self._step_path is None: + vertices = self._path.vertices + codes = self._path.codes + siz = len(vertices) + if siz<2: return + new_vertices = npy.zeros((2*siz, 2), vertices.dtype) + new_vertices[0:-1:2, 0], new_vertices[1:-1:2, 0], newvertices[-1, 0] = vertices[:, 0], vertices[1:, 0], vertices[-1, 0] + new_vertices[0:-1:2, 1], new_vertices[1::2, 1] = vertices[:, 1], vertices[:, 1] + self._step_path = Path(new_vertices, closed=False) + gc.set_linestyle('solid') + renderer.draw_path(gc, self._step_path, self.get_transform()) + + def _draw_solid(self, renderer, gc, path): gc.set_linestyle('solid') renderer.draw_path(gc, path, self.get_transform()) Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-09-19 13:28:11 UTC (rev 3857) +++ branches/transforms/lib/matplotlib/path.py 2007-09-19 16:18:51 UTC (rev 3858) @@ -1,10 +1,10 @@ import numpy as npy -VALIDATE_PATHS = True +DEBUG = True class Path(object): # Path codes - STOP = 0 + IGNORE = 0 # 1 vertex MOVETO = 1 # 1 vertex LINETO = 2 # 1 vertex CURVE3 = 3 # 2 vertices @@ -18,7 +18,7 @@ UBSPLINE = 8 #### - NUM_VERTICES = [0, 1, 1, 2, 3, 0] + NUM_VERTICES = [1, 1, 1, 2, 3, 0] code_type = npy.uint8 @@ -43,7 +43,7 @@ assert self._codes.ndim == 1 - if VALIDATE_PATHS: + if DEBUG: i = 0 NUM_VERTICES = self.NUM_VERTICES for code in codes: Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-09-19 13:28:11 UTC (rev 3857) +++ branches/transforms/lib/matplotlib/transforms.py 2007-09-19 16:18:51 UTC (rev 3858) @@ -32,18 +32,6 @@ for child in children: getattr(self, child)._parents.add(self) self._children = children - - # MGDTODO: decide whether we need this in-place updating and - # remove if not -# def replace_child(self, index, child): -# children = self._children -# getattr(self, children[index])._parents.remove(self) -# setattr(self, children[index], child) -# # We have to reset children in case two or more -# # of the children are the same -# for child in children: -# getattr(self, child)._parents.add(self) -# self.invalidate() class BboxBase(TransformNode): ''' @@ -327,53 +315,7 @@ if self._points is None: self._points = self.transform(self.bbox.get_points()) return self._points - -# MGDTODO: This code probably works, but I don't think it's a good idea -# (from a code clarity perspective) -# class BlendedBbox(BboxBase): -# def __init__(self, bbox_x, bbox_y): -# assert isinstance(bbox_x, BboxBase) -# assert isinstance(bbox_y, BboxBase) - -# BboxBase.__init__(self) -# self._x = bbox_x -# self._y = bbox_y -# self.set_children(['_x', '_y']) -# self._points = None - -# def __repr__(self): -# return "TransformedBbox(%s, %s)" % (self.bbox, self.transform) -# __str__ = __repr__ -# def _do_invalidation(self): -# self._points = None - -# def get_points(self): -# if self._points is None: -# # MGDTODO: Optimize -# if self._x == self._y: -# self._points = self._x.get_points() -# else: -# x_points = self._x.get_points() -# y_points = self._y.get_points() -# self._points = npy.array( -# [[x_points[0,0], y_points[0,1]], -# [x_points[1,0], y_points[1,1]]], -# npy.float_) -# return self._points - -# def _set_intervalx(self, pair): -# # MGDTODO: Optimize -# bbox = Bbox([[pair[0], 0.0], [pair[1], 0.0]]) -# self.replace_child(0, bbox) -# intervalx = property(BboxBase._get_intervalx, _set_intervalx) - -# def _set_intervaly(self, pair): -# # MGDTODO: Optimize -# bbox = Bbox([[0.0, pair[0]], [0.0, pair[1]]]) -# self.replace_child(1, bbox) -# intervaly = property(BboxBase._get_intervaly, _set_intervaly) - class Transform(TransformNode): def __init__(self): TransformNode.__init__(self) @@ -746,7 +688,6 @@ self._mtx = affine._mtx return self._mtx -# MGDTODO: There's probably a better place for this def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True): ''' Ensure the endpoints of a range are not too close together. Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-09-19 13:28:11 UTC (rev 3857) +++ branches/transforms/src/_backend_agg.cpp 2007-09-19 16:18:51 UTC (rev 3858) @@ -634,6 +634,9 @@ if (num_vertices) { for (size_t j=0; j<num_vertices; ++j) GET_NEXT_VERTEX(x, y); + if (code_i == IGNORE) + continue; + trans.transform(&x, &y); if (face.first) { @@ -860,6 +863,10 @@ for (size_t i = 0; i < N; ++i) { switch (*(unsigned char*)(code_i)) { + case IGNORE: + GET_NEXT_VERTEX(x0, y0); + _VERBOSE("IGNORE"); + break; case MOVETO: GET_NEXT_VERTEX(x0, y0); move_to(x0, y0); Modified: branches/transforms/src/_backend_agg.h =================================================================== --- branches/transforms/src/_backend_agg.h 2007-09-19 13:28:11 UTC (rev 3857) +++ branches/transforms/src/_backend_agg.h 2007-09-19 16:18:51 UTC (rev 3858) @@ -40,14 +40,14 @@ #include "agg_vcgen_markers_term.h" // These are copied directly from path.py, and must be kept in sync -#define STOP 0 +#define IGNORE 0 #define MOVETO 1 #define LINETO 2 #define CURVE3 3 #define CURVE4 4 #define CLOSEPOLY 5 -const size_t NUM_VERTICES[] = { 0, 1, 1, 2, 3, 0 }; +const size_t NUM_VERTICES[] = { 1, 1, 1, 2, 3, 0 }; typedef agg::pixfmt_rgba32 pixfmt; typedef agg::renderer_base<pixfmt> renderer_base; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-19 19:48:22
|
Revision: 3860 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3860&view=rev Author: mdboom Date: 2007-09-19 12:48:17 -0700 (Wed, 19 Sep 2007) Log Message: ----------- Use iterator rather than caching approach for paths Modified Paths: -------------- branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-19 19:46:34 UTC (rev 3859) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-19 19:48:17 UTC (rev 3860) @@ -112,8 +112,7 @@ self.dpi = dpi self.width = width self.height = height - if __debug__: verbose.report('RendererAgg.__init__ width=%s, \ - height=%s'%(width, height), 'debug-annoying') + if __debug__: verbose.report('RendererAgg.__init__ width=%s, height=%s'%(width, height), 'debug-annoying') self._renderer = _RendererAgg(int(width), int(height), dpi, debug=False) if __debug__: verbose.report('RendererAgg.__init__ _RendererAgg done', Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-09-19 19:46:34 UTC (rev 3859) +++ branches/transforms/src/_backend_agg.cpp 2007-09-19 19:48:17 UTC (rev 3860) @@ -87,15 +87,17 @@ inline void get_next_vertex(const char* & vertex_i, const char* vertex_end, double& x, double& y, size_t next_vertex_stride, - size_t next_axis_stride) { + size_t next_axis_stride, + const char* & code_i, size_t code_stride) { if (vertex_i + next_axis_stride >= vertex_end) throw Py::ValueError("Error parsing path. Read past end of vertices"); x = *(double*)vertex_i; y = *(double*)(vertex_i + next_axis_stride); vertex_i += next_vertex_stride; + code_i += code_stride; } -#define GET_NEXT_VERTEX(x, y) get_next_vertex(vertex_i, vertex_end, x, y, next_vertex_stride, next_axis_stride) +#define GET_NEXT_VERTEX(x, y) get_next_vertex(vertex_i, vertex_end, x, y, next_vertex_stride, next_axis_stride, code_i, code_stride) Py::Object BufferRegion::to_string(const Py::Tuple &args) { @@ -103,7 +105,71 @@ return Py::String(PyString_FromStringAndSize((const char*)aggbuf.data,aggbuf.height*aggbuf.stride), true); } +class PathIterator { + PyArrayObject* vertices; + PyArrayObject* codes; + size_t m_iterator; + size_t m_total_vertices; +public: + PathIterator(const Py::Object& path_obj) : + vertices(NULL), codes(NULL), m_iterator(0) { + Py::Object vertices_obj = path_obj.getAttr("vertices"); + Py::Object codes_obj = path_obj.getAttr("codes"); + + vertices = (PyArrayObject*)PyArray_ContiguousFromObject + (vertices_obj.ptr(), PyArray_DOUBLE, 2, 2); + if (!vertices || vertices->nd != 2 || vertices->dimensions[1] != 2) + throw Py::ValueError("Invalid vertices array."); + codes = (PyArrayObject*)PyArray_ContiguousFromObject + (codes_obj.ptr(), PyArray_UINT8, 1, 1); + if (!codes) + throw Py::ValueError("Invalid codes array."); + + if (codes->dimensions[0] != vertices->dimensions[0]) + throw Py::ValueError("Vertices and codes array are not the same length."); + + m_total_vertices = codes->dimensions[0]; + } + + ~PathIterator() { + Py_XDECREF(vertices); + Py_XDECREF(codes); + } + + static const char code_map[]; + + inline unsigned vertex(unsigned idx, double* x, double* y) { + if (idx > m_total_vertices) + throw Py::RuntimeError("Requested vertex past end"); + double* pv = (double*)(vertices->data + (idx * vertices->strides[0])); + *x = *pv++; + *y = *pv; + // MGDTODO: Range check + return code_map[(unsigned int)*(codes->data + (idx * codes->strides[0]))]; + } + + inline unsigned vertex(double* x, double* y) { + if(m_iterator >= m_total_vertices) return agg::path_cmd_stop; + return vertex(m_iterator++, x, y); + } + + inline void rewind(unsigned path_id) { + m_iterator = path_id; + } + + inline unsigned total_vertices() { + return m_total_vertices; + } +}; + +const char PathIterator::code_map[] = {0, + agg::path_cmd_move_to, + agg::path_cmd_line_to, + agg::path_cmd_curve3, + agg::path_cmd_curve4, + agg::path_cmd_end_poly | agg::path_flags_close}; + GCAgg::GCAgg(const Py::Object &gc, double dpi, bool snapto) : dpi(dpi), snapto(snapto), isaa(true), linewidth(1.0), alpha(1.0), cliprect(NULL), clippath(NULL), @@ -634,7 +700,7 @@ if (num_vertices) { for (size_t j=0; j<num_vertices; ++j) GET_NEXT_VERTEX(x, y); - if (code_i == IGNORE) + if (*code_i == STOP || *code_i == CLOSEPOLY) continue; trans.transform(&x, &y); @@ -863,9 +929,10 @@ for (size_t i = 0; i < N; ++i) { switch (*(unsigned char*)(code_i)) { - case IGNORE: + case STOP: GET_NEXT_VERTEX(x0, y0); - _VERBOSE("IGNORE"); + _VERBOSE("STOP"); + // MGDTODO: If this isn't the end, we should raise an error break; case MOVETO: GET_NEXT_VERTEX(x0, y0); @@ -894,10 +961,10 @@ break; case CLOSEPOLY: close_polygon(); + GET_NEXT_VERTEX(x0, y0); _VERBOSE("CLOSEPOLY"); break; } - code_i += code_stride; } } catch(...) { Py_XDECREF(vertices); @@ -911,7 +978,7 @@ Py::Object RendererAgg::draw_path(const Py::Tuple& args) { - typedef agg::conv_transform<agg::path_storage> transformed_path_t; + typedef agg::conv_transform<PathIterator> transformed_path_t; typedef agg::conv_curve<transformed_path_t> curve_t; typedef agg::conv_stroke<curve_t> stroke_t; typedef agg::conv_dash<curve_t> dash_t; @@ -928,9 +995,11 @@ GCAgg gc = GCAgg(args[0], dpi); Py::Object path_obj = args[1]; - if (!PathAgg::check(path_obj)) - throw Py::TypeError("Native path object is not of correct type"); - PathAgg* path = static_cast<PathAgg*>(path_obj.ptr()); +// if (!PathAgg::check(path_obj)) +// throw Py::TypeError("Native path object is not of correct type"); + // PathAgg* path = static_cast<PathAgg*>(path_obj.ptr()); + PathIterator path(path_obj); + agg::trans_affine trans = py_to_agg_transformation_matrix(args[2]); facepair_t face = _get_rgba_face(args[3], gc.alpha); @@ -943,34 +1012,34 @@ bool has_clippath = (gc.clippath != NULL); if (has_clippath && (gc.clippath != lastclippath || trans != lastclippath_transform)) { - rendererBaseAlphaMask->clear(agg::gray8(0, 0)); - gc.clippath->rewind(0); - transformed_path_t transformed_clippath(*(gc.clippath), trans); - theRasterizer->add_path(transformed_clippath); - rendererAlphaMask->color(agg::gray8(255, 255)); - agg::render_scanlines(*theRasterizer, *scanlineAlphaMask, *rendererAlphaMask); - lastclippath = gc.clippath; - lastclippath_transform = trans; +// rendererBaseAlphaMask->clear(agg::gray8(0, 0)); +// gc.clippath->rewind(0); +// transformed_path_t transformed_clippath(*(gc.clippath), trans); +// theRasterizer->add_path(transformed_clippath); +// rendererAlphaMask->color(agg::gray8(255, 255)); +// agg::render_scanlines(*theRasterizer, *scanlineAlphaMask, *rendererAlphaMask); +// lastclippath = gc.clippath; +// lastclippath_transform = trans; } try { // If this is a straight horizontal or vertical line, quantize to nearest // pixels - if (path->total_vertices() == 2) { - double x0, y0, x1, y1; - path->vertex(0, &x0, &y0); - trans.transform(&x0, &y0); - path->vertex(1, &x1, &y1); - trans.transform(&x1, &y1); - if (((int)x0 == (int)x1) || ((int)y0 == (int)y1)) { - new_path.move_to((int)x0 + 0.5, (int)y0 + 0.5); - new_path.line_to((int)x1 + 0.5, (int)y1 + 0.5); - tpath = new transformed_path_t(new_path, agg::trans_affine()); - } - } +// if (path.total_vertices() == 2) { +// double x0, y0, x1, y1; +// path.vertex(0, &x0, &y0); +// trans.transform(&x0, &y0); +// path.vertex(1, &x1, &y1); +// trans.transform(&x1, &y1); +// if (((int)x0 == (int)x1) || ((int)y0 == (int)y1)) { +// new_path.move_to((int)x0 + 0.5, (int)y0 + 0.5); +// new_path.line_to((int)x1 + 0.5, (int)y1 + 0.5); +// tpath = new transformed_path_t(new_path, agg::trans_affine()); +// } +// } if (!tpath) { - tpath = new transformed_path_t(*path, trans); + tpath = new transformed_path_t(path, trans); } // Benchmarking shows that there is no noticable slowdown to always Modified: branches/transforms/src/_backend_agg.h =================================================================== --- branches/transforms/src/_backend_agg.h 2007-09-19 19:46:34 UTC (rev 3859) +++ branches/transforms/src/_backend_agg.h 2007-09-19 19:48:17 UTC (rev 3860) @@ -40,14 +40,14 @@ #include "agg_vcgen_markers_term.h" // These are copied directly from path.py, and must be kept in sync -#define IGNORE 0 +#define STOP 0 #define MOVETO 1 #define LINETO 2 #define CURVE3 3 #define CURVE4 4 #define CLOSEPOLY 5 -const size_t NUM_VERTICES[] = { 1, 1, 1, 2, 3, 0 }; +const size_t NUM_VERTICES[] = { 1, 1, 1, 2, 3, 1 }; typedef agg::pixfmt_rgba32 pixfmt; typedef agg::renderer_base<pixfmt> renderer_base; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-20 13:58:01
|
Revision: 3865 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3865&view=rev Author: mdboom Date: 2007-09-20 06:57:59 -0700 (Thu, 20 Sep 2007) Log Message: ----------- Go all out with iterator (rather than copy) approach, as it is much faster. Modified Paths: -------------- branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-09-20 13:57:32 UTC (rev 3864) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-09-20 13:57:59 UTC (rev 3865) @@ -17,11 +17,6 @@ class RendererBase: """An abstract base class to handle drawing/rendering operations """ - # This will cache paths across rendering instances - # Each subclass of RenderBase should define this a weak-keyed - # dictionary to hold native paths - # _native_paths = weakref.WeakKeyDictionary() - def __init__(self): self._texmanager = None @@ -37,43 +32,16 @@ """ pass - def _get_cached_native_path(self, path): - native_path = self._native_paths.get(path) - if native_path is None: - print "CACHE MISS", path - native_path = self.convert_to_native_path(path) - self._native_paths[path] = native_path - return native_path - def draw_path(self, gc, path, transform, rgbFace=None): """ Handles the caching of the native path associated with the given path and calls the underlying backend's _draw_path to actually do the drawing. """ - native_path = self._get_cached_native_path(path) - self._draw_native_path(gc, native_path, transform, rgbFace) + # MGDTODO: Update docstring + raise NotImplementedError - def _draw_native_path(self, gc, native_path, transform, rgbFace): - """ - Draw the native path object with the given GraphicsContext and - transform. The transform passed in will always be affine. - """ - raise NotImplementedError - - def convert_to_native_path(self, path): - """ - Backends will normally will override this, but if they don't need any - special optimizations, they can just have the generic path data - passed to them in draw_path. - """ - return path - def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): - native_marker_path = self._get_cached_native_path(marker_path) - self._draw_native_markers(gc, native_marker_path, marker_trans, path, trans, rgbFace) - - def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None): """ This method is currently underscore hidden because the draw_markers method is being used as a sentinel for newstyle @@ -94,7 +62,11 @@ vec6 = transform.as_vec6_val() ...backend dependent affine... """ + # MGDTODO: Update docstring raise NotImplementedError + + def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None): + raise NotImplementedError def get_image_magnification(self): """ Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-20 13:57:32 UTC (rev 3864) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-20 13:57:59 UTC (rev 3865) @@ -117,8 +117,8 @@ debug=False) if __debug__: verbose.report('RendererAgg.__init__ _RendererAgg done', 'debug-annoying') - - self.convert_to_native_path = self._renderer.convert_to_native_path + self.draw_path = self._renderer.draw_path + self.draw_markers = self._renderer.draw_markers self.draw_image = self._renderer.draw_image self.copy_from_bbox = self._renderer.copy_from_bbox self.restore_region = self._renderer.restore_region @@ -129,16 +129,6 @@ if __debug__: verbose.report('RendererAgg.__init__ done', 'debug-annoying') - def _draw_native_path(self, gc, path, transform, rgbFace): - return self._renderer.draw_path(gc, path, transform.get_matrix(), rgbFace) - - def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None): - return self._renderer.draw_markers( - gc, - native_marker_path, marker_trans.get_matrix(), - path.vertices, path.codes, trans.get_matrix(), - rgbFace) - def draw_mathtext(self, gc, x, y, s, prop, angle): """ Draw the math text using matplotlib.mathtext Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-09-20 13:57:32 UTC (rev 3864) +++ branches/transforms/lib/matplotlib/transforms.py 2007-09-20 13:57:59 UTC (rev 3865) @@ -365,7 +365,7 @@ Transform.__init__(self) self._inverted = None - def __array__(self): + def __array__(self, *args, **kwargs): return self.get_matrix() def _do_invalidation(self): Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-09-20 13:57:32 UTC (rev 3864) +++ branches/transforms/src/_backend_agg.cpp 2007-09-20 13:57:59 UTC (rev 3865) @@ -48,59 +48,42 @@ agg::trans_affine py_to_agg_transformation_matrix(const Py::Object& obj) { PyArrayObject* matrix = NULL; - double a = 1.0, b = 0.0, c = 0.0, d = 1.0, e = 0.0, f = 0.0; - try { - matrix = (PyArrayObject*) PyArray_ContiguousFromObject(obj.ptr(), PyArray_DOUBLE, 2, 2); - if (!matrix || matrix->nd != 2 || matrix->dimensions[0] != 3 || matrix->dimensions[1] != 3) { - throw Py::ValueError("Invalid affine transformation matrix."); + matrix = (PyArrayObject*) PyArray_FromObject(obj.ptr(), PyArray_DOUBLE, 2, 2); + if (!matrix) { + throw Py::Exception(); } - - size_t stride0 = matrix->strides[0]; - size_t stride1 = matrix->strides[1]; - char* row0 = matrix->data; - char* row1 = row0 + stride0; - - a = *(double*)(row0); - row0 += stride1; - c = *(double*)(row0); - row0 += stride1; - e = *(double*)(row0); - - b = *(double*)(row1); - row1 += stride1; - d = *(double*)(row1); - row1 += stride1; - f = *(double*)(row1); + if (matrix->nd == 2 || matrix->dimensions[0] == 3 || matrix->dimensions[1] == 3) { + size_t stride0 = matrix->strides[0]; + size_t stride1 = matrix->strides[1]; + char* row0 = matrix->data; + char* row1 = row0 + stride0; + + double a = *(double*)(row0); + row0 += stride1; + double c = *(double*)(row0); + row0 += stride1; + double e = *(double*)(row0); + + double b = *(double*)(row1); + row1 += stride1; + double d = *(double*)(row1); + row1 += stride1; + double f = *(double*)(row1); + + Py_XDECREF(matrix); + + return agg::trans_affine(a, b, c, d, e, f); + } } catch (...) { - Py_XDECREF(matrix); + } Py_XDECREF(matrix); - - return agg::trans_affine(a, b, c, d, e, f); + throw Py::TypeError("Invalid affine transformation matrix"); } -/** Helper function to get the next vertex in a Numpy array of vertices. - * Will generally be used through the GET_NEXT_VERTEX macro. - */ -inline void get_next_vertex(const char* & vertex_i, const char* vertex_end, - double& x, double& y, - size_t next_vertex_stride, - size_t next_axis_stride, - const char* & code_i, size_t code_stride) { - if (vertex_i + next_axis_stride >= vertex_end) - throw Py::ValueError("Error parsing path. Read past end of vertices"); - x = *(double*)vertex_i; - y = *(double*)(vertex_i + next_axis_stride); - vertex_i += next_vertex_stride; - code_i += code_stride; -} - -#define GET_NEXT_VERTEX(x, y) get_next_vertex(vertex_i, vertex_end, x, y, next_vertex_stride, next_axis_stride, code_i, code_stride) - Py::Object BufferRegion::to_string(const Py::Tuple &args) { - // owned=true to prevent memory leak return Py::String(PyString_FromStringAndSize((const char*)aggbuf.data,aggbuf.height*aggbuf.stride), true); } @@ -145,7 +128,6 @@ double* pv = (double*)(vertices->data + (idx * vertices->strides[0])); *x = *pv++; *y = *pv; - // MGDTODO: Range check return code_map[(unsigned int)*(codes->data + (idx * codes->strides[0]))]; } @@ -170,9 +152,43 @@ agg::path_cmd_curve4, agg::path_cmd_end_poly | agg::path_flags_close}; +template<class VertexSource> class conv_quantize +{ +public: + conv_quantize(VertexSource& source, bool quantize) : + m_source(&source), m_quantize(quantize) {} + + void set_source(VertexSource& source) { m_source = &source; } + + void rewind(unsigned path_id) + { + m_source->rewind(path_id); + } + + unsigned vertex(double* x, double* y) + { + unsigned cmd = m_source->vertex(x, y); + if(m_quantize && agg::is_vertex(cmd)) + { + *x = (int)(*x); + *y = (int)(*y); + } + return cmd; + } + + void activate(bool quantize) { + m_quantize = quantize; + } + +private: + VertexSource* m_source; + bool m_quantize; +}; + + GCAgg::GCAgg(const Py::Object &gc, double dpi, bool snapto) : dpi(dpi), snapto(snapto), isaa(true), linewidth(1.0), alpha(1.0), - cliprect(NULL), clippath(NULL), + cliprect(NULL), Ndash(0), dashOffset(0.0), dasha(NULL) { _VERBOSE("GCAgg::GCAgg"); @@ -316,15 +332,7 @@ _VERBOSE("GCAgg::_set_clip_path"); - Py_XINCREF(clippath); - clippath = NULL; - - Py::Object o = gc.getAttr("_clippath"); - if (o.ptr()==Py_None) { - return; - } - - clippath = new PathAgg(o); + clippath = gc.getAttr("_clippath"); } @@ -337,8 +345,7 @@ height(height), dpi(dpi), NUMBYTES(width*height*4), - debug(debug), - lastclippath(NULL) + debug(debug) { _VERBOSE("RendererAgg::RendererAgg"); unsigned stride(width*4); @@ -599,7 +606,7 @@ Py::Object RendererAgg::draw_markers(const Py::Tuple& args) { - typedef agg::conv_transform<agg::path_storage> transformed_path_t; + typedef agg::conv_transform<PathIterator> transformed_path_t; typedef agg::conv_curve<transformed_path_t> curve_t; typedef agg::conv_stroke<curve_t> stroke_t; typedef agg::conv_dash<curve_t> dash_t; @@ -607,27 +614,29 @@ theRasterizer->reset_clipping(); - args.verify_length(7); + args.verify_length(5, 6); GCAgg gc = GCAgg(args[0], dpi); Py::Object marker_path_obj = args[1]; - if (!PathAgg::check(marker_path_obj)) - throw Py::TypeError("Native path object is not of correct type"); - PathAgg* marker_path = static_cast<PathAgg*>(marker_path_obj.ptr()); agg::trans_affine marker_trans = py_to_agg_transformation_matrix(args[2]); - Py::Object vertices_obj = args[3]; - Py::Object codes_obj = args[4]; - agg::trans_affine trans = py_to_agg_transformation_matrix(args[5]); - facepair_t face = _get_rgba_face(args[6], gc.alpha); + Py::Object path_obj = args[3]; + agg::trans_affine trans = py_to_agg_transformation_matrix(args[4]); + Py::Object face_obj; + if (args.size() == 6) + face_obj = args[5]; + facepair_t face = _get_rgba_face(face_obj, gc.alpha); // Deal with the difference in y-axis direction marker_trans *= agg::trans_affine_scaling(1.0, -1.0); trans *= agg::trans_affine_scaling(1.0, -1.0); trans *= agg::trans_affine_translation(0.0, (double)height); - marker_path->rewind(0); - transformed_path_t marker_path_transformed(*marker_path, marker_trans); + PathIterator marker_path(marker_path_obj); + transformed_path_t marker_path_transformed(marker_path, marker_trans); curve_t marker_path_curve(marker_path_transformed); + + PathIterator path(path_obj); + transformed_path_t path_transformed(path, trans); //maxim's suggestions for cached scanlines agg::scanline_storage_aa8 scanlines; @@ -635,19 +644,8 @@ agg::int8u* fillCache = NULL; agg::int8u* strokeCache = NULL; - PyArrayObject* vertices = NULL; - PyArrayObject* codes = NULL; try { - vertices = (PyArrayObject*)PyArray_ContiguousFromObject - (vertices_obj.ptr(), PyArray_DOUBLE, 2, 2); - if (!vertices || vertices->nd != 2 || vertices->dimensions[1] != 2) - throw Py::ValueError("Invalid vertices array."); - codes = (PyArrayObject*)PyArray_ContiguousFromObject - (codes_obj.ptr(), PyArray_UINT8, 1, 1); - if (!codes) - throw Py::ValueError("Invalid codes array."); - unsigned fillSize = 0; if (face.first) { theRasterizer->add_path(marker_path_curve); @@ -681,53 +679,29 @@ rendererBase->clip_box(l, height-(b+h),l+w, height-b); } - size_t next_vertex_stride = vertices->strides[0]; - size_t next_axis_stride = vertices->strides[1]; - size_t code_stride = codes->strides[0]; - - const char* vertex_i = vertices->data; - const char* code_i = codes->data; - const char* vertex_end = vertex_i + (vertices->dimensions[0] * vertices->strides[0]); - - size_t N = codes->dimensions[0]; double x, y; agg::serialized_scanlines_adaptor_aa8 sa; agg::serialized_scanlines_adaptor_aa8::embedded_scanline sl; - for (size_t i=0; i < N; i++) { - size_t num_vertices = NUM_VERTICES[(int)(*code_i)]; - if (num_vertices) { - for (size_t j=0; j<num_vertices; ++j) - GET_NEXT_VERTEX(x, y); - if (*code_i == STOP || *code_i == CLOSEPOLY) - continue; - - trans.transform(&x, &y); - - if (face.first) { - //render the fill - sa.init(fillCache, fillSize, x, y); - rendererAA->color(face.second); - agg::render_scanlines(sa, sl, *rendererAA); - } - - //render the stroke - sa.init(strokeCache, strokeSize, x, y); - rendererAA->color(gc.color); + while (path_transformed.vertex(&x, &y) != agg::path_cmd_stop) { + if (face.first) { + //render the fill + sa.init(fillCache, fillSize, x, y); + rendererAA->color(face.second); agg::render_scanlines(sa, sl, *rendererAA); } - code_i += code_stride; + + //render the stroke + sa.init(strokeCache, strokeSize, x, y); + rendererAA->color(gc.color); + agg::render_scanlines(sa, sl, *rendererAA); } } catch(...) { - Py_XDECREF(vertices); - Py_XDECREF(codes); delete[] fillCache; delete[] strokeCache; } - Py_XDECREF(vertices); - Py_XDECREF(codes); delete [] fillCache; delete [] strokeCache; @@ -888,98 +862,12 @@ } -Py::Object -RendererAgg::convert_to_native_path(const Py::Tuple& args) { - _VERBOSE("RendererAgg::draw_image"); - args.verify_length(1); - - Py::Object path = args[0]; - return Py::asObject(new PathAgg(path)); -} - - -PathAgg::PathAgg(const Py::Object& path_obj) : curvy(false) { - Py::Object vertices_obj = path_obj.getAttr("vertices"); - Py::Object codes_obj = path_obj.getAttr("codes"); - - PyArrayObject* vertices = NULL; - PyArrayObject* codes = NULL; - - try { - vertices = (PyArrayObject*)PyArray_ContiguousFromObject - (vertices_obj.ptr(), PyArray_DOUBLE, 2, 2); - if (!vertices || vertices->nd != 2 || vertices->dimensions[1] != 2) - throw Py::ValueError("Invalid vertices array."); - codes = (PyArrayObject*)PyArray_ContiguousFromObject - (codes_obj.ptr(), PyArray_UINT8, 1, 1); - if (!codes) - throw Py::ValueError("Invalid codes array."); - - size_t next_vertex_stride = vertices->strides[0]; - size_t next_axis_stride = vertices->strides[1]; - size_t code_stride = codes->strides[0]; - - const char* vertex_i = vertices->data; - const char* code_i = codes->data; - const char* vertex_end = vertex_i + (vertices->dimensions[0] * vertices->strides[0]); - - size_t N = codes->dimensions[0]; - double x0, y0, x1, y1, x2, y2; - - for (size_t i = 0; i < N; ++i) { - switch (*(unsigned char*)(code_i)) { - case STOP: - GET_NEXT_VERTEX(x0, y0); - _VERBOSE("STOP"); - // MGDTODO: If this isn't the end, we should raise an error - break; - case MOVETO: - GET_NEXT_VERTEX(x0, y0); - move_to(x0, y0); - _VERBOSE("MOVETO"); - break; - case LINETO: - GET_NEXT_VERTEX(x0, y0); - line_to(x0, y0); - _VERBOSE("LINETO"); - break; - case CURVE3: - GET_NEXT_VERTEX(x0, y0); - GET_NEXT_VERTEX(x1, y1); - curve3(x0, y0, x1, y1); - curvy = true; - _VERBOSE("CURVE3"); - break; - case CURVE4: - GET_NEXT_VERTEX(x0, y0); - GET_NEXT_VERTEX(x1, y1); - GET_NEXT_VERTEX(x2, y2); - curve4(x0, y0, x1, y1, x2, y2); - curvy = true; - _VERBOSE("CURVE4"); - break; - case CLOSEPOLY: - close_polygon(); - GET_NEXT_VERTEX(x0, y0); - _VERBOSE("CLOSEPOLY"); - break; - } - } - } catch(...) { - Py_XDECREF(vertices); - Py_XDECREF(codes); - throw; - } - - Py_XDECREF(vertices); - Py_XDECREF(codes); -} - Py::Object RendererAgg::draw_path(const Py::Tuple& args) { typedef agg::conv_transform<PathIterator> transformed_path_t; - typedef agg::conv_curve<transformed_path_t> curve_t; + typedef conv_quantize<transformed_path_t> quantize_t; + typedef agg::conv_curve<quantize_t> curve_t; typedef agg::conv_stroke<curve_t> stroke_t; typedef agg::conv_dash<curve_t> dash_t; typedef agg::conv_stroke<dash_t> stroke_dash_t; @@ -991,61 +879,59 @@ theRasterizer->reset_clipping(); _VERBOSE("RendererAgg::draw_path"); - args.verify_length(4); + args.verify_length(3, 4); - GCAgg gc = GCAgg(args[0], dpi); + Py::Object gc_obj = args[0]; Py::Object path_obj = args[1]; -// if (!PathAgg::check(path_obj)) -// throw Py::TypeError("Native path object is not of correct type"); - // PathAgg* path = static_cast<PathAgg*>(path_obj.ptr()); PathIterator path(path_obj); agg::trans_affine trans = py_to_agg_transformation_matrix(args[2]); - facepair_t face = _get_rgba_face(args[3], gc.alpha); trans *= agg::trans_affine_scaling(1.0, -1.0); trans *= agg::trans_affine_translation(0.0, (double)height); - transformed_path_t* tpath = NULL; - agg::path_storage new_path; + bool snap = false; + if (path.total_vertices() == 2) { + double x0, y0, x1, y1; + path.vertex(0, &x0, &y0); + trans.transform(&x0, &y0); + path.vertex(1, &x1, &y1); + trans.transform(&x1, &y1); + snap = ((int)x0 == (int)x1) || ((int)y0 == (int)y1); + } - bool has_clippath = (gc.clippath != NULL); + GCAgg gc = GCAgg(gc_obj, dpi, snap); + Py::Object face_obj; + if (args.size() == 4) + face_obj = args[3]; + facepair_t face = _get_rgba_face(face_obj, gc.alpha); - if (has_clippath && (gc.clippath != lastclippath || trans != lastclippath_transform)) { -// rendererBaseAlphaMask->clear(agg::gray8(0, 0)); -// gc.clippath->rewind(0); -// transformed_path_t transformed_clippath(*(gc.clippath), trans); -// theRasterizer->add_path(transformed_clippath); -// rendererAlphaMask->color(agg::gray8(255, 255)); -// agg::render_scanlines(*theRasterizer, *scanlineAlphaMask, *rendererAlphaMask); -// lastclippath = gc.clippath; -// lastclippath_transform = trans; + bool has_clippath = (gc.clippath.ptr() != Py_None); + + if (has_clippath && + (gc.clippath.ptr() != lastclippath.ptr() || trans != lastclippath_transform)) { + PathIterator clippath(gc.clippath); + rendererBaseAlphaMask->clear(agg::gray8(0, 0)); + transformed_path_t transformed_clippath(clippath, trans); + agg::conv_curve<transformed_path_t> curved_clippath(transformed_clippath); + theRasterizer->add_path(curved_clippath); + rendererAlphaMask->color(agg::gray8(255, 255)); + agg::render_scanlines(*theRasterizer, *scanlineAlphaMask, *rendererAlphaMask); + lastclippath = gc.clippath; + lastclippath_transform = trans; } try { // If this is a straight horizontal or vertical line, quantize to nearest // pixels -// if (path.total_vertices() == 2) { -// double x0, y0, x1, y1; -// path.vertex(0, &x0, &y0); -// trans.transform(&x0, &y0); -// path.vertex(1, &x1, &y1); -// trans.transform(&x1, &y1); -// if (((int)x0 == (int)x1) || ((int)y0 == (int)y1)) { -// new_path.move_to((int)x0 + 0.5, (int)y0 + 0.5); -// new_path.line_to((int)x1 + 0.5, (int)y1 + 0.5); -// tpath = new transformed_path_t(new_path, agg::trans_affine()); -// } -// } - if (!tpath) { - tpath = new transformed_path_t(path, trans); - } + transformed_path_t tpath(path, trans); + quantize_t quantized(tpath, snap); // Benchmarking shows that there is no noticable slowdown to always // treating paths as having curved segments. Doing so greatly // simplifies the code - curve_t curve(*tpath); + curve_t curve(quantized); set_clipbox_rasterizer(gc.cliprect); @@ -1106,12 +992,11 @@ } } } catch (...) { - delete tpath; + // MGDTODO: We don't have anything on the heap, so this catch + // clause isn't really necessary, but we might again soon... throw; } - delete tpath; - return Py::Object(); } @@ -1446,11 +1331,9 @@ behaviors().doc("The agg backend extension module"); add_varargs_method("draw_path", &RendererAgg::draw_path, - "draw_path(gc, rgbFace, native_path, transform)\n"); - add_varargs_method("convert_to_native_path", &RendererAgg::convert_to_native_path, - "convert_to_native_path(vertices, codes)\n"); + "draw_path(gc, path, transform, rgbFace)\n"); add_varargs_method("draw_markers", &RendererAgg::draw_markers, - "draw_markers(gc, marker_path, marker_trans, vertices, codes, rgbFace)\n"); + "draw_markers(gc, marker_path, marker_trans, path, rgbFace)\n"); add_varargs_method("draw_text_image", &RendererAgg::draw_text_image, "draw_text_image(font_image, x, y, r, g, b, a)\n"); add_varargs_method("draw_image", &RendererAgg::draw_image, @@ -1476,12 +1359,6 @@ "restore_region(region)"); } -void PathAgg::init_type() -{ - behaviors().name("PathAgg"); - behaviors().doc("A native Agg path object"); -} - extern "C" DL_EXPORT(void) init_backend_agg(void) Modified: branches/transforms/src/_backend_agg.h =================================================================== --- branches/transforms/src/_backend_agg.h 2007-09-20 13:57:32 UTC (rev 3864) +++ branches/transforms/src/_backend_agg.h 2007-09-20 13:57:59 UTC (rev 3865) @@ -105,20 +105,6 @@ }; }; -// A completely opaque data type used only to pass native path -// data to/from Python. Python can't do anything with the data -// other than create and then use it. -class PathAgg : - public agg::path_storage, - public Py::PythonExtension<PathAgg> { -public: - static void init_type(void); - - PathAgg(const Py::Object& path_obj); - - bool curvy; -}; - class GCAgg { public: GCAgg(const Py::Object& gc, double dpi, bool snapto=false); @@ -126,7 +112,6 @@ ~GCAgg() { delete [] dasha; delete [] cliprect; - Py_XINCREF(clippath); } double dpi; @@ -142,7 +127,7 @@ agg::rgba color; double *cliprect; - PathAgg *clippath; + Py::Object clippath; //dashes size_t Ndash; double dashOffset; @@ -183,7 +168,6 @@ Py::Object draw_text_image(const Py::Tuple & args); Py::Object draw_image(const Py::Tuple & args); Py::Object draw_path(const Py::Tuple & args); - Py::Object convert_to_native_path(const Py::Tuple & args); Py::Object write_rgba(const Py::Tuple & args); Py::Object write_png(const Py::Tuple & args); @@ -240,7 +224,7 @@ void set_clipbox_rasterizer( double *cliprect); private: - PathAgg *lastclippath; + Py::Object lastclippath; agg::trans_affine lastclippath_transform; }; @@ -253,7 +237,6 @@ : Py::ExtensionModule<_backend_agg_module>( "_backend_agg" ) { RendererAgg::init_type(); - PathAgg::init_type(); add_keyword_method("RendererAgg", &_backend_agg_module::new_renderer, "RendererAgg(width, height, dpi)"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-20 13:59:16
|
Revision: 3866 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3866&view=rev Author: mdboom Date: 2007-09-20 06:59:15 -0700 (Thu, 20 Sep 2007) Log Message: ----------- Merged revisions 3847-3865 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3853 | jouni | 2007-09-15 00:01:56 -0400 (Sat, 15 Sep 2007) | 2 lines Bugfix and doc fixes in type1font.py ........ r3861 | mdboom | 2007-09-20 08:31:26 -0400 (Thu, 20 Sep 2007) | 2 lines Fix font.size from being saved in the fontManager.cache ........ r3862 | mdboom | 2007-09-20 08:40:41 -0400 (Thu, 20 Sep 2007) | 2 lines Removing debugging output in last commit. ........ r3863 | jdh2358 | 2007-09-20 09:50:27 -0400 (Thu, 20 Sep 2007) | 1 line added gradient bar example ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/font_manager.py Added Paths: ----------- branches/transforms/examples/gradient_bar.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3846 + /trunk/matplotlib:1-3865 Copied: branches/transforms/examples/gradient_bar.py (from rev 3863, trunk/matplotlib/examples/gradient_bar.py) =================================================================== --- branches/transforms/examples/gradient_bar.py (rev 0) +++ branches/transforms/examples/gradient_bar.py 2007-09-20 13:59:15 UTC (rev 3866) @@ -0,0 +1,26 @@ +from pylab import figure, show, nx, cm + +def gbar(ax, x, y, width=0.5, bottom=0): + X = [[.6, .6],[.7,.7]] + for left,top in zip(x, y): + right = left+width + ax.imshow(X, interpolation='bicubic', cmap=cm.Blues, + extent=(left, right, bottom, top), alpha=1) + +fig = figure() + +xmin, xmax = xlim = 0,10 +ymin, ymax = ylim = 0,1 +ax = fig.add_subplot(111, xlim=xlim, ylim=ylim, + autoscale_on=False) +X = [[.6, .6],[.7,.7]] + +ax.imshow(X, interpolation='bicubic', cmap=cm.copper, + extent=(xmin, xmax, ymin, ymax), alpha=1) + +N = 10 +x = nx.arange(N)+0.25 +y = nx.mlab.rand(N) +gbar(ax, x, y, width=0.7) +ax.set_aspect('normal') +show() Modified: branches/transforms/lib/matplotlib/font_manager.py =================================================================== --- branches/transforms/lib/matplotlib/font_manager.py 2007-09-20 13:57:59 UTC (rev 3865) +++ branches/transforms/lib/matplotlib/font_manager.py 2007-09-20 13:59:15 UTC (rev 3866) @@ -843,10 +843,9 @@ """ def __init__(self, size=None, weight='normal'): - if not size : size = rcParams['font.size'] - self.__default_size = size self.__default_weight = weight - + self.default_size = size + paths = [os.path.join(rcParams['datapath'],'fonts','ttf'), os.path.join(rcParams['datapath'],'fonts','afm')] @@ -899,7 +898,9 @@ def get_default_size(self): "Return the default font size." - return self.__default_size + if self.default_size is None: + return rcParams['font.size'] + return self.default_size def set_default_weight(self, weight): "Set the default font weight. The initial value is 'normal'." @@ -1085,6 +1086,7 @@ try: fontManager = pickle_load(_fmcache) + fontManager.default_size = None verbose.report("Using fontManager instance from %s" % _fmcache) except: _rebuild() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-20 18:03:02
|
Revision: 3870 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3870&view=rev Author: mdboom Date: 2007-09-20 11:02:51 -0700 (Thu, 20 Sep 2007) Log Message: ----------- Merged revisions 3866-3869 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3867 | jdh2358 | 2007-09-20 10:13:51 -0400 (Thu, 20 Sep 2007) | 1 line committed rectangle selector lock patch ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/mlab.py branches/transforms/lib/matplotlib/widgets.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3865 + /trunk/matplotlib:1-3869 Modified: branches/transforms/lib/matplotlib/mlab.py =================================================================== --- branches/transforms/lib/matplotlib/mlab.py 2007-09-20 18:00:32 UTC (rev 3869) +++ branches/transforms/lib/matplotlib/mlab.py 2007-09-20 18:02:51 UTC (rev 3870) @@ -1255,7 +1255,7 @@ if unpack: return X.transpose() else: return X -def csv2rec(fname, comments='#', skiprows=1, checkrows=5, delimiter=',', +def csv2rec(fname, comments='#', skiprows=0, checkrows=5, delimiter=',', converterd=None, names=None, missing=None): """ Load data from comma/space/tab delimited file in fname into a @@ -1314,6 +1314,14 @@ else: return get_func(item, funcmap[func]) # recurse else: return func + + # map column names that clash with builtins -- TODO - extend this list + itemd = { + 'return' : 'return_', + 'file' : 'file_', + 'print' : 'print_', + } + def get_converters(reader): converters = None @@ -1352,6 +1360,7 @@ if not len(item): item = 'column%d'%i + item = itemd.get(item, item) cnt = seen.get(item, 0) if cnt>0: names.append(item + '%d'%cnt) Modified: branches/transforms/lib/matplotlib/widgets.py =================================================================== --- branches/transforms/lib/matplotlib/widgets.py 2007-09-20 18:00:32 UTC (rev 3869) +++ branches/transforms/lib/matplotlib/widgets.py 2007-09-20 18:02:51 UTC (rev 3870) @@ -955,24 +955,40 @@ warnings.warn('Use SpanSelector instead!', DeprecationWarning) SpanSelector.__init__(self, ax, onselect, 'horizontal', **kwargs) + class RectangleSelector: """ Select a min/max range of the x axes for a matplotlib Axes Example usage: - ax = subplot(111) - ax.plot(x,y) + from matplotlib.widgets import RectangleSelector + from pylab import * - def onselect(eclick, erelease): + def onselect(eclick, erelease): 'eclick and erelease are matplotlib events at press and release' - print 'startposition : (%f,%f)'%(eclick.xdata, eclick.ydata) - print 'endposition : (%f,%f)'%(erelease.xdata, erelease.ydata) - print 'used button : ', eclick.button + print ' startposition : (%f, %f)' % (eclick.xdata, eclick.ydata) + print ' endposition : (%f, %f)' % (erelease.xdata, erelease.ydata) + print ' used button : ', eclick.button - span = Selector(ax, onselect,drawtype='box') - show() + def toggle_Selector(event): + print ' Key pressed.' + if event.key in ['Q', 'q'] and toggle_Selector.RS.active: + print ' RectangleSelector deactivated.' + toggle_Selector.RS.set_active(False) + if event.key in ['A', 'a'] and not toggle_Selector.RS.active: + print ' RectangleSelector activated.' + toggle_Selector.RS.set_active(True) + x = arange(100)/(99.0) + y = sin(x) + fig = figure + ax = subplot(111) + ax.plot(x,y) + + toggle_Selector.RS = RectangleSelector(ax, onselect, drawtype='line') + connect('key_press_event', toggle_Selector) + show() """ def __init__(self, ax, onselect, drawtype='box', minspanx=None, minspany=None, useblit=False, @@ -1001,8 +1017,6 @@ Use type if you want the mouse to draw a line, a box or nothing between click and actual position ny setting drawtype = 'line', drawtype='box' or drawtype = 'none'. - - """ self.ax = ax self.visible = True @@ -1012,6 +1026,7 @@ self.canvas.mpl_connect('button_release_event', self.release) self.canvas.mpl_connect('draw_event', self.update_background) + self.active = True # for activation / deactivation self.to_draw = None self.background = None @@ -1052,6 +1067,14 @@ def ignore(self, event): 'return True if event should be ignored' + # If RectangleSelector is not active : + if not self.active: + return True + + # If canvas was locked + if not self.canvas.widgetlock.available(self): + return True + # If no button was pressed yet ignore the event if it was out # of the axes if self.eventpress == None: @@ -1142,6 +1165,17 @@ self.update() return False + def set_active(self, active): + """ Use this to activate / deactivate the RectangleSelector + + from your program with an boolean variable 'active'. + """ + self.active = active + + def get_active(self): + """ to get status of active mode (boolean variable)""" + return self.active + class Lasso(Widget): def __init__(self, ax, xy, callback=None, useblit=True): self.axes = ax This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-21 16:54:35
|
Revision: 3873 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3873&view=rev Author: mdboom Date: 2007-09-21 09:54:32 -0700 (Fri, 21 Sep 2007) Log Message: ----------- Merged revisions 3870-3872 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3871 | dsdale | 2007-09-21 11:33:18 -0400 (Fri, 21 Sep 2007) | 2 lines changed cbooks reversed to agree with the python builtin ........ Modified Paths: -------------- branches/transforms/API_CHANGES branches/transforms/CHANGELOG branches/transforms/lib/matplotlib/cbook.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3869 + /trunk/matplotlib:1-3872 Modified: branches/transforms/API_CHANGES =================================================================== --- branches/transforms/API_CHANGES 2007-09-21 16:52:50 UTC (rev 3872) +++ branches/transforms/API_CHANGES 2007-09-21 16:54:32 UTC (rev 3873) @@ -1,3 +1,8 @@ + Changed cbook.reversed so it yields a tuple rather than a + (index, tuple). This agrees with the python reversed builtin, + and cbook only defines reversed if python doesnt provide the + builtin. + Made skiprows=1 the default on csv2rec The gd and paint backends have been deleted. Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-09-21 16:52:50 UTC (rev 3872) +++ branches/transforms/CHANGELOG 2007-09-21 16:54:32 UTC (rev 3873) @@ -1,3 +1,6 @@ +2007-09-21 Changed cbook.reversed to yield the same result as the + python reversed builtin - DSD + 2007-09-13 The usetex support in the pdf backend is more usable now, so I am enabling it. - JKS Modified: branches/transforms/lib/matplotlib/cbook.py =================================================================== --- branches/transforms/lib/matplotlib/cbook.py 2007-09-21 16:52:50 UTC (rev 3872) +++ branches/transforms/lib/matplotlib/cbook.py 2007-09-21 16:54:32 UTC (rev 3873) @@ -482,7 +482,7 @@ enumerate() is new in Python 2.3 """ for i in range(len(seq)-1,-1,-1): - yield i, seq[i] + yield seq[i] # use itertools.izip if available, else use python version This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-24 16:54:40
|
Revision: 3885 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3885&view=rev Author: mdboom Date: 2007-09-24 09:54:37 -0700 (Mon, 24 Sep 2007) Log Message: ----------- Merged revisions 3873-3884 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3874 | jouni | 2007-09-22 02:48:49 -0400 (Sat, 22 Sep 2007) | 3 lines Replace some generator expressions by list comprehensions for Python 2.3 compatibility ........ r3879 | dsdale | 2007-09-24 08:56:38 -0400 (Mon, 24 Sep 2007) | 2 lines fix backend_qt* bug with multiple plot windows and show() ........ r3880 | dsdale | 2007-09-24 09:00:12 -0400 (Mon, 24 Sep 2007) | 2 lines backend_qt* bugfix for multiple plot windows and show() ........ r3881 | dsdale | 2007-09-24 09:01:17 -0400 (Mon, 24 Sep 2007) | 2 lines fix backend_wxagg reference in new config module ........ r3882 | dsdale | 2007-09-24 09:03:01 -0400 (Mon, 24 Sep 2007) | 3 lines modifed embedding_in_qt* examples so they can be run from ipython with -q*thread ........ r3883 | dsdale | 2007-09-24 11:11:58 -0400 (Mon, 24 Sep 2007) | 2 lines fix bug in improved support for multiple windows in backend_qt4 ........ Modified Paths: -------------- branches/transforms/CHANGELOG branches/transforms/examples/embedding_in_qt.py branches/transforms/examples/embedding_in_qt4.py branches/transforms/lib/matplotlib/backends/backend_pdf.py branches/transforms/lib/matplotlib/backends/backend_qt.py branches/transforms/lib/matplotlib/backends/backend_qt4.py branches/transforms/lib/matplotlib/config/mpltraits.py branches/transforms/lib/matplotlib/dviread.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3872 + /trunk/matplotlib:1-3884 Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-09-24 16:53:38 UTC (rev 3884) +++ branches/transforms/CHANGELOG 2007-09-24 16:54:37 UTC (rev 3885) @@ -1,3 +1,7 @@ +2007-09-24 Applied Eike Welk's patch reported on mpl-dev on 2007-09-22 + Fixes a bug with multiple plot windows in the qt backend, + ported the changes to backend_qt4 as well - DSD + 2007-09-21 Changed cbook.reversed to yield the same result as the python reversed builtin - DSD Modified: branches/transforms/examples/embedding_in_qt.py =================================================================== --- branches/transforms/examples/embedding_in_qt.py 2007-09-24 16:53:38 UTC (rev 3884) +++ branches/transforms/examples/embedding_in_qt.py 2007-09-24 16:54:37 UTC (rev 3885) @@ -25,7 +25,7 @@ # Note: color-intensive applications may require a different color allocation # strategy. -QApplication.setColorSpec(QApplication.NormalColor) +#QApplication.setColorSpec(QApplication.NormalColor) app = QApplication(sys.argv) class MyMplCanvas(FigureCanvas): @@ -129,12 +129,8 @@ % {"prog": progname, "version": progversion}) -def main(): - aw = ApplicationWindow() - aw.setCaption("%s" % progname) - qApp.setMainWidget(aw) - aw.show() - sys.exit(qApp.exec_loop()) - - -if __name__ == "__main__": main() +aw = ApplicationWindow() +aw.setCaption("%s" % progname) +qApp.setMainWidget(aw) +aw.show() +sys.exit(qApp.exec_loop()) Modified: branches/transforms/examples/embedding_in_qt4.py =================================================================== --- branches/transforms/examples/embedding_in_qt4.py 2007-09-24 16:53:38 UTC (rev 3884) +++ branches/transforms/examples/embedding_in_qt4.py 2007-09-24 16:54:37 UTC (rev 3885) @@ -122,17 +122,10 @@ % {"prog": progname, "version": progversion}) -def main(): - # Note: color-intensive applications may require a different color - # allocation strategy. - QtGui.QApplication.setColorSpec(QtGui.QApplication.NormalColor) - qApp = QtGui.QApplication(sys.argv) +qApp = QtGui.QApplication(sys.argv) - aw = ApplicationWindow() - aw.setWindowTitle("%s" % progname) - aw.show() -# sys.exit(qApp.exec_()) - qApp.exec_() - - -if __name__ == "__main__": main() +aw = ApplicationWindow() +aw.setWindowTitle("%s" % progname) +aw.show() +sys.exit(qApp.exec_()) +#qApp.exec_() Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-09-24 16:53:38 UTC (rev 3884) +++ branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-09-24 16:54:37 UTC (rev 3885) @@ -541,10 +541,10 @@ widths[ch] = afmdata.get_width_char(ch, isord=True) except KeyError: pass - not_None = (ch for ch in range(256) - if widths[ch] is not None) - firstchar = not_None.next() - lastchar = max(not_None) + not_None = [ch for ch in range(256) + if widths[ch] is not None] + firstchar = not_None[0] + lastchar = not_None[-1] widths = widths[firstchar:lastchar+1] for i,w in enumerate(widths): if w is None: widths[i] = 0 Modified: branches/transforms/lib/matplotlib/backends/backend_qt.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_qt.py 2007-09-24 16:53:38 UTC (rev 3884) +++ branches/transforms/lib/matplotlib/backends/backend_qt.py 2007-09-24 16:54:37 UTC (rev 3885) @@ -46,11 +46,11 @@ qApp = qt.QApplication( [" "] ) qt.QObject.connect( qApp, qt.SIGNAL( "lastWindowClosed()" ), qApp, qt.SLOT( "quit()" ) ) - else: - # someone else aready created the qApp and - # we let them handle the event-loop control. - show._needmain = False + #remember that matplotlib created the qApp - will be used by show() + _create_qApp.qAppCreatedHere = True +_create_qApp.qAppCreatedHere = False + def show(): """ Show all the figures and enter the qt main loop @@ -65,13 +65,10 @@ if figManager != None: figManager.canvas.draw() - if ( show._needmain ): - qt.qApp.exec_loop() - show._needmain = False + if _create_qApp.qAppCreatedHere: + qt.qApp.exec_loop() -show._needmain = True - def new_figure_manager( num, *args, **kwargs ): """ Create a new figure manager instance Modified: branches/transforms/lib/matplotlib/backends/backend_qt4.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_qt4.py 2007-09-24 16:53:38 UTC (rev 3884) +++ branches/transforms/lib/matplotlib/backends/backend_qt4.py 2007-09-24 16:54:37 UTC (rev 3885) @@ -46,11 +46,11 @@ qApp = QtGui.QApplication( [" "] ) QtCore.QObject.connect( qApp, QtCore.SIGNAL( "lastWindowClosed()" ), qApp, QtCore.SLOT( "quit()" ) ) - else: - # someone else aready created the qApp and - # we let them handle the event-loop control. - show._needmain = False + #remember that matplotlib created the qApp - will be used by show() + _create_qApp.qAppCreatedHere = True +_create_qApp.qAppCreatedHere = False + def show(): """ Show all the figures and enter the qt main loop @@ -65,13 +65,10 @@ if figManager != None: figManager.canvas.draw() - if ( show._needmain ): - qApp.exec_() - show._needmain = False + if _create_qApp.qAppCreatedHere: + QtGui.qApp.exec_() -show._needmain = True - def new_figure_manager( num, *args, **kwargs ): """ Create a new figure manager instance Modified: branches/transforms/lib/matplotlib/config/mpltraits.py =================================================================== --- branches/transforms/lib/matplotlib/config/mpltraits.py 2007-09-24 16:53:38 UTC (rev 3884) +++ branches/transforms/lib/matplotlib/config/mpltraits.py 2007-09-24 16:54:37 UTC (rev 3885) @@ -29,7 +29,7 @@ 'gtkcairo': 'GTKCairo', 'qt4agg': 'Qt4Agg', 'qtagg': 'QtAgg', - 'wxagg': 'WxAgg', + 'wxagg': 'WXAgg', 'agg': 'Agg', 'cairo': 'Cairo', 'ps': 'PS', Modified: branches/transforms/lib/matplotlib/dviread.py =================================================================== --- branches/transforms/lib/matplotlib/dviread.py 2007-09-24 16:53:38 UTC (rev 3884) +++ branches/transforms/lib/matplotlib/dviread.py 2007-09-24 16:54:37 UTC (rev 3885) @@ -350,9 +350,9 @@ def _xxx(self, special): matplotlib.verbose.report( 'Dvi._xxx: encountered special: %s' - % ''.join((32 <= ord(ch) < 127) and ch - or '<%02x>' % ord(ch) - for ch in special), + % ''.join([(32 <= ord(ch) < 127) and ch + or '<%02x>' % ord(ch) + for ch in special]), 'debug') def _fnt_def(self, k, c, s, d, a, l, n): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-09-26 13:55:53
|
Revision: 3896 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3896&view=rev Author: mdboom Date: 2007-09-26 06:55:41 -0700 (Wed, 26 Sep 2007) Log Message: ----------- Merged revisions 3885-3895 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3894 | mdboom | 2007-09-26 09:41:15 -0400 (Wed, 26 Sep 2007) | 3 lines Bugfix: Display exponents in tick values in the default font (not the default math font) ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/mathtext.py branches/transforms/lib/matplotlib/ticker.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3884 + /trunk/matplotlib:1-3895 Modified: branches/transforms/lib/matplotlib/mathtext.py =================================================================== --- branches/transforms/lib/matplotlib/mathtext.py 2007-09-26 13:53:53 UTC (rev 3895) +++ branches/transforms/lib/matplotlib/mathtext.py 2007-09-26 13:55:41 UTC (rev 3896) @@ -1855,7 +1855,7 @@ "tanh") fontname = oneOf("rm cal it tt sf bf") - latex2efont = oneOf("mathrm mathcal mathit mathtt mathsf mathbf") + latex2efont = oneOf("mathrm mathcal mathit mathtt mathsf mathbf mathdefault") space =(FollowedBy(bslash) + (Literal(r'\ ') Modified: branches/transforms/lib/matplotlib/ticker.py =================================================================== --- branches/transforms/lib/matplotlib/ticker.py 2007-09-26 13:53:53 UTC (rev 3895) +++ branches/transforms/lib/matplotlib/ticker.py 2007-09-26 13:55:41 UTC (rev 3896) @@ -300,9 +300,12 @@ sciNotStr = r'{\times}'+self.format_data(10**self.orderOfMagnitude) else: sciNotStr = u'\xd7'+'1e%d'% self.orderOfMagnitude - if self._useMathText or self._usetex: + if self._useMathText: + return ''.join(('$\mathdefault{',sciNotStr,offsetStr,'}$')) + elif self._usetex: return ''.join(('$',sciNotStr,offsetStr,'$')) - else: return ''.join((sciNotStr,offsetStr)) + else: + return ''.join((sciNotStr,offsetStr)) else: return '' def set_locs(self, locs): @@ -363,8 +366,11 @@ for loc in locs] sigfigs.sort() self.format = '%1.' + str(sigfigs[-1]) + 'f' - if self._usetex or self._useMathText: self.format = '$%s$'%self.format - + if self._usetex: + self.format = '$%s$' % self.format + elif self._useMathText: + self.format = '$\mathdefault{%s}$' % self.format + def pprint_val(self, x): xp = (x-self.offset)/10**self.orderOfMagnitude if npy.absolute(xp) < 1e-8: xp = 0 @@ -511,11 +517,13 @@ elif not isDecade: if usetex: s = r'$%d^{%.2f}$'% (b, fx) - else: s = '$%d^{%.2f}$'% (b, fx) + else: + s = '$\mathdefault{%d^{%.2f}}$'% (b, fx) else: if usetex: s = r'$%d^{%d}$'% (b, self.nearest_long(fx)) - else: s = r'$%d^{%d}$'% (b, self.nearest_long(fx)) + else: + s = r'$\mathdefault{%d^{%d}}$'% (b, self.nearest_long(fx)) return s This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-01 11:54:17
|
Revision: 3906 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3906&view=rev Author: mdboom Date: 2007-10-01 04:53:52 -0700 (Mon, 01 Oct 2007) Log Message: ----------- Merged revisions 3896-3905 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3898 | jdh2358 | 2007-09-28 08:41:08 -0400 (Fri, 28 Sep 2007) | 2 lines fixed some tick accessor bugs ........ r3899 | jouni | 2007-09-28 11:50:01 -0400 (Fri, 28 Sep 2007) | 3 lines Catch UnboundLocalError in checkdep_pdftops; it is raised if no output line of pdftops -v contains the word "version". ........ r3900 | jouni | 2007-09-28 11:57:49 -0400 (Fri, 28 Sep 2007) | 2 lines More debugging output when using TeX with the pdf backend ........ r3901 | jouni | 2007-09-30 16:08:50 -0400 (Sun, 30 Sep 2007) | 3 lines use_tex in pdf backend: don't use AFM files, which are not there in some TeX distros ........ r3902 | efiring | 2007-09-30 16:32:31 -0400 (Sun, 30 Sep 2007) | 4 lines bugfix by Zack, confirmed by Gary Ruben. http://sourceforge.net/mailarchive/forum.php?thread_name=d8cf9020703071339y43354eaerbfa1a47d272e5d26%40mail.gmail.com&forum_name=matplotlib-users ........ r3903 | efiring | 2007-09-30 16:47:55 -0400 (Sun, 30 Sep 2007) | 2 lines Apply patch by Leon Barrett, tracker #1798196 ........ r3904 | efiring | 2007-10-01 03:06:43 -0400 (Mon, 01 Oct 2007) | 2 lines Fixed bug in updating dataLim when an axis is reversed ........ Modified Paths: -------------- branches/transforms/CHANGELOG branches/transforms/lib/matplotlib/__init__.py branches/transforms/lib/matplotlib/axes3d.py branches/transforms/lib/matplotlib/axis.py branches/transforms/lib/matplotlib/backends/backend_pdf.py branches/transforms/lib/matplotlib/dviread.py branches/transforms/lib/matplotlib/widgets.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3895 + /trunk/matplotlib:1-3905 Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-10-01 11:44:54 UTC (rev 3905) +++ branches/transforms/CHANGELOG 2007-10-01 11:53:52 UTC (rev 3906) @@ -1,3 +1,10 @@ +2007-09-30 Modified update* methods of Bbox and Interval so they + work with reversed axes. Prior to this, trying to + set the ticks on a reversed axis failed with an + uninformative error message. - EF + +2007-09-30 Applied patches to axes3d to fix index error problem - EF + 2007-09-24 Applied Eike Welk's patch reported on mpl-dev on 2007-09-22 Fixes a bug with multiple plot windows in the qt backend, ported the changes to backend_qt4 as well - DSD @@ -2,3 +9,3 @@ -2007-09-21 Changed cbook.reversed to yield the same result as the +2007-09-21 Changed cbook.reversed to yield the same result as the python reversed builtin - DSD Modified: branches/transforms/lib/matplotlib/__init__.py =================================================================== --- branches/transforms/lib/matplotlib/__init__.py 2007-10-01 11:44:54 UTC (rev 3905) +++ branches/transforms/lib/matplotlib/__init__.py 2007-10-01 11:53:52 UTC (rev 3906) @@ -270,7 +270,7 @@ v = line.split()[-1] float(v) return v - except (IndexError, ValueError): + except (IndexError, ValueError, UnboundLocalError): return None def compare_versions(a, b): Modified: branches/transforms/lib/matplotlib/axes3d.py =================================================================== --- branches/transforms/lib/matplotlib/axes3d.py 2007-10-01 11:44:54 UTC (rev 3905) +++ branches/transforms/lib/matplotlib/axes3d.py 2007-10-01 11:53:52 UTC (rev 3906) @@ -510,16 +510,16 @@ # polys = [] boxes = [] - for rs in npy.arange(0,rows,rstride): - for cs in npy.arange(0,cols,cstride): + for rs in npy.arange(0,rows-1,rstride): + for cs in npy.arange(0,cols-1,cstride): ps = [] corners = [] for a,ta in [(X,tX),(Y,tY),(Z,tZ)]: - ztop = a[rs][cs:min(cols-1,cs+cstride)] + ztop = a[rs][cs:min(cols,cs+cstride+1)] zleft = ta[min(cols-1,cs+cstride)][rs:min(rows,rs+rstride+1)] zbase = a[min(rows-1,rs+rstride)][cs:min(cols,cs+cstride+1):] zbase = zbase[::-1] - zright = ta[cs][rs:min(rows-1,rs+rstride):] + zright = ta[cs][rs:min(rows,rs+rstride+1):] zright = zright[::-1] corners.append([ztop[0],ztop[-1],zbase[0],zbase[-1]]) z = npy.concatenate((ztop,zleft,zbase,zright)) Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-10-01 11:44:54 UTC (rev 3905) +++ branches/transforms/lib/matplotlib/axis.py 2007-10-01 11:53:52 UTC (rev 3906) @@ -530,8 +530,11 @@ def get_children(self): children = [self.label] - children.extend(self.majorTicks) - children.extend(self.minorTicks) + majorticks = self.get_major_ticks() + minorticks = self.get_minor_ticks() + + children.extend(majorticks) + children.extend(minorticks) return children def cla(self): @@ -654,7 +657,8 @@ def get_gridlines(self): 'Return the grid lines as a list of Line2D instance' - return silent_list('Line2D gridline', [tick.gridline for tick in self.majorTicks]) + ticks = self.get_major_ticks() + return silent_list('Line2D gridline', [tick.gridline for tick in ticks]) def get_label(self): 'Return the axis label as a Text instance' @@ -670,14 +674,16 @@ def get_ticklabels(self): 'Return a list of Text instances for ticklabels' - labels1 = [tick.label1 for tick in self.majorTicks if tick.label1On] - labels2 = [tick.label2 for tick in self.majorTicks if tick.label2On] + ticks = self.get_major_ticks() + labels1 = [tick.label1 for tick in ticks if tick.label1On] + labels2 = [tick.label2 for tick in ticks if tick.label2On] return silent_list('Text ticklabel', labels1+labels2) def get_ticklines(self): 'Return the ticklines lines as a list of Line2D instance' lines = [] - for tick in self.majorTicks: + ticks = self.get_major_ticks() + for tick in ticks: lines.append(tick.tick1line) lines.append(tick.tick2line) return silent_list('Line2D ticklines', lines) @@ -1087,9 +1093,10 @@ """ assert position == 'top' or position == 'bottom' or position == 'both' or position == 'default' - ticks = list(self.majorTicks) # a copy - ticks.extend( self.minorTicks ) + ticks = list( self.get_major_ticks() ) # a copy + ticks.extend( self.get_minor_ticks() ) + if position == 'top': for t in ticks: t.tick1On = False @@ -1287,8 +1294,8 @@ """ assert position == 'left' or position == 'right' or position == 'both' or position == 'default' - ticks = list(self.majorTicks) # a copy - ticks.extend( self.minorTicks ) + ticks = list( self.get_major_ticks() ) # a copy + ticks.extend( self.get_minor_ticks() ) if position == 'right': self.set_offset_position('right') Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-10-01 11:44:54 UTC (rev 3905) +++ branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-10-01 11:53:52 UTC (rev 3906) @@ -500,70 +500,15 @@ finally: fh.close() - fh = open(fontinfo.afmfile, 'rb') - matplotlib.verbose.report( - 'Reading metrics from ' + fontinfo.afmfile, 'debug') - try: - afmdata = AFM(fh) - finally: - fh.close() - font = FT2Font(filename) - font.attach_file(fontinfo.afmfile) widthsObject, fontdescObject, fontdictObject, fontfileObject = \ [ self.reserveObject(n) for n in ('font widths', 'font descriptor', 'font dictionary', 'font file') ] - _, _, fullname, familyname, weight, italic_angle, fixed_pitch, \ - ul_position, ul_thickness = font.get_ps_font_info() - - if fontinfo.encodingfile is not None: - enc = dviread.Encoding(fontinfo.encodingfile) - widths = [] - for ch in enc: - try: - widths.append(afmdata.get_width_from_char_name(ch)) - except KeyError: - matplotlib.verbose.report( - 'No width for %s in %s' % (ch, fullname), 'debug-annoying') - widths.append(0) - - differencesArray = [ Name(ch) for ch in enc ] - differencesArray = [ 0 ] + differencesArray - firstchar = 0 - lastchar = len(differencesArray) - 2 - else: - widths = [ None for i in range(256) ] - for ch in range(256): - try: - widths[ch] = afmdata.get_width_char(ch, isord=True) - except KeyError: - pass - not_None = [ch for ch in range(256) - if widths[ch] is not None] - firstchar = not_None[0] - lastchar = not_None[-1] - widths = widths[firstchar:lastchar+1] - for i,w in enumerate(widths): - if w is None: widths[i] = 0 - - differencesArray = [ ] - need_idx = True - for ch in range(firstchar, lastchar+1): - try: - name = afmdata.get_name_char(ch, isord=True) - if need_idx: - differencesArray.append(ch) - need_idx = False - differencesArray.append(Name(name)) - except KeyError: - matplotlib.verbose.report( - 'No name for glyph %d in %s' % (ch, fullname), - 'debug-annoying') - need_idx = True - + firstchar = 0 + lastchar = len(fontinfo.widths) - 1 fontdict = { 'Type': Name('Font'), @@ -575,15 +520,22 @@ 'FontDescriptor': fontdescObject, } - fontdict.update({ - 'Encoding': { 'Type': Name('Encoding'), - 'Differences': differencesArray }, - }) + if fontinfo.encodingfile is not None: + enc = dviread.Encoding(fontinfo.encodingfile) + differencesArray = [ Name(ch) for ch in enc ] + differencesArray = [ 0 ] + differencesArray + fontdict.update({ + 'Encoding': { 'Type': Name('Encoding'), + 'Differences': differencesArray }, + }) + _, _, fullname, familyname, weight, italic_angle, fixed_pitch, \ + ul_position, ul_thickness = font.get_ps_font_info() + flags = 0 if fixed_pitch: flags |= 1 << 0 # fixed width if 0: flags |= 1 << 1 # TODO: serif - if 1: flags |= 1 << 2 # TODO: symbolic + if 1: flags |= 1 << 2 # TODO: symbolic (most TeX fonts are) else: flags |= 1 << 5 # non-symbolic if italic_angle: flags |= 1 << 6 # italic if 0: flags |= 1 << 16 # TODO: all caps @@ -598,33 +550,17 @@ 'ItalicAngle': italic_angle, 'Ascent': font.ascender, 'Descent': font.descender, - 'CapHeight': 1000, # default guess if missing from AFM file - 'XHeight': afmdata.get_xheight(), + 'CapHeight': 1000, # TODO: find this out + 'XHeight': 500, # TODO: this one too 'FontFile': fontfileObject, 'FontFamily': familyname, + 'StemV': 50, # TODO + # (see also revision 3874; but not all TeX distros have AFM files!) #'FontWeight': a number where 400 = Regular, 700 = Bold } - try: - descriptor['CapHeight'] = afmdata.get_capheight() - except KeyError: - pass - # StemV is obligatory in PDF font descriptors but optional in - # AFM files. The collection of AFM files in my TeX Live 2007 - # collection has values ranging from 22 to 219, with both - # median and mode 50, so if the AFM file is silent, I'm - # guessing 50. -JKS - StemV = afmdata.get_vertical_stem_width() - if StemV is None: StemV = 50 - descriptor['StemV'] = StemV - - # StemH is entirely optional: - StemH = afmdata.get_horizontal_stem_width() - if StemH is not None: - descriptor['StemH'] = StemH - self.writeObject(fontdictObject, fontdict) - self.writeObject(widthsObject, widths) + self.writeObject(widthsObject, fontinfo.widths) self.writeObject(fontdescObject, descriptor) t1font = type1font.Type1Font(filename) @@ -1470,11 +1406,13 @@ oldfont, seq = None, [] for x1, y1, dvifont, glyph, width in page.text: if dvifont != oldfont: - fontinfo = self.tex_font_mapping(dvifont.texname) - pdfname = self.file.fontName(fontinfo.filename) - self.file.fontInfo[pdfname] = Bunch( - encodingfile=fontinfo.encoding, - afmfile=fontinfo.afm) + psfont = self.tex_font_mapping(dvifont.texname) + pdfname = self.file.fontName(psfont.filename) + if self.file.fontInfo.get(pdfname, None) is None: + self.file.fontInfo[pdfname] = Bunch( + encodingfile=psfont.encoding, + widths=dvifont.widths, + dvifont=dvifont) seq += [['font', pdfname, dvifont.size]] oldfont = dvifont seq += [['text', x1, y1, [chr(glyph)], x1+width]] Modified: branches/transforms/lib/matplotlib/dviread.py =================================================================== --- branches/transforms/lib/matplotlib/dviread.py 2007-10-01 11:44:54 UTC (rev 3905) +++ branches/transforms/lib/matplotlib/dviread.py 2007-10-01 11:53:52 UTC (rev 3906) @@ -84,7 +84,7 @@ e = 0 # zero depth else: # glyph x,y,font,g,w = elt - h = _mul2012(font._scale, font._tfm.height[g]) + h = _mul2012(font._scale, font._tfm.height[g]) e = _mul2012(font._scale, font._tfm.depth[g]) minx = min(minx, x) miny = min(miny, y - h) @@ -380,19 +380,21 @@ class DviFont(object): """ - Object that holds a font's texname and size and supports comparison. + Object that holds a font's texname and size, supports comparison, + and knows the widths of glyphs in the same units as the AFM file. There are also internal attributes (for use by dviread.py) that are _not_ used for comparison. The size is in Adobe points (converted from TeX points). """ - __slots__ = ('texname', 'size', '_scale', '_vf', '_tfm') + __slots__ = ('texname', 'size', 'widths', '_scale', '_vf', '_tfm') def __init__(self, scale, tfm, texname, vf): self._scale, self._tfm, self.texname, self._vf = \ scale, tfm, texname, vf - # TODO: would it make more sense to have the size in dpi units? self.size = scale * (72.0 / (72.27 * 2**16)) + self.widths = [ (1000*tfm.width.get(char, 0)) >> 20 + for char in range(0, max(tfm.width)) ] def __eq__(self, other): return self.__class__ == other.__class__ and \ @@ -402,6 +404,10 @@ return not self.__eq__(other) def _width_of(self, char): + """ + Width of char in dvi units. For internal use by dviread.py. + """ + width = self._tfm.width.get(char, None) if width is not None: return _mul2012(width, self._scale) @@ -598,7 +604,6 @@ fn, enc = result.filename, result.encoding if fn is not None and not fn.startswith('/'): result.filename = find_tex_file(fn) - result.afm = find_tex_file(fn[:-4] + '.afm') if enc is not None and not enc.startswith('/'): result.encoding = find_tex_file(result.encoding) return result @@ -734,6 +739,9 @@ result = pipe.readline().rstrip() pipe.close() + matplotlib.verbose.report('find_tex_file: %s -> %s' \ + % (filename, result), + 'debug') return result # With multiple text objects per figure (e.g. tick labels) we may end Modified: branches/transforms/lib/matplotlib/widgets.py =================================================================== --- branches/transforms/lib/matplotlib/widgets.py 2007-10-01 11:44:54 UTC (rev 3905) +++ branches/transforms/lib/matplotlib/widgets.py 2007-10-01 11:53:52 UTC (rev 3906) @@ -971,14 +971,14 @@ print ' endposition : (%f, %f)' % (erelease.xdata, erelease.ydata) print ' used button : ', eclick.button - def toggle_Selector(event): + def toggle_selector(event): print ' Key pressed.' - if event.key in ['Q', 'q'] and toggle_Selector.RS.active: + if event.key in ['Q', 'q'] and toggle_selector.RS.active: print ' RectangleSelector deactivated.' - toggle_Selector.RS.set_active(False) - if event.key in ['A', 'a'] and not toggle_Selector.RS.active: + toggle_selector.RS.set_active(False) + if event.key in ['A', 'a'] and not toggle_selector.RS.active: print ' RectangleSelector activated.' - toggle_Selector.RS.set_active(True) + toggle_selector.RS.set_active(True) x = arange(100)/(99.0) y = sin(x) @@ -986,8 +986,8 @@ ax = subplot(111) ax.plot(x,y) - toggle_Selector.RS = RectangleSelector(ax, onselect, drawtype='line') - connect('key_press_event', toggle_Selector) + toggle_selector.RS = RectangleSelector(ax, onselect, drawtype='line') + connect('key_press_event', toggle_selector) show() """ def __init__(self, ax, onselect, drawtype='box', This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-03 12:50:11
|
Revision: 3908 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3908&view=rev Author: mdboom Date: 2007-10-03 05:50:04 -0700 (Wed, 03 Oct 2007) Log Message: ----------- Lots of progress on Polar transform refactoring. Added point_in_path algorithm. Modified Paths: -------------- branches/transforms/lib/matplotlib/artist.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/axis.py branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/cbook.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/path.py branches/transforms/lib/matplotlib/scale.py branches/transforms/lib/matplotlib/text.py branches/transforms/lib/matplotlib/ticker.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/setup.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h Added Paths: ----------- branches/transforms/lib/matplotlib/projections/ branches/transforms/lib/matplotlib/projections/polar.py Removed Paths: ------------- branches/transforms/lib/matplotlib/pbox.py Modified: branches/transforms/lib/matplotlib/artist.py =================================================================== --- branches/transforms/lib/matplotlib/artist.py 2007-10-02 08:30:29 UTC (rev 3907) +++ branches/transforms/lib/matplotlib/artist.py 2007-10-03 12:50:04 UTC (rev 3908) @@ -1,7 +1,8 @@ from __future__ import division import sys, re from cbook import iterable, flatten -from transforms import Affine2D +from transforms import Affine2D, Bbox, IdentityTransform, TransformedBbox, \ + TransformedPath import matplotlib.units as units ## Note, matplotlib artists use the doc strings for set and get @@ -145,7 +146,7 @@ def get_transform(self): 'return the Transformation instance used by this artist' if self._transform is None: - self._transform = Affine2D() + self._transform = IdentityTransform() return self._transform def hitlist(self,event): @@ -284,17 +285,29 @@ self._clipon = clipbox is not None or self._clippath is not None self.pchanged() - def set_clip_path(self, path): + def set_clip_path(self, path, transform=None): """ Set the artist's clip path - ACCEPTS: an agg.path_storage instance + ACCEPTS: a Path instance and a Transform instance, or a Patch instance """ - self._clippath = path + from patches import Patch, Rectangle + if transform is None: + if isinstance(path, Rectangle): + self.clipbox = TransformedBbox(Bbox.unit(), path.get_transform()) + elif isinstance(path, Patch): + self._clippath = TransformedPath( + path.get_path(), + path.get_transform()) + elif path is None: + self._clippath = None + else: + raise TypeError("Invalid arguments to set_clip_path") + else: + self._clippath = TransformedPath(path, transform) self._clipon = self.clipbox is not None or path is not None self.pchanged() - def get_alpha(self): """ Return the alpha value used for blending - not supported on all @@ -431,6 +444,7 @@ self._alpha = other._alpha self.clipbox = other.clipbox self._clipon = other._clipon + self._clippath = other._clippath self._lod = other._lod self._label = other._label self.pchanged() Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-02 08:30:29 UTC (rev 3907) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-03 12:50:04 UTC (rev 3908) @@ -1,5 +1,5 @@ from __future__ import division, generators -import math, sys, warnings, copy +import math, sys, warnings, copy, new import numpy as npy @@ -24,7 +24,6 @@ from matplotlib import cm from matplotlib import patches as mpatches from matplotlib import path as mpath -from matplotlib import pbox as mpbox from matplotlib import quiver as mquiver from matplotlib import scale as mscale from matplotlib import table as mtable @@ -428,15 +427,8 @@ """ - - # MGDTODO -# scaled = {mtrans.IDENTITY : 'linear', -# mtrans.LOG10 : 'log', -# } - scaled = {0 : 'linear', - 1 : 'log', - } - + name = "rectilinear" + _shared_x_axes = cbook.Grouper() _shared_y_axes = cbook.Grouper() @@ -474,16 +466,16 @@ visible: a boolean - whether the axes is visible xlabel: the xlabel xlim: (xmin, xmax) view limits - xscale: ['log' | 'linear' ] + xscale: [%(scale)s] xticklabels: sequence of strings xticks: sequence of floats ylabel: the ylabel strings ylim: (ymin, ymax) view limits - yscale: ['log' | 'linear'] + yscale: [%(scale)s] yticklabels: sequence of strings yticks: sequence of floats - """ + """ % {'scale': ' | '.join([repr(x) for x in mscale.get_scale_names()])} martist.Artist.__init__(self) self._position = mtransforms.Bbox.from_lbwh(*rect) self._originalPosition = copy.deepcopy(self._position) @@ -637,6 +629,10 @@ # It is assumed that this part will have non-linear components self.transScale = mtransforms.TransformWrapper(mtransforms.IdentityTransform()) + self._set_transData() + + # MGDTODO: Rename this method + def _set_transData(self): # A (possibly non-linear) projection on the (already scaled) data self.transProjection = mtransforms.IdentityTransform() @@ -647,7 +643,33 @@ self.transData = self.transScale + self.transProjection + self.transLimits + self.transAxes + self._xaxis_transform = mtransforms.blended_transform_factory( + self.axes.transData, self.axes.transAxes) + self._yaxis_transform = mtransforms.blended_transform_factory( + self.axes.transAxes, self.axes.transData) + def get_xaxis_transform(self): + return self._xaxis_transform + + def get_xaxis_text1_transform(self, pad_pixels): + return (self._xaxis_transform + + mtransforms.Affine2D().translate(0, -1 * pad_pixels)) + + def get_xaxis_text2_transform(self, pad_pixels): + return (self._xaxis_transform + + mtransforms.Affine2D().translate(0, pad_pixels)) + + def get_yaxis_transform(self): + return self._yaxis_transform + + def get_yaxis_text1_transform(self, pad_pixels): + return (self._yaxis_transform + + mtransforms.Affine2D().translate(-1 * pad_pixels, 0)) + + def get_yaxis_text2_transform(self, pad_pixels): + return (self._yaxis_transform + + mtransforms.Affine2D().translate(pad_pixels, 0)) + def _update_transScale(self): self.transScale.set( mtransforms.blended_transform_factory( @@ -691,6 +713,9 @@ a.set_transform(self.transData) a.axes = self + def get_axes_patch(self): + return mpatches.Rectangle((0.0, 0.0), 1.0, 1.0) + def cla(self): 'Clear the current axes' @@ -734,24 +759,26 @@ self.title.set_clip_box(None) self._set_artist_props(self.title) - - self.axesPatch = mpatches.Rectangle( - xy=(0,0), width=1, height=1, - facecolor=self._axisbg, - edgecolor=rcParams['axes.edgecolor'], - ) + + self.axesPatch = self.get_axes_patch() self.axesPatch.set_figure(self.figure) - self.axesPatch.set_transform(self.transAxes) + self.axesPatch.set_facecolor(self._axisbg) + self.axesPatch.set_edgecolor(rcParams['axes.edgecolor']) self.axesPatch.set_linewidth(rcParams['axes.linewidth']) - # MGDTODO: What is axesFrame for? We already have axesPatch - self.axesFrame = mlines.Line2D((0,1,1,0,0), (0,0,1,1,0), - linewidth=rcParams['axes.linewidth'], - color=rcParams['axes.edgecolor'], - figure=self.figure) + self.axesPatch.set_transform(self.transAxes) + + self.axesFrame = self.get_axes_patch() + self.axesFrame.set_figure(self.figure) + self.axesFrame.set_facecolor(None) + self.axesFrame.set_edgecolor(rcParams['axes.edgecolor']) + self.axesFrame.set_linewidth(rcParams['axes.linewidth']) self.axesFrame.set_transform(self.transAxes) self.axesFrame.set_zorder(2.5) self.axison = True + self.xaxis.set_clip_path(self.axesPatch) + self.yaxis.set_clip_path(self.axesPatch) + def clear(self): 'clear the axes' self.cla() @@ -838,19 +865,23 @@ """ ACCEPTS: ['C', 'SW', 'S', 'SE', 'E', 'NE', 'N', 'NW', 'W'] """ - if anchor in mpbox.PBox.coefs.keys() or len(anchor) == 2: + if anchor in mtransforms.Bbox.coefs.keys() or len(anchor) == 2: self._anchor = anchor else: raise ValueError('argument must be among %s' % - ', '.join(PBox.coefs.keys())) + ', '.join(mtransforms.BBox.coefs.keys())) - - def apply_aspect(self, data_ratio = None): + def get_data_ratio(self): + xmin,xmax = self.get_xlim() + xsize = max(math.fabs(xmax-xmin), 1e-30) + ymin,ymax = self.get_ylim() + ysize = max(math.fabs(ymax-ymin), 1e-30) + return ysize/xsize + + def apply_aspect(self): ''' Use self._aspect and self._adjustable to modify the axes box or the view limits. - The data_ratio kwarg is set to 1 for polar axes. It is - used only when _adjustable is 'box'. ''' if self._aspect == 'auto': @@ -869,18 +900,11 @@ figW,figH = self.get_figure().get_size_inches() fig_aspect = figH/figW - #print 'figW, figH, fig_aspect', figW, figH, fig_aspect - xmin,xmax = self.get_xlim() - xsize = max(math.fabs(xmax-xmin), 1e-30) - ymin,ymax = self.get_ylim() - ysize = max(math.fabs(ymax-ymin), 1e-30) if self._adjustable == 'box': - if data_ratio is None: - data_ratio = ysize/xsize - box_aspect = A * data_ratio - pb = mpbox.PBox(self._originalPosition) - pb1 = pb.shrink_to_aspect(box_aspect, fig_aspect) - self.set_position(pb1.anchor(self._anchor), 'active') + box_aspect = A * self.get_data_ratio() + pb = self._originalPosition.frozen() + pb1 = pb.shrunk_to_aspect(box_aspect, pb, fig_aspect) + self.set_position(pb1.anchored(self._anchor, pb), 'active') return @@ -1079,7 +1103,7 @@ collection.set_label('collection%d'%len(self.collections)) self.collections.append(collection) self._set_artist_props(collection) - collection.set_clip_box(self.bbox) + collection.set_clip_path(self.axesPatch) if autolim: self.update_datalim(collection.get_verts(self.transData)) collection._remove_method = lambda h: self.collections.remove(h) @@ -1087,7 +1111,7 @@ def add_line(self, line): 'Add a line to the list of plot lines' self._set_artist_props(line) - line.set_clip_box(self.bbox) + line.set_clip_path(self.axesPatch) self._update_line_limits(line) if not line.get_label(): @@ -1107,7 +1131,7 @@ """ self._set_artist_props(p) - p.set_clip_box(self.bbox) + p.set_clip_path(self.axesPatch) self._update_patch_limits(p) self.patches.append(p) p._remove_method = lambda h: self.patches.remove(h) @@ -1115,7 +1139,7 @@ def _update_patch_limits(self, p): 'update the datalimits for patch p' xys = self._get_verts_in_data_coords( - p.get_transform(), p.get_verts()) + p.get_transform(), p.get_path().vertices) self.update_datalim(xys) @@ -1160,8 +1184,8 @@ # display and then back to data to get it in data units #xys = trans.seq_xy_tups(xys) #return [ self.transData.inverse_xy_tup(xy) for xy in xys] - xys = trans(npy.asarray(xys)) - return self.transData.inverted()(xys) + xys = trans.transform(npy.asarray(xys)) + return self.transData.inverted().transform(xys) def _process_unit_info(self, xdata=None, ydata=None, kwargs=None): 'look for unit kwargs and update the axis instances as necessary' @@ -1189,9 +1213,9 @@ #print '\tkw setting yunits', yunits self.yaxis.set_units(yunits) - def in_axes(self, xwin, ywin): + def in_axes(self, mouseevent): 'return True is the point xwin, ywin (display coords) are in the Axes' - return self.bbox.contains(xwin, ywin) + return self.axesPatch.contains(mouseevent)[0] def get_autoscale_on(self): """ @@ -1207,7 +1231,6 @@ """ self._autoscaleon = b - def autoscale_view(self, tight=False, scalex=True, scaley=True): """ autoscale the view limits using the data limits. You can @@ -1239,8 +1262,8 @@ if yl[1] < yl[0]: YL = YL[::-1] self.set_ylim(YL) - #### Drawing + #### Drawing def draw(self, renderer=None, inframe=False): "Draw everything (plot lines, axes, labels)" if renderer is None: @@ -1252,7 +1275,9 @@ renderer.open_group('axes') self.apply_aspect() - if self.axison and self._frameon: self.axesPatch.draw(renderer) + if self.axison and self._frameon: + self.axesPatch.draw(renderer) + artists = [] if len(self.images)<=1 or renderer.option_image_nocomposite(): @@ -1262,7 +1287,6 @@ # make a composite image blending alpha # list of (mimage.Image, ox, oy) - mag = renderer.get_image_magnification() ims = [(im.make_image(mag),0,0) for im in self.images if im.get_visible()] @@ -1277,8 +1301,6 @@ # respect z-order for now renderer.draw_image(l, b, im, self.bbox) - - artists.extend(self.collections) artists.extend(self.patches) artists.extend(self.lines) @@ -1517,14 +1539,15 @@ return xmin, xmax def get_xscale(self): - 'return the xaxis scale string: log or linear' + 'return the xaxis scale string: %s' % ( + ", ".join(mscale.get_scale_names())) return self.xaxis.get_scale() def set_xscale(self, value, **kwargs): """ - SET_XSCALE(value, basex=10, subsx=None) + SET_XSCALE(value) - Set the xscaling: 'log' or 'linear' + Set the xscaling: %(scale)s If value is 'log', the additional kwargs have the following meaning @@ -1536,8 +1559,8 @@ put minor ticks on 1,2,5,11,12,15,21, ....To turn off minor ticking, set subsx=[] - ACCEPTS: ['log' | 'linear' ] - """ + ACCEPTS: [%(scale)s] + """ % {'scale': ' | '.join([repr(x) for x in mscale.get_scale_names()])} self.xaxis.set_scale(value, **kwargs) self._update_transScale() @@ -1610,11 +1633,6 @@ if ymin is None: ymin = old_ymin if ymax is None: ymax = old_ymax - # MGDTODO -# if (self.transData.get_funcy().get_type()==mtrans.LOG10 -# and min(ymin, ymax)<=0): -# raise ValueError('Cannot set nonpositive limits with log transform') - ymin, ymax = mtransforms.nonsingular(ymin, ymax, increasing=False) self.viewLim.intervaly = (ymin, ymax) if emit: @@ -1627,14 +1645,15 @@ return ymin, ymax def get_yscale(self): - 'return the yaxis scale string: log or linear' + 'return the xaxis scale string: %s' % ( + ", ".join(mscale.get_scale_names())) return self.yaxis.get_scale() def set_yscale(self, value, **kwargs): """ SET_YSCALE(value, basey=10, subsy=None) - Set the yscaling: 'log' or 'linear' + Set the yscaling: %(scale)s If value is 'log', the additional kwargs have the following meaning @@ -1646,8 +1665,8 @@ put minor ticks on 1,2,5,11,12,15, 21, ....To turn off minor ticking, set subsy=[] - ACCEPTS: ['log' | 'linear'] - """ + ACCEPTS: %(scale)s + """ % {'scale': ' | '.join([repr(x) for x in mscale.get_scale_names()])} self.yaxis.set_scale(value, **kwargs) self._update_transScale() @@ -1682,14 +1701,6 @@ return self.yaxis.set_ticklabels(labels, fontdict, **kwargs) set_yticklabels.__doc__ = cbook.dedent(set_yticklabels.__doc__) % martist.kwdocd - def toggle_log_lineary(self): - 'toggle between log and linear on the y axis' - # MGDTODO -# funcy = self.transData.get_funcy().get_type() -# if funcy==mtrans.LOG10: self.set_yscale('linear') -# elif funcy==mtrans.IDENTITY: self.set_yscale('log') - pass - def xaxis_date(self, tz=None): """Sets up x-axis ticks and labels that treat the x data as dates. @@ -1748,12 +1759,12 @@ def format_coord(self, x, y): 'return a format string formatting the x, y coord' - + if x is None or y is None: + return '' xs = self.format_xdata(x) ys = self.format_ydata(y) return 'x=%s, y=%s'%(xs,ys) - - + #### Interactive manipulation def get_navigate(self): @@ -1784,17 +1795,40 @@ """ self._navigate_mode = b - def drag_pan(self, button, x, y, startx, starty, start_lim, start_trans): + def drag_pan(self, button, key, startx, starty, dx, dy, + start_lim, start_trans): + def format_deltas(key, dx, dy): + if key=='control': + if(abs(dx)>abs(dy)): + dy = dx + else: + dx = dy + elif key=='x': + dy = 0 + elif key=='y': + dx = 0 + elif key=='shift': + if 2*abs(dx) < abs(dy): + dx=0 + elif 2*abs(dy) < abs(dx): + dy=0 + elif(abs(dx)>abs(dy)): + dy=dy/abs(dy)*abs(dx) + else: + dx=dx/abs(dx)*abs(dy) + return (dx,dy) + if button == 1: inverse = start_trans.inverted() - dx = startx - x - dy = starty - y - result = self.bbox.frozen().translated(dx, dy).transformed(inverse) + dx, dy = format_deltas(key, dx, dy) + result = self.bbox.frozen().translated(-dx, -dy).transformed(inverse) elif button == 3: try: + # MGDTODO: This is broken with log scales inverse = start_trans.inverted() - dx = (startx - x) / float(self.bbox.width) - dy = (starty - y) / float(self.bbox.height) + dx, dy = format_deltas(key, dx, dy) + dx = -dx / float(self.bbox.width) + dy = -dy / float(self.bbox.height) xmin, ymin, xmax, ymax = start_lim.lbrt alpha = npy.power(10.0, (dx, dy)) @@ -1806,7 +1840,6 @@ warnings.warn('Overflow while panning') return - # MGDTODO: Could we do this with a single set_lim? self.set_xlim(*result.intervalx) self.set_ylim(*result.intervaly) @@ -1880,7 +1913,7 @@ """ if callable(self._contains): return self._contains(self,mouseevent) - inside = self.bbox.contains(mouseevent.x,mouseevent.y) + inside = self.axesPatch.contains(mouseevent.x, mouseevent.y) return inside,{} def pick(self,*args): @@ -2100,7 +2133,7 @@ #if t.get_clip_on(): t.set_clip_box(self.bbox) - if kwargs.has_key('clip_on'): t.set_clip_box(self.bbox) + if kwargs.has_key('clip_on'): t.set_clip_path(self.axesPatch) return t text.__doc__ = cbook.dedent(text.__doc__) % martist.kwdocd @@ -2118,7 +2151,7 @@ a = mtext.Annotation(*args, **kwargs) a.set_transform(mtransforms.Affine2D()) self._set_artist_props(a) - if kwargs.has_key('clip_on'): a.set_clip_box(self.bbox) + if kwargs.has_key('clip_on'): a.set_clip_path(self.axesPatch) self.texts.append(a) return a annotate.__doc__ = cbook.dedent(annotate.__doc__) % martist.kwdocd @@ -5056,7 +5089,7 @@ Subplot(211) # 2 rows, 1 column, first (upper) plot """ - def __init__(self, fig, *args): + def __init__(self, fig, *args, **kwargs): """ fig is a figure instance @@ -5087,6 +5120,10 @@ self.update_params() + # _axes_class is set in the subplot_class_factory + self._axes_class.__init__(self, fig, [self.figLeft, self.figBottom, + self.figW, self.figH], **kwargs) + def get_geometry(self): 'get the subplot geometry, eg 2,2,3' return self._rows, self._cols, self._num+1 @@ -5176,36 +5213,18 @@ for label in self.get_yticklabels(): label.set_visible(firstcol) -class Subplot(SubplotBase, Axes): - """ - Emulate matlab's(TM) subplot command, creating axes with +def subplot_class_factory(axes_class=None): + # MGDTODO: This is a little bit strange to make a new class on the + # fly like this, but it keeps things relatively similar to how they + # were before + new_class = new.classobj("%sSubplot" % (axes_class.__name__), + (SubplotBase, axes_class), + {'_axes_class': axes_class}) + return new_class - Subplot(numRows, numCols, plotNum) - where plotNum=1 is the first plot number and increasing plotNums - fill rows first. max(plotNum)==numRows*numCols - - You can leave out the commas if numRows<=numCols<=plotNum<10, as - in - - Subplot(211) # 2 rows, 1 column, first (upper) plot - """ - def __str__(self): - return "Subplot(%f,%f,%f,%f)" % (self.bbox.bounds) - - def __init__(self, fig, *args, **kwargs): - """ - See Axes base class documentation for args and kwargs - """ - SubplotBase.__init__(self, fig, *args) - Axes.__init__(self, fig, [self.figLeft, self.figBottom, - self.figW, self.figH], **kwargs) - - - class PolarAxes(Axes): """ - Make a PolarAxes. The rectangular bounding box of the axes is given by @@ -5644,11 +5663,6 @@ 'return the yaxis scale string' return 'polar' - def toggle_log_lineary(self): - 'toggle between log and linear axes ignored for polar' - pass - - def table(self, *args, **kwargs): """ TABLE(*args, **kwargs) @@ -5679,255 +5693,9 @@ PolarAxes.__init__( self, fig, [self.figLeft, self.figBottom, self.figW, self.figH], **kwargs) - -###################################################################### -# New Polar Axes -class PolarAxes(Axes): - class PolarTransform(mtransforms.Transform): - input_dims = 2 - output_dims = 2 - is_separable = False - - def transform(self, tr): - xy = npy.zeros(tr.shape, npy.float_) - t = tr[:, 0:1] - r = tr[:, 1:2] - x = xy[:, 0:1] - y = xy[:, 1:2] - x += r * npy.cos(t) - y += r * npy.sin(t) - return xy - transform_non_affine = transform - - def interpolate(self, a, steps): - steps = npy.floor(steps) - new_length = ((len(a) - 1) * steps) + 1 - new_shape = list(a.shape) - new_shape[0] = new_length - result = npy.zeros(new_shape, a.dtype) - - result[0] = a[0] - a0 = a[0:-1] - a1 = a[1: ] - delta = ((a1 - a0) / steps) - - for i in range(1, int(steps)+1): - result[i::steps] = delta * i + a0 - - return result - -# def transform_path(self, path): -# twopi = 2.0 * npy.pi -# halfpi = 0.5 * npy.pi - -# vertices = path.vertices -# t0 = vertices[0:-1, 0] -# t1 = vertices[1: , 0] -# td = npy.where(t1 > t0, t1 - t0, twopi - (t0 - t1)) -# maxtd = td.max() -# interpolate = npy.ceil(maxtd / halfpi) -# if interpolate > 1.0: -# vertices = self.interpolate(vertices, interpolate) - -# vertices = self.transform(vertices) - -# result = npy.zeros((len(vertices) * 3 - 2, 2), npy.float_) -# codes = mpath.Path.CURVE4 * npy.ones((len(vertices) * 3 - 2, ), mpath.Path.code_type) -# result[0] = vertices[0] -# codes[0] = mpath.Path.MOVETO - -# kappa = 4.0 * ((npy.sqrt(2.0) - 1.0) / 3.0) -# kappa = 0.5 - -# p0 = vertices[0:-1] -# p1 = vertices[1: ] - -# x0 = p0[:, 0:1] -# y0 = p0[:, 1: ] -# b0 = ((y0 - x0) - y0) / ((x0 + y0) - x0) -# a0 = y0 - b0*x0 - -# x1 = p1[:, 0:1] -# y1 = p1[:, 1: ] -# b1 = ((y1 - x1) - y1) / ((x1 + y1) - x1) -# a1 = y1 - b1*x1 - -# x = -(a0-a1) / (b0-b1) -# y = a0 + b0*x - -# xk = (x - x0) * kappa + x0 -# yk = (y - y0) * kappa + y0 - -# result[1::3, 0:1] = xk -# result[1::3, 1: ] = yk - -# xk = (x - x1) * kappa + x1 -# yk = (y - y1) * kappa + y1 - -# result[2::3, 0:1] = xk -# result[2::3, 1: ] = yk - -# result[3::3] = p1 - -# print vertices[-2:] -# print result[-2:] - -# return mpath.Path(result, codes) - -# twopi = 2.0 * npy.pi -# halfpi = 0.5 * npy.pi - -# vertices = path.vertices -# t0 = vertices[0:-1, 0] -# t1 = vertices[1: , 0] -# td = npy.where(t1 > t0, t1 - t0, twopi - (t0 - t1)) -# maxtd = td.max() -# interpolate = npy.ceil(maxtd / halfpi) - -# print "interpolate", interpolate -# if interpolate > 1.0: -# vertices = self.interpolate(vertices, interpolate) - -# result = npy.zeros((len(vertices) * 3 - 2, 2), npy.float_) -# codes = mpath.Path.CURVE4 * npy.ones((len(vertices) * 3 - 2, ), mpath.Path.code_type) -# result[0] = vertices[0] -# codes[0] = mpath.Path.MOVETO - -# kappa = 4.0 * ((npy.sqrt(2.0) - 1.0) / 3.0) -# tkappa = npy.arctan(kappa) -# hyp_kappa = npy.sqrt(kappa*kappa + 1.0) - -# t0 = vertices[0:-1, 0] -# t1 = vertices[1: , 0] -# r0 = vertices[0:-1, 1] -# r1 = vertices[1: , 1] - -# td = npy.where(t1 > t0, t1 - t0, twopi - (t0 - t1)) -# td_scaled = td / (npy.pi * 0.5) -# rd = r1 - r0 -# r0kappa = r0 * kappa * td_scaled -# r1kappa = r1 * kappa * td_scaled -# ravg_kappa = ((r1 + r0) / 2.0) * kappa * td_scaled - -# result[1::3, 0] = t0 + (tkappa * td_scaled) -# result[1::3, 1] = r0*hyp_kappa -# # result[1::3, 1] = r0 / npy.cos(tkappa * td_scaled) # npy.sqrt(r0*r0 + ravg_kappa*ravg_kappa) - -# result[2::3, 0] = t1 - (tkappa * td_scaled) -# result[2::3, 1] = r1*hyp_kappa -# # result[2::3, 1] = r1 / npy.cos(tkappa * td_scaled) # npy.sqrt(r1*r1 + ravg_kappa*ravg_kappa) - -# result[3::3, 0] = t1 -# result[3::3, 1] = r1 - -# print vertices[:6], result[:6], t0[:6], t1[:6], td[:6], td_scaled[:6], tkappa -# result = self.transform(result) -# return mpath.Path(result, codes) -# transform_path_non_affine = transform_path - - def inverted(self): - return PolarAxes.InvertedPolarTransform() - - class PolarAffine(mtransforms.Affine2DBase): - def __init__(self, limits): - mtransforms.Affine2DBase.__init__(self) - self._limits = limits - self.set_children(limits) - self._mtx = None - - def get_matrix(self): - if self._invalid: - xmin, ymin, xmax, ymax = self._limits.lbrt - affine = mtransforms.Affine2D().rotate(xmin).scale(0.5 / ymax).translate(0.5, 0.5) - self._mtx = affine.get_matrix() - self._inverted = None - self._invalid = 0 - return self._mtx - - class InvertedPolarTransform(mtransforms.Transform): - input_dims = 2 - output_dims = 2 - is_separable = False - - def transform(self, xy): - x = xy[:, 0:1] - y = xy[:, 1:] - r = npy.sqrt(x*x + y*y) - theta = npy.arccos(x / r) - theta = npy.where(y < 0, 2 * npy.pi - theta, theta) - return npy.concatenate((theta, r), 1) - - def inverted(self): - return PolarAxes.PolarTransform() - - def _set_lim_and_transforms(self): - """ - set the dataLim and viewLim BBox attributes and the - transData and transAxes Transformation attributes - """ - self.dataLim = mtransforms.Bbox.unit() - self.viewLim = mtransforms.Bbox.unit() - self.transAxes = mtransforms.BboxTransform( - mtransforms.Bbox.unit(), self.bbox) - - # Transforms the x and y axis separately by a scale factor - # It is assumed that this part will have non-linear components - self.transScale = mtransforms.TransformWrapper(mtransforms.IdentityTransform()) - - # A (possibly non-linear) projection on the (already scaled) data - self.transProjection = self.PolarTransform() - - # An affine transformation on the data, generally to limit the - # range of the axes - self.transProjectionAffine = self.PolarAffine(self.viewLim) - - self.transData = self.transScale + self.transProjection + \ - self.transProjectionAffine + self.transAxes - - def drag_pan(self, button, x, y, startx, starty, start_lim, start_trans): - if button == 1: - inverse = start_trans.inverted() - startt, startr = inverse.transform_point((startx, starty)) - t, r = inverse.transform_point((x, y)) - - scale = r / startr - self.set_ylim(start_lim.ymin, start_lim.ymax / scale) - - dt0 = t - startt - dt1 = startt - t - if abs(dt1) < abs(dt0): - dt = abs(dt1) * sign(dt0) * -1.0 - else: - dt = dt0 * -1.0 - self.set_xlim(start_lim.xmin - dt, start_lim.xmin - dt + npy.pi*2.0) - - def set_rmax(self, rmax): - self.viewLim.maxy = rmax - -class PolarSubplot(SubplotBase, PolarAxes): - """ - Create a polar subplot with - - PolarSubplot(numRows, numCols, plotNum) - - where plotNum=1 is the first plot number and increasing plotNums - fill rows first. max(plotNum)==numRows*numCols - - You can leave out the commas if numRows<=numCols<=plotNum<10, as - in - - Subplot(211) # 2 rows, 1 column, first (upper) plot - """ - def __str__(self): - return "PolarSubplot(%gx%g)"%(self.figW,self.figH) - def __init__(self, fig, *args, **kwargs): - SubplotBase.__init__(self, fig, *args) - PolarAxes.__init__( - self, fig, - [self.figLeft, self.figBottom, self.figW, self.figH], **kwargs) - martist.kwdocd['Axes'] = martist.kwdocd['Subplot'] = martist.kwdoc(Axes) + """ # this is some discarded code I was using to find the minimum positive # data point for some log scaling fixes. I realized there was a Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-10-02 08:30:29 UTC (rev 3907) +++ branches/transforms/lib/matplotlib/axis.py 2007-10-03 12:50:04 UTC (rev 3908) @@ -18,12 +18,11 @@ from font_manager import FontProperties from text import Text, TextWithDash, _process_text_args from transforms import Affine2D, Bbox, blended_transform_factory, interval_contains, \ - interval_contains_open, IntervalTransform + interval_contains_open, IntervalTransform, IdentityTransform from patches import bbox_artist from scale import scale_factory import matplotlib.units as units -#import pdb class Tick(Artist): @@ -112,6 +111,12 @@ children = [self.tick1line, self.tick2line, self.gridline, self.label1, self.label2] return children + def set_clip_path(self, clippath, transform=None): + Artist.set_clip_path(self, clippath, transform) + self.tick1line.set_clip_path(clippath, transform) + self.tick2line.set_clip_path(clippath, transform) + self.gridline.set_clip_path(clippath, transform) + def contains(self, mouseevent): """Test whether the mouse event occured in the Tick marks. @@ -164,9 +169,12 @@ midPoint = interval_contains_open(self.get_view_interval(), self.get_loc() ) if midPoint: - if self.gridOn: self.gridline.draw(renderer) - if self.tick1On: self.tick1line.draw(renderer) - if self.tick2On: self.tick2line.draw(renderer) + if self.gridOn: + self.gridline.draw(renderer) + if self.tick1On: + self.tick1line.draw(renderer) + if self.tick2On: + self.tick2line.draw(renderer) if self.label1On: self.label1.draw(renderer) if self.label2On: self.label2.draw(renderer) @@ -213,8 +221,10 @@ 'return the view Interval instance for the axis tjis tick is ticking' raise NotImplementedError('Derived must override') + def set_view_interval(self, vmin, vmax, ignore=False): + raise NotImplementedError('Derived must override') - + class XTick(Tick): """ Contains all the Artists needed to make an x tick - the tick line, @@ -237,12 +247,7 @@ xaxis=True, ) - trans = blended_transform_factory( - self.axes.transData, self.axes.transAxes) - #offset the text downward with a post transformation - trans = trans + Affine2D().translate(0, -1 * self._padPixels) - t.set_transform(trans) - + t.set_transform(self.axes.get_xaxis_text1_transform(self._padPixels)) self._set_artist_props(t) return t @@ -262,11 +267,7 @@ horizontalalignment='center', ) - trans = blended_transform_factory( - self.axes.transData, self.axes.transAxes) - # offset the text upward with a post transformation - trans = trans + Affine2D().translate(0, self._padPixels) - t.set_transform( trans ) + t.set_transform(self.axes.get_xaxis_text2_transform(self._padPixels)) self._set_artist_props(t) return t @@ -280,8 +281,7 @@ marker = self._xtickmarkers[0], markersize=self._size, ) - l.set_transform(blended_transform_factory( - self.axes.transData, self.axes.transAxes) ) + l.set_transform(self.axes.get_xaxis_transform()) self._set_artist_props(l) return l @@ -296,24 +296,20 @@ markersize=self._size, ) - l.set_transform(blended_transform_factory( - self.axes.transData, self.axes.transAxes) ) + l.set_transform(self.axes.get_xaxis_transform()) self._set_artist_props(l) return l def _get_gridline(self, loc): 'Get the default line2D instance' # x in data coords, y in axes coords - l = Line2D( xdata=(loc, loc), ydata=(0, 1), - color=rcParams['grid.color'], - linestyle=rcParams['grid.linestyle'], - linewidth=rcParams['grid.linewidth'], - antialiased=False, - ) - l.set_transform( - blended_transform_factory( - self.axes.transData, self.axes.transAxes)) - l.set_clip_box(self.axes.bbox) + l = Line2D(xdata=(loc, loc), ydata=(0, 1.0), + color=rcParams['grid.color'], + linestyle=rcParams['grid.linestyle'], + linewidth=rcParams['grid.linewidth'], + antialiased=False, + ) + l.set_transform(self.axes.get_xaxis_transform()) self._set_artist_props(l) return l @@ -322,7 +318,6 @@ 'Set the location of tick in data coords with scalar loc' x = loc - self.tick1line.set_xdata((x,)) self.tick2line.set_xdata((x,)) self.gridline.set_xdata((x, )) @@ -334,6 +329,13 @@ 'return the Interval instance for this axis view limits' return self.axes.viewLim.intervalx + def set_view_interval(self, vmin, vmax, ignore = False): + if ignore: + self.axes.viewLim.intervalx = vmin, vmax + else: + Vmin, Vmax = self.get_view_interval() + self.axes.viewLim.intervalx = min(vmin, Vmin), max(vmax, Vmax) + def get_minpos(self): return self.axes.dataLim.minposx @@ -363,12 +365,7 @@ dashdirection=0, xaxis=False, ) - trans = blended_transform_factory( - self.axes.transAxes, self.axes.transData) - # offset the text leftward with a post transformation - trans = trans + Affine2D().translate(-1 * self._padPixels, 0) - - t.set_transform( trans ) + t.set_transform(self.axes.get_yaxis_text1_transform(self._padPixels)) #t.set_transform( self.axes.transData ) self._set_artist_props(t) return t @@ -386,11 +383,7 @@ xaxis=False, horizontalalignment='left', ) - trans = blended_transform_factory( - self.axes.transAxes, self.axes.transData) - # offset the text rightward with a post transformation - trans = trans + Affine2D().translate(self._padPixels, 0) - t.set_transform( trans ) + t.set_transform(self.axes.get_yaxis_text2_transform(self._padPixels)) self._set_artist_props(t) return t @@ -404,9 +397,7 @@ linestyle = 'None', markersize=self._size, ) - l.set_transform( - blended_transform_factory( - self.axes.transAxes, self.axes.transData)) + l.set_transform(self.axes.get_yaxis_transform()) self._set_artist_props(l) return l @@ -420,9 +411,7 @@ markersize=self._size, ) - l.set_transform( - blended_transform_factory( - self.axes.transAxes, self.axes.transData)) + l.set_transform(self.axes.get_yaxis_transform()) self._set_artist_props(l) return l @@ -436,10 +425,7 @@ antialiased=False, ) - l.set_transform( blended_transform_factory( - self.axes.transAxes, self.axes.transData) ) - l.set_clip_box(self.axes.bbox) - + l.set_transform(self.axes.get_yaxis_transform()) self._set_artist_props(l) return l @@ -461,6 +447,13 @@ 'return the Interval instance for this axis view limits' return self.axes.viewLim.intervaly + def set_view_interval(self, vmin, vmax): + if ignore: + self.axes.viewLim.intervaly = vmin, vmax + else: + Vmin, Vmax = self.get_view_interval() + self.axes.viewLim.intervaly = min(vmin, Vmin), max(vmax, Vmax) + def get_minpos(self): return self.axes.dataLim.minposy @@ -530,8 +523,8 @@ def get_children(self): children = [self.label] - majorticks = self.get_major_ticks() - minorticks = self.get_minor_ticks() + majorticks = self.get_major_ticks(len(self.major.locator())) + minorticks = self.get_minor_ticks(len(self.minor.locator())) children.extend(majorticks) children.extend(minorticks) @@ -565,11 +558,20 @@ self.units = None self.set_units(None) - + def set_clip_path(self, clippath, transform=None): + Artist.set_clip_path(self, clippath, transform) + majorticks = self.get_major_ticks(len(self.major.locator())) + minorticks = self.get_minor_ticks(len(self.minor.locator())) + for child in self.majorTicks + self.minorTicks: + child.set_clip_path(clippath, transform) + def get_view_interval(self): 'return the Interval instance for this axis view limits' raise NotImplementedError('Derived must override') + def set_view_interval(self, vmin, vmax, ignore=False): + raise NotImplementedError('Derived must override') + def get_data_interval(self): 'return the Interval instance for this axis data limits' raise NotImplementedError('Derived must override') @@ -585,8 +587,8 @@ ticklabelBoxes = [] ticklabelBoxes2 = [] - majorTicks = self.get_major_ticks() majorLocs = self.major.locator() + majorTicks = self.get_major_ticks(len(majorLocs)) self.major.formatter.set_locs(majorLocs) majorLabels = [self.major.formatter(val, i) for i, val in enumerate(majorLocs)] @@ -609,8 +611,8 @@ extent = tick.label2.get_window_extent(renderer) ticklabelBoxes2.append(extent) - minorTicks = self.get_minor_ticks() minorLocs = self.minor.locator() + minorTicks = self.get_minor_ticks(len(minorLocs)) self.minor.formatter.set_locs(minorLocs) minorLabels = [self.minor.formatter(val, i) for i, val in enumerate(minorLocs)] @@ -727,11 +729,9 @@ 'Get the formatter of the minor ticker' return self.minor.formatter - def get_major_ticks(self): + def get_major_ticks(self, numticks): 'get the tick instances; grow as necessary' - numticks = len(self.major.locator()) - if len(self.majorTicks)<numticks: # update the new tick label properties from the old protoTick = self.majorTicks[0] @@ -746,9 +746,8 @@ return ticks - def get_minor_ticks(self): + def get_minor_ticks(self, numticks): 'get the minor tick instances; grow as necessary' - numticks = len(self.minor.locator()) if len(self.minorTicks)<numticks: protoTick = self.minorTicks[0] for i in range(numticks-len(self.minorTicks)): @@ -949,8 +948,9 @@ ### XXX if the user changes units, the information will be lost here ticks = self.convert_units(ticks) self.set_major_locator( FixedLocator(ticks) ) - self.get_view_interval().update(ticks,0) - return self.get_major_ticks() + if len(ticks): + self.set_view_interval(min(ticks), max(ticks)) + return self.get_major_ticks(len(ticks)) def _update_label_position(self, bboxes, bboxes2): """ @@ -1153,6 +1153,13 @@ 'return the Interval instance for this axis view limits' return self.axes.viewLim.intervalx + def set_view_interval(self, vmin, vmax, ignore=False): + if ignore: + self.axes.viewLim.intervalx = vmin, vmax + else: + Vmin, Vmax = self.get_view_interval() + self.axes.viewLim.intervalx = min(vmin, Vmin), max(vmax, Vmax) + def get_minpos(self): return self.axes.dataLim.minposx @@ -1357,6 +1364,13 @@ 'return the Interval instance for this axis view limits' return self.axes.viewLim.intervaly + def set_view_interval(self, vmin, vmax, ignore=False): + if ignore: + self.axes.viewLim.intervaly = vmin, vmax + else: + Vmin, Vmax = self.get_view_interval() + self.axes.viewLim.intervaly = min(vmin, Vmin), max(vmax, Vmax) + def get_minpos(self): return self.axes.dataLim.minposy Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-10-02 08:30:29 UTC (rev 3907) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-10-03 12:50:04 UTC (rev 3908) @@ -537,7 +537,9 @@ """ Return the clip path """ - return self._clippath + if self._clippath is not None: + return self._clippath.get_transformed_path_and_affine() + return None, None def get_dashes(self): """ @@ -608,7 +610,7 @@ def set_clip_path(self, path): """ - Set the clip path + Set the clip path and transformation """ self._clippath = path @@ -758,7 +760,7 @@ return # Find all axes containing the mouse - axes_list = [a for a in self.canvas.figure.get_axes() if a.in_axes(x, y)] + axes_list = [a for a in self.canvas.figure.get_axes() if a.in_axes(self)] if len(axes_list) == 0: # None found self.inaxes = None @@ -1333,7 +1335,7 @@ if event.key!='a': n=int(event.key)-1 for i, a in enumerate(self.canvas.figure.get_axes()): - if event.x is not None and event.y is not None and a.in_axes(event.x, event.y): + if event.x is not None and event.y is not None and a.in_axes(event): if event.key=='a': a.set_navigate(True) else: @@ -1557,7 +1559,7 @@ self._xypress=[] for i, a in enumerate(self.canvas.figure.get_axes()): - if x is not None and y is not None and a.in_axes(x, y) and a.get_navigate(): + if x is not None and y is not None and a.in_axes(event) and a.get_navigate(): self._xypress.append((x, y, a, i, a.viewLim.frozen(), a.transData.frozen())) self.canvas.mpl_disconnect(self._idDrag) self._idDrag=self.canvas.mpl_connect('motion_notify_event', self.drag_pan) @@ -1581,7 +1583,7 @@ self._xypress=[] for i, a in enumerate(self.canvas.figure.get_axes()): - if x is not None and y is not None and a.in_axes(x, y) and a.get_navigate(): + if x is not None and y is not None and a.in_axes(event) and a.get_navigate(): self._xypress.append(( x, y, a, i, a.viewLim.frozen(), a.transData.frozen())) self.press(event) @@ -1621,33 +1623,12 @@ def drag_pan(self, event): 'the drag callback in pan/zoom mode' - def format_deltas(event,dx,dy): - if event.key=='control': - if(abs(dx)>abs(dy)): - dy = dx - else: - dx = dy - elif event.key=='x': - dy = 0 - elif event.key=='y': - dx = 0 - elif event.key=='shift': - if 2*abs(dx) < abs(dy): - dx=0 - elif 2*abs(dy) < abs(dx): - dy=0 - elif(abs(dx)>abs(dy)): - dy=dy/abs(dy)*abs(dx) - else: - dx=dx/abs(dx)*abs(dy) - return (dx,dy) - for lastx, lasty, a, ind, old_lim, old_trans in self._xypress: #safer to use the recorded button at the press than current button: #multiple button can get pressed during motion... dx, dy = event.x - lastx, event.y - lasty - dx, dy = format_deltas(event, dx, dy) - a.drag_pan(self._button_pressed, lastx + dx, lasty + dy, lastx, lasty, old_lim, old_trans) + a.drag_pan(self._button_pressed, event.key, lastx, lasty, dx, dy, + old_lim, old_trans) self.dynamic_update() def release_zoom(self, event): @@ -1664,7 +1645,7 @@ self.draw() return - xmin, ymin, xmax, ymax = lim + xmin, ymin, xmax, ymax = lim.lbrt # zoom to rect inverse = a.transData.inverted() Modified: branches/transforms/lib/matplotlib/cbook.py =================================================================== --- branches/transforms/lib/matplotlib/cbook.py 2007-10-02 08:30:29 UTC (rev 3907) +++ branches/transforms/lib/matplotlib/cbook.py 2007-10-03 12:50:04 UTC (rev 3908) @@ -1033,7 +1033,27 @@ itself. """ return self._mapping.get(a, [a]) - + + +def simple_linear_interpolation(a, steps): + steps = npy.floor(steps) + new_length = ((len(a) - 1) * steps) + 1 + new_shape = list(a.shape) + new_shape[0] = new_length + result = npy.zeros(new_shape, a.dtype) + + result[0] = a[0] + a0 = a[0:-1] + a1 = a[1: ] + delta = ((a1 - a0) / steps) + + # MGDTODO: Could use linspace here? + for i in range(1, int(steps)): + result[i::steps] = delta * i + a0 + result[steps::steps] = a1 + + return result + if __name__=='__main__': assert( allequal([1,1,1]) ) assert(not allequal([1,1,0]) ) Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-10-02 08:30:29 UTC (rev 3907) +++ branches/transforms/lib/matplotlib/figure.py 2007-10-03 12:50:04 UTC (rev 3908) @@ -7,7 +7,7 @@ import artist from artist import Artist -from axes import Axes, Subplot, PolarSubplot, PolarAxes +from axes import Axes, SubplotBase, subplot_class_factory from cbook import flatten, allequal, Stack, iterable, dedent import _image import colorbar as cbar @@ -22,6 +22,8 @@ from transforms import Affine2D, Bbox, BboxTransform, TransformedBbox from cm import ScalarMappable from contour import ContourSet +from projections import projection_factory, get_projection_names, \ + get_projection_class import warnings class SubplotParams: @@ -449,12 +451,17 @@ """ Add an a axes with axes rect [left, bottom, width, height] where all quantities are in fractions of figure width and height. kwargs are - legal Axes kwargs plus "polar" which sets whether to create a polar axes - + legal Axes kwargs plus "projection" which sets the projection type + of the axes. (For backward compatibility, polar=True may also be + provided, which is equivalent to projection='polar'). + Valid values for "projection" are: %s. Some of these projections + support additional kwargs, which may be provided to add_axes. + rect = l,b,w,h add_axes(rect) add_axes(rect, frameon=False, axisbg='g') add_axes(rect, polar=True) + add_axes(rect, projection='polar') add_axes(ax) # add an Axes instance @@ -470,10 +477,10 @@ add_axes(rect, label='axes2') The Axes instance will be returned - + The following kwargs are supported: - %(Axes)s - """ + %s + """ % (", ".join(get_projection_names()), '%(Axes)s') key = self._make_key(*args, **kwargs) @@ -489,13 +496,17 @@ else: rect = args[0] ispolar = kwargs.pop('polar', False) - + projection = kwargs.pop('projection', None) if ispolar: - a = PolarAxes(self, rect, **kwargs) - else: - a = Axes(self, rect, **kwargs) + if projection is not None and projection != 'polar': + raise ValueError( + "polar=True, yet projection='%s'. " + + "Only one of these arguments should be supplied." % + projection) + projection = 'polar' + + a = projection_factory(projection, self, rect, **kwargs) - self.axes.append(a) self._axstack.push(a) self.sca(a) @@ -513,15 +524,21 @@ add_subplot(111, polar=True) # add a polar subplot add_subplot(sub) # add Subplot instance sub - kwargs are legal Axes kwargs plus"polar" which sets whether to create a - polar axes. The Axes instance will be returned. + kwargs are legal Axes kwargs plus "projection", which chooses + a projection type for the axes. (For backward compatibility, + polar=True may also be provided, which is equivalent to + projection='polar'). Valid values for "projection" are: %s. + Some of these projections support additional kwargs, which may + be provided to add_axes. + The Axes instance will be returned. + If the figure already has a subplot with key *args, *kwargs then it will simply make that subplot current and return it The following kwargs are supported: - %(Axes)s - """ + %s + """ % (", ".join(get_projection_names()), "%(Axes)s") key = self._make_key(*args, **kwargs) if self._seen.has_key(key): @@ -532,16 +549,22 @@ if not len(args): return - if isinstance(args[0], Subplot) or isinstance(args[0], PolarSubplot): + if isinstance(args[0], SubplotBase): a = args[0] assert(a.get_figure() is self) else: ispolar = kwargs.pop('polar', False) + projection = kwargs.pop('projection', None) if ispolar: - a = PolarSubplot(self, *args, **kwargs) - else: - a = Subplot(self, *args, **kwargs) + if projection is not None and projection != 'polar': + raise ValueError( + "polar=True, yet projection='%s'. " + + "Only one of these arguments should be supplied." % + projection) + projection = 'polar' + projection_class = get_projection_class(projection) + a = subplot_class_factory(projection_class)(self, *args, **kwargs) self.axes.append(a) self._axstack.push(a) Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-10-02 08:30:29 UTC (rev 3907) +++ branches/transforms/lib/matplotlib/patches.py 2007-10-03 12:50:04 UTC (rev 3908) @@ -12,6 +12,8 @@ import matplotlib.mlab as mlab import matplotlib.artist as artist from matplotlib.path import Path +# MGDTODO: Maybe this belongs elsewhere +from matplotlib.backends._backend_agg import point_in_path # these are not available for the object inspector until after the # class is build so we define an initial set here for the init @@ -72,6 +74,7 @@ self._linewidth = linewidth self._antialiased = antialiased self._hatch = hatch + self._combined_transform = transforms.IdentityTransform() self.fill = fill if len(kwargs): artist.setp(self, **kwargs) @@ -84,19 +87,15 @@ Returns T/F, {} """ - # MGDTODO: This will probably need to be implemented in C++ - + # This is a general version of contains should work on any + # patch with a path. However, patches that have a faster + # algebraic solution to hit-testing should override this + # method. if callable(self._contains): return self._contains(self,mouseevent) - try: - # TODO: make this consistent with patch collection algorithm - x, y = self.get_transform().inverse_xy_tup((mouseevent.x, mouseevent.y)) - xyverts = self.get_verts() - inside = nxutils.pnpoly(x, y, xyverts) - #print str(self),"%g,%g is in"%(x,y),xyverts,inside - return inside,{} - except ValueError: - return False,{} + inside = point_in_path(mouseevent.x, mouseevent.y, self.get_path(), + self.get_transform().frozen()) + return inside, {} def update_from(self, other): artist.Artist.update_from(self, other) @@ -109,6 +108,17 @@ self.set_figure(other.get_figure()) self.set_alpha(other.get_alpha()) + def get_transform(self): + return self._combined_transform + + def set_transform(self, t): + artist.Artist.set_transform(self, t) + self._combined_transform = self.get_patch_transform() + \ + artist.Artist.get_transform(self) + + def get_patch_transform(self): + return transforms.IdentityTransform() + def get_antialiased(self): return self._antialiased @@ -207,12 +217,12 @@ if not self.fill or self._facecolor is None: rgbFace = None else: rgbFace = colors.colorConverter.to_rgb(self._facecolor) - + if self._hatch: gc.set_hatch(self._hatch ) path = self.get_path() - transform = self.get_patch_transform() + self.get_transform() + transform = self.get_transform() renderer.draw_path(gc, path, transform, rgbFace) @@ -226,12 +236,10 @@ def get_window_extent(self, renderer=None): - verts = self.get_verts() - tverts = self.get_transform().seq_xy_tups(verts) - return transforms.bound_vertices(tverts) + trans_path = self.get_path().transformed(self.get_path_transform()) + return Bbox.unit().update_from_data(trans_path.vertices) - def set_lw(self, val): 'alias for set_linewidth' self.set_linewidth(val) @@ -350,6 +358,11 @@ def get_patch_transform(self): return self._rect_transform + + def contains(self, mouseevent): + x, y = self.get_transform().inverted().transform_point( + (mouseevent.x, mouseevent.y)) + return (x >= 0.0 and x <= 1.0 and y >= 0.0 and y <= 1.0), {} def get_x(self): "Return the left coord of the rectangle" @@ -445,8 +458,8 @@ def get_path(self): return self._path - def get_transform(self): - return self._poly_transform + self._transform + def get_patch_transform(self): + return self._poly_transform class Polygon(Patch): """ @@ -467,39 +480,35 @@ self._path = Path(xy, closed=True) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd - def get_verts(self): + def get_path(self): return self._path - - # MGDTODO: Convert units - xs = self.convert_xunits(xs) - ys = self.convert_yunits(ys) - -class Wedge(Polygon): + +class Wedge(Patch): def __str__(self): return "Wedge(%g,%g)"%self.xy[0] - def __init__(self, center, r, theta1, theta2, - dtheta=0.1, **kwargs): + def __init__(self, center, r, theta1, theta2, **kwargs): """ Draw a wedge centered at x,y tuple center with radius r that sweeps theta1 to theta2 (angles) - dtheta is the resolution in degrees - Valid kwargs are: %(Patch)s """ - # MGDTODO: Implement me - xc, yc = center - rads = (math.pi/180.)*npy.arange(theta1, theta2+0.1*dtheta, dtheta) - xs = r*npy.cos(rads)+xc - ys = r*npy.sin(rads)+yc - ... [truncated message content] |
From: <md...@us...> - 2007-10-03 12:51:20
|
Revision: 3909 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3909&view=rev Author: mdboom Date: 2007-10-03 05:51:16 -0700 (Wed, 03 Oct 2007) Log Message: ----------- Merged revisions 3906-3908 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3907 | efiring | 2007-10-02 04:30:29 -0400 (Tue, 02 Oct 2007) | 2 lines matplotlib.use() raises an exception if called too late ........ Modified Paths: -------------- branches/transforms/CHANGELOG branches/transforms/lib/matplotlib/__init__.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3905 + /trunk/matplotlib:1-3908 Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-10-03 12:50:04 UTC (rev 3908) +++ branches/transforms/CHANGELOG 2007-10-03 12:51:16 UTC (rev 3909) @@ -1,3 +1,6 @@ +2007-10-01 Made matplotlib.use() raise an exception if called after + backends has been imported. + 2007-09-30 Modified update* methods of Bbox and Interval so they work with reversed axes. Prior to this, trying to set the ticks on a reversed axis failed with an Modified: branches/transforms/lib/matplotlib/__init__.py =================================================================== --- branches/transforms/lib/matplotlib/__init__.py 2007-10-03 12:50:04 UTC (rev 3908) +++ branches/transforms/lib/matplotlib/__init__.py 2007-10-03 12:51:16 UTC (rev 3909) @@ -716,6 +716,9 @@ except: from config import rcParams, rcdefaults +_use_error_msg = """ matplotlib.use() must be called *before* pylab +or matplotlib.backends is imported for the first time.""" + def use(arg): """ Set the matplotlib backend to one of the known backends. @@ -732,6 +735,8 @@ for the first time; or, if you are not using pylab, it must be called before importing matplotlib.backends. """ + if 'matplotlib.backends' in sys.modules: + raise RuntimeError(_use_error_msg) be_parts = arg.split('.') name = validate_backend(be_parts[0]) rcParams['backend'] = name This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-04 17:21:31
|
Revision: 3912 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3912&view=rev Author: mdboom Date: 2007-10-04 10:21:26 -0700 (Thu, 04 Oct 2007) Log Message: ----------- Lots of new docstrings. Reasonably good state for polar plots. r-axis labels can be dragged on polar plots. r-scale can be zoomed on polar plot. Lots of other minor changes too numerous to mention. Modified Paths: -------------- branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/axis.py branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/legend.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/path.py branches/transforms/lib/matplotlib/projections/polar.py branches/transforms/lib/matplotlib/pyplot.py branches/transforms/lib/matplotlib/ticker.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-03 23:05:30 UTC (rev 3911) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-04 17:21:26 UTC (rev 3912) @@ -478,13 +478,12 @@ """ % {'scale': ' | '.join([repr(x) for x in mscale.get_scale_names()])} martist.Artist.__init__(self) self._position = mtransforms.Bbox.from_lbwh(*rect) - self._originalPosition = copy.deepcopy(self._position) + self._originalPosition = self._position.frozen() self.set_axes(self) self.set_aspect('auto') self.set_adjustable('box') self.set_anchor('C') - # MGDTODO: Check that the axes being shared are scalable self._sharex = sharex self._sharey = sharey if sharex is not None: @@ -540,69 +539,6 @@ self.yaxis = maxis.YAxis(self) self._update_transScale() - def sharex_foreign(self, axforeign): - """ - You can share your x-axis view limits with another Axes in the - same Figure by using the sharex and sharey property of the - Axes. But this doesn't work for Axes in a different figure. - This function sets of the callbacks so that when the xaxis of - this Axes or the Axes in a foreign figure are changed, both - will be synchronized. - - The connection ids for the self.callbacks and - axforeign.callbacks cbook.CallbackRegistry instances are - returned in case you want to disconnect the coupling - """ - - def follow_foreign_xlim(ax): - xmin, xmax = axforeign.get_xlim() - # do not emit here or we'll get a ping png effect - self.set_xlim(xmin, xmax, emit=False) - self.figure.canvas.draw_idle() - - def follow_self_xlim(ax): - xmin, xmax = self.get_xlim() - # do not emit here or we'll get a ping png effect - axforeign.set_xlim(xmin, xmax, emit=False) - axforeign.figure.canvas.draw_idle() - - - cidForeign = axforeign.callbacks.connect('xlim_changed', follow_foreign_xlim) - cidSelf = self.callbacks.connect('xlim_changed', follow_self_xlim) - return cidSelf, cidForeign - - - def sharey_foreign(self, axforeign): - """ - You can share your y-axis view limits with another Axes in the - same Figure by using the sharey and sharey property of the - Axes. But this doesn't work for Axes in a different figure. - This function sets of the callbacks so that when the yaxis of - this Axes or the Axes in a foreign figure are changed, both - will be synchronized. - - The connection ids for the self.callbacks and - axforeign.callbacks cbook.CallbackRegistry instances are - returned in case you want to disconnect the coupling - """ - - def follow_foreign_ylim(ax): - ymin, ymax = axforeign.get_ylim() - # do not emit here or we'll get a ping pong effect - self.set_ylim(ymin, ymax, emit=False) - self.figure.canvas.draw_idle() - - def follow_self_ylim(ax): - ymin, ymax = self.get_ylim() - # do not emit here or we'll get a ping pong effect - axforeign.set_ylim(ymin, ymax, emit=False) - axforeign.figure.canvas.draw_idle() - - - cidForeign = axforeign.callbacks.connect('ylim_changed', follow_foreign_ylim) - cidSelf = self.callbacks.connect('ylim_changed', follow_self_ylim) - return cidSelf, cidForeign - def set_figure(self, fig): """ Set the Axes figure @@ -629,10 +565,6 @@ # It is assumed that this part will have non-linear components self.transScale = mtransforms.TransformWrapper(mtransforms.IdentityTransform()) - self._set_transData() - - # MGDTODO: Rename this method - def _set_transData(self): # A (possibly non-linear) projection on the (already scaled) data self.transProjection = mtransforms.IdentityTransform() @@ -648,34 +580,38 @@ self._yaxis_transform = mtransforms.blended_transform_factory( self.axes.transAxes, self.axes.transData) + self.transData.write_graphviz(open("trans.dot", "w")) + def get_xaxis_transform(self): return self._xaxis_transform def get_xaxis_text1_transform(self, pad_pixels): return (self._xaxis_transform + - mtransforms.Affine2D().translate(0, -1 * pad_pixels)) + mtransforms.Affine2D().translate(0, -1 * pad_pixels), + "top", "center") def get_xaxis_text2_transform(self, pad_pixels): return (self._xaxis_transform + - mtransforms.Affine2D().translate(0, pad_pixels)) + mtransforms.Affine2D().translate(0, pad_pixels), + "top", "center") def get_yaxis_transform(self): return self._yaxis_transform def get_yaxis_text1_transform(self, pad_pixels): return (self._yaxis_transform + - mtransforms.Affine2D().translate(-1 * pad_pixels, 0)) + mtransforms.Affine2D().translate(-1 * pad_pixels, 0), + "center", "right") def get_yaxis_text2_transform(self, pad_pixels): return (self._yaxis_transform + - mtransforms.Affine2D().translate(pad_pixels, 0)) + mtransforms.Affine2D().translate(pad_pixels, 0), + "center", "right") def _update_transScale(self): self.transScale.set( mtransforms.blended_transform_factory( self.xaxis.get_transform(), self.yaxis.get_transform())) - - self.transData.make_graphviz(open("trans.dot", "w")) def get_position(self, original=False): 'Return the axes rectangle left, bottom, width, height' @@ -1164,7 +1100,8 @@ # limits and set the bound to be the bounds of the xydata. # Otherwise, it will compute the bounds of it's current data # and the data in xydata - xys = npy.asarray(xys) + if not ma.isMaskedArray(xys): + xys = npy.asarray(xys) self.update_datalim_numerix(xys[:, 0], xys[:, 1]) def update_datalim_numerix(self, x, y): @@ -1535,7 +1472,9 @@ for other in self._shared_x_axes.get_siblings(self): if other is not self: other.set_xlim(self.viewLim.intervalx, emit=False) - + + self.figure.canvas.draw_idle() + return xmin, xmax def get_xscale(self): @@ -1641,7 +1580,9 @@ for other in self._shared_y_axes.get_siblings(self): if other is not self: other.set_ylim(self.viewLim.ymin, self.viewLim.ymax, emit=False) - + + self.figure.canvas.draw_idle() + return ymin, ymax def get_yscale(self): @@ -1795,8 +1736,19 @@ """ self._navigate_mode = b - def drag_pan(self, button, key, startx, starty, dx, dy, - start_lim, start_trans): + def start_pan(self, x, y, button): + self._pan_start = cbook.Bunch( + lim = self.viewLim.frozen(), + trans = self.transData.frozen(), + trans_inverse = self.transData.inverted().frozen(), + x = x, + y = y + ) + + def end_pan(self): + del self._pan_start + + def drag_pan(self, button, key, x, y): def format_deltas(key, dx, dy): if key=='control': if(abs(dx)>abs(dy)): @@ -1818,22 +1770,24 @@ dx=dx/abs(dx)*abs(dy) return (dx,dy) + p = self._pan_start + dx = x - p.x + dy = y - p.y if button == 1: - inverse = start_trans.inverted() dx, dy = format_deltas(key, dx, dy) - result = self.bbox.frozen().translated(-dx, -dy).transformed(inverse) + result = self.bbox.frozen().translated(-dx, -dy) \ + .transformed(p.trans_inverse) elif button == 3: try: # MGDTODO: This is broken with log scales - inverse = start_trans.inverted() dx, dy = format_deltas(key, dx, dy) dx = -dx / float(self.bbox.width) dy = -dy / float(self.bbox.height) - xmin, ymin, xmax, ymax = start_lim.lbrt + xmin, ymin, xmax, ymax = p.lim.lbrt alpha = npy.power(10.0, (dx, dy)) - start = inverse.transform_point((startx, starty)) - lim_points = start_lim.get_points() + start = p.trans_inverse.transform_point((p.x, p.y)) + lim_points = p.lim.get_points() result = start + alpha * (lim_points - start) result = mtransforms.Bbox(result) except OverflowError: @@ -5214,485 +5168,16 @@ label.set_visible(firstcol) def subplot_class_factory(axes_class=None): - # MGDTODO: This is a little bit strange to make a new class on the - # fly like this, but it keeps things relatively similar to how they - # were before + # This makes a new class that inherits from SubclassBase and the + # given axes_class (which is assumed to be a subclass of Axes). + + # This is perhaps a little bit roundabout to make a new class on + # the fly like this, but it means that a new Subplot class does + # not have to be created for every type of Axes. new_class = new.classobj("%sSubplot" % (axes_class.__name__), (SubplotBase, axes_class), {'_axes_class': axes_class}) return new_class - - -class PolarAxes(Axes): - """ - Make a PolarAxes. The rectangular bounding box of the axes is given by - - - PolarAxes(position=[left, bottom, width, height]) - - where all the arguments are fractions in [0,1] which specify the - fraction of the total figure window. - - axisbg is the color of the axis background - - Attributes: - thetagridlines : a list of Line2D for the theta grids - rgridlines : a list of Line2D for the radial grids - thetagridlabels : a list of Text for the theta grid labels - rgridlabels : a list of Text for the theta grid labels - - """ - - RESOLUTION = 100 - - def __init__(self, *args, **kwarg): - """ - See Axes base class for args and kwargs documentation - """ - Axes.__init__(self, *args, **kwarg) - self.set_aspect('equal', adjustable='box', anchor='C') - self.cla() - def _init_axis(self): - "nuthin to do" - self.xaxis = None - self.yaxis = None - - - def _set_lim_and_transforms(self): - """ - set the dataLim and viewLim BBox attributes and the - transData and transAxes Transformation attributes - """ - - # the lim are theta, r - - # MGDTODO -# Bbox = mtrans.Bbox -# Value = mtrans.Value -# Point = mtrans.Point -# self.dataLim = Bbox( Point( Value(5/4.*math.pi), Value(math.sqrt(2))), -# Point( Value(1/4.*math.pi), Value(math.sqrt(2)))) -# self.viewLim = Bbox( Point( Value(5/4.*math.pi), Value(math.sqrt(2))), -# Point( Value(1/4.*math.pi), Value(math.sqrt(2)))) - -# self.transData = mtrans.NonseparableTransformation( -# self.viewLim, self.bbox, -# mtrans.FuncXY(mtrans.POLAR)) -# self.transAxes = mtrans.get_bbox_transform( -# mtrans.unit_bbox(), self.bbox) - pass - - def contains(self,mouseevent): - """Test whether the mouse event occured in the axes. - - Returns T/F, {} - """ - if callable(self._contains): return self._contains(self,mouseevent) - - x,y = self.axes.transAxes.inverse_xy_tup((mouseevent.x,mouseevent.y)) - #print "Polar: x,y = ",x,y - inside = (x-0.5)**2 + (y-0.5)**2 <= 0.25 - return inside,{} - - def cla(self): - 'Clear the current axes' - - # init these w/ some arbitrary numbers - they'll be updated as - # data is added to the axes - - self._get_lines = _process_plot_var_args(self) - self._get_patches_for_fill = _process_plot_var_args(self, 'fill') - - self._gridOn = rcParams['polaraxes.grid'] - self.thetagridlabels = [] - self.thetagridlines = [] - self.rgridlabels = [] - self.rgridlines = [] - - self.lines = [] - self.images = [] - self.patches = [] - self.artists = [] - self.collections = [] - self.texts = [] # text in axis coords - self.legend_ = None - - self.grid(self._gridOn) - props = font_manager.FontProperties(size=rcParams['axes.titlesize']) - self.title = mtext.Text( - x=0.5, y=1.05, text='', - fontproperties=props, - verticalalignment='bottom', - horizontalalignment='center', - ) - self.title.set_transform(self.transAxes) - - self._set_artist_props(self.title) - - - self.thetas = npy.linspace(0, 2*math.pi, self.RESOLUTION) - - verts = zip(self.thetas, npy.ones(self.RESOLUTION)) - self.axesPatch = mpatches.Polygon( - verts, - facecolor=self._axisbg, - edgecolor=rcParams['axes.edgecolor'], - ) - - - - self.axesPatch.set_figure(self.figure) - self.axesPatch.set_transform(self.transData) - self.axesPatch.set_linewidth(rcParams['axes.linewidth']) - self.axison = True - - # we need to set a view and data interval from 0->rmax to make - # the formatter and locator work correctly - # MGDTODO - Value = mtrans.Value - Interval = mtrans.Interval - self.rintv = Interval(Value(0), Value(1)) - self.rintd = Interval(Value(0), Value(1)) - - self.rformatter = mticker.ScalarFormatter() - self.rformatter.set_view_interval(self.rintv) - self.rformatter.set_data_interval(self.rintd) - - class RadialLocator(mticker.AutoLocator): - 'enforce strictly positive radial ticks' - - def __call__(self): - ticks = mticker.AutoLocator.__call__(self) - return [t for t in ticks if t>0] - - self.rlocator = RadialLocator() - self.rlocator.set_view_interval(self.rintv) - self.rlocator.set_data_interval(self.rintd) - - - angles = npy.arange(0, 360, 45) - radii = npy.arange(0.2, 1.1, 0.2) - self.set_thetagrids(angles) - self.set_rgrids(radii) - - def get_children(self): - 'return a list of child artists' - children = [] - children.extend(self.rgridlines) - children.extend(self.rgridlabels) - children.extend(self.thetagridlines) - children.extend(self.thetagridlabels) - children.extend(self.lines) - children.extend(self.patches) - children.extend(self.texts) - children.extend(self.artists) - children.extend(self.images) - if self.legend_ is not None: - children.append(self.legend_) - children.extend(self.collections) - children.append(self.title) - children.append(self.axesPatch) - return children - - - def set_rmax(self, rmax): - self.rintv.set_bounds(0, rmax) - self.regrid(rmax) - - def grid(self, b): - 'Set the axes grids on or off; b is a boolean' - self._gridOn = b - - def regrid(self, rmax): - rmax = float(rmax) - self.axesPatch.xy = zip(self.thetas, rmax*npy.ones(self.RESOLUTION)) - - val = rmax*math.sqrt(2) - self.viewLim.intervaly().set_bounds(val, val) - - ticks = self.rlocator() - self.set_rgrids(ticks) - self.rformatter.set_locs(ticks) - - for t in self.thetagridlabels: - t.set_y(1.05*rmax) - - r = npy.linspace(0, rmax, self.RESOLUTION) - for l in self.thetagridlines: - l.set_ydata(r) - - def autoscale_view(self, scalex=True, scaley=True): - 'set the view limits to include all the data in the axes' - self.rintd.set_bounds(0, self.get_rmax()) - rmin, rmax = self.rlocator.autoscale() - self.rintv.set_bounds(rmin, rmax) - self.regrid(rmax) - - def set_rgrids(self, radii, labels=None, angle=22.5, rpad=0.05, **kwargs): - """ - set the radial locations and labels of the r grids - - The labels will appear at radial distances radii at angle - - labels, if not None, is a len(radii) list of strings of the - labels to use at each angle. - - if labels is None, the self.rformatter will be used - - rpad is a fraction of the max of radii which will pad each of - the radial labels in the radial direction. - - Return value is a list of lines, labels where the lines are - lines.Line2D instances and the labels are text.Text - instances - - kwargs control the rgrid Text label properties: - %(Text)s - - ACCEPTS: sequence of floats - """ - - - radii = npy.asarray(radii) - rmin = radii.min() - if rmin<=0: - raise ValueError('radial grids must be strictly positive') - - rpad = rpad * max(radii) - cbook.popall(self.rgridlines) - - theta = npy.linspace(0., 2*math.pi, self.RESOLUTION) - ls = rcParams['grid.linestyle'] - color = rcParams['grid.color'] - lw = rcParams['grid.linewidth'] - - rmax = self.get_rmax() - for r in radii: - r = npy.ones(self.RESOLUTION)*r - line = mlines.Line2D(theta, r, linestyle=ls, color=color, linewidth=lw, - figure=self.figure) - line.set_transform(self.transData) - self.rgridlines.append(line) - - cbook.popall(self.rgridlabels) - - - color = rcParams['xtick.color'] - - - props = font_manager.FontProperties(size=rcParams['xtick.labelsize']) - if labels is None: - labels = [self.rformatter(r,0) for r in radii] - for r,l in zip(radii, labels): - t = mtext.Text(angle/180.*math.pi, r+rpad, l, - fontproperties=props, color=color, - horizontalalignment='center', verticalalignment='center') - t.set_transform(self.transData) - t.update(kwargs) - self._set_artist_props(t) - t.set_clip_on(False) - self.rgridlabels.append(t) - - return self.rgridlines, self.rgridlabels - set_rgrids.__doc__ = cbook.dedent(set_rgrids.__doc__) % martist.kwdocd - - def set_thetagrids(self, angles, labels=None, fmt='%d', frac = 1.1, - **kwargs): - """ - set the angles at which to place the theta grids (these - gridlines are equal along the theta dimension). angles is in - degrees - - labels, if not None, is a len(angles) list of strings of the - labels to use at each angle. - - if labels is None, the labels with be fmt%%angle - - frac is the fraction of the polar axes radius at which to - place the label (1 is the edge).Eg 1.05 isd outside the axes - and 0.95 is inside the axes - - Return value is a list of lines, labels where the lines are - lines.Line2D instances and the labels are Text - instances: - - kwargs are optional text properties for the labels - %(Text)s - ACCEPTS: sequence of floats - """ - cbook.popall(self.thetagridlines) - ox, oy = 0,0 - ls = rcParams['grid.linestyle'] - color = rcParams['grid.color'] - lw = rcParams['grid.linewidth'] - - rmax = self.get_rmax() - r = npy.linspace(0., rmax, self.RESOLUTION) - for a in angles: - theta = npy.ones(self.RESOLUTION)*a/180.*math.pi - line = mlines.Line2D( - theta, r, linestyle=ls, color=color, linewidth=lw, - figure=self.figure) - line.set_transform(self.transData) - self.thetagridlines.append(line) - - cbook.popall(self.thetagridlabels) - - color = rcParams['xtick.color'] - - props = font_manager.FontProperties(size=rcParams['xtick.labelsize']) - r = frac*rmax - if labels is None: - labels = [fmt%a for a in angles] - for a,l in zip(angles, labels): - t = mtext.Text(a/180.*math.pi, r, l, fontproperties=props, color=color, - horizontalalignment='center', verticalalignment='center') - t.set_transform(self.transData) - t.update(kwargs) - self._set_artist_props(t) - t.set_clip_on(False) - self.thetagridlabels.append(t) - return self.thetagridlines, self.thetagridlabels - set_thetagrids.__doc__ = cbook.dedent(set_thetagrids.__doc__) % martist.kwdocd - - def get_rmax(self): - 'get the maximum radius in the view limits dimension' - vmin, vmax = self.dataLim.intervaly().get_bounds() - return max(vmin, vmax) - - def draw(self, renderer): - if not self.get_visible(): return - renderer.open_group('polar_axes') - self.apply_aspect(1) - self.transData.freeze() # eval the lazy objects - self.transAxes.freeze() # eval the lazy objects - - verts = self.axesPatch.get_verts() - tverts = self.transData.seq_xy_tups(verts) - - #for i,v,t in zip(range(len(verts)), verts, tverts): - # print i,v,t - - - - l,b,w,h = self.figure.bbox.get_bounds() - clippath = agg.path_storage() - for i, xy in enumerate(tverts): - x,y = xy - y = h-y - if i==0: clippath.move_to(x, y) - else: clippath.line_to(x, y) - clippath.close_polygon() - - #self._update_axes() - if self.axison: - if self._frameon: self.axesPatch.draw(renderer) - - if self._gridOn: - for l in self.rgridlines: - l.set_clip_path(clippath) - l.draw(renderer) - - for l in self.thetagridlines: - l.set_clip_path(clippath) - l.draw(renderer) - - for a in self.lines:# + self.patches: - a.set_clip_path(clippath) - - artists = [] - artists.extend(self.lines) - artists.extend(self.texts) - artists.extend(self.collections) - artists.extend(self.patches) - artists.extend(self.artists) - - dsu = [ (a.zorder, a) for a in artists] - dsu.sort() - - for zorder, a in dsu: - a.draw(renderer) - - - for t in self.thetagridlabels+self.rgridlabels: - t.draw(renderer) - - if self.legend_ is not None: - self.legend_.draw(renderer) - - self.title.draw(renderer) - - - - self.transData.thaw() # release the lazy objects - self.transAxes.thaw() # release the lazy objects - renderer.close_group('polar_axes') - - - def format_coord(self, theta, r): - 'return a format string formatting the coordinate' - theta /= math.pi - return 'theta=%1.2fpi, r=%1.3f'%(theta, r) - - - def has_data(self): - 'return true if any artists have been added to axes' - return len(self.lines)+len(self.collections) - - def set_xlabel(self, xlabel, fontdict=None, **kwargs): - 'xlabel not implemented' - raise NotImplementedError('xlabel not defined for polar axes (yet)') - - def set_ylabel(self, ylabel, fontdict=None, **kwargs): - 'ylabel not implemented' - raise NotImplementedError('ylabel not defined for polar axes (yet)') - - def set_xlim(self, xmin=None, xmax=None, emit=True, **kwargs): - 'xlim not implemented' - raise NotImplementedError('xlim not meaningful for polar axes') - - def set_ylim(self, ymin=None, ymax=None, emit=True, **kwargs): - 'ylim not implemented' - raise NotImplementedError('ylim not meaningful for polar axes') - - def get_xscale(self): - 'return the xaxis scale string' - return 'polar' - - def get_yscale(self): - 'return the yaxis scale string' - return 'polar' - - def table(self, *args, **kwargs): - """ - TABLE(*args, **kwargs) - Not implemented for polar axes - """ - raise NotImplementedError('table not implemented for polar axes') - - - -class PolarSubplot(SubplotBase, PolarAxes): - """ - Create a polar subplot with - - PolarSubplot(numRows, numCols, plotNum) - - where plotNum=1 is the first plot number and increasing plotNums - fill rows first. max(plotNum)==numRows*numCols - - You can leave out the commas if numRows<=numCols<=plotNum<10, as - in - - Subplot(211) # 2 rows, 1 column, first (upper) plot - """ - def __str__(self): - return "PolarSubplot(%gx%g)"%(self.figW,self.figH) - def __init__(self, fig, *args, **kwargs): - SubplotBase.__init__(self, fig, *args) - PolarAxes.__init__( - self, fig, - [self.figLeft, self.figBottom, self.figW, self.figH], **kwargs) martist.kwdocd['Axes'] = martist.kwdocd['Subplot'] = martist.kwdoc(Axes) Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-10-03 23:05:30 UTC (rev 3911) +++ branches/transforms/lib/matplotlib/axis.py 2007-10-04 17:21:26 UTC (rev 3912) @@ -166,7 +166,7 @@ def draw(self, renderer): if not self.get_visible(): return renderer.open_group(self.__name__) - midPoint = interval_contains_open(self.get_view_interval(), self.get_loc() ) + midPoint = interval_contains(self.get_view_interval(), self.get_loc()) if midPoint: if self.gridOn: @@ -176,8 +176,10 @@ if self.tick2On: self.tick2line.draw(renderer) - if self.label1On: self.label1.draw(renderer) - if self.label2On: self.label2.draw(renderer) + if self.label1On: + self.label1.draw(renderer) + if self.label2On: + self.label2.draw(renderer) renderer.close_group(self.__name__) @@ -237,17 +239,19 @@ # get the affine as an a,b,c,d,tx,ty list # x in data coords, y in axes coords #t = Text( + trans, vert, horiz = self.axes.get_xaxis_text1_transform(self._padPixels) + t = TextWithDash( x=loc, y=0, fontproperties=FontProperties(size=rcParams['xtick.labelsize']), color=rcParams['xtick.color'], - verticalalignment='top', - horizontalalignment='center', + verticalalignment=vert, + horizontalalignment=horiz, dashdirection=0, xaxis=True, ) - t.set_transform(self.axes.get_xaxis_text1_transform(self._padPixels)) + t.set_transform(trans) self._set_artist_props(t) return t @@ -257,17 +261,19 @@ 'Get the default Text 2 instance' # x in data coords, y in axes coords #t = Text( + trans, vert, horiz = self.axes.get_xaxis_text2_transform(self._padPixels) + t = TextWithDash( x=loc, y=1, fontproperties=FontProperties(size=rcParams['xtick.labelsize']), color=rcParams['xtick.color'], - verticalalignment='bottom', + verticalalignment=vert, dashdirection=1, xaxis=True, - horizontalalignment='center', + horizontalalignment=horiz, ) - t.set_transform(self.axes.get_xaxis_text2_transform(self._padPixels)) + t.set_transform(trans) self._set_artist_props(t) return t @@ -277,7 +283,6 @@ l = Line2D( xdata=(loc,), ydata=(0,), color='k', linestyle = 'None', - antialiased=False, marker = self._xtickmarkers[0], markersize=self._size, ) @@ -291,7 +296,6 @@ l = Line2D( xdata=(loc,), ydata=(1,), color='k', linestyle = 'None', - antialiased=False, marker = self._xtickmarkers[1], markersize=self._size, ) @@ -307,7 +311,6 @@ color=rcParams['grid.color'], linestyle=rcParams['grid.linestyle'], linewidth=rcParams['grid.linewidth'], - antialiased=False, ) l.set_transform(self.axes.get_xaxis_transform()) self._set_artist_props(l) @@ -356,16 +359,18 @@ 'Get the default Text instance' # x in axes coords, y in data coords #t = Text( - t = TextWithDash( + trans, vert, horiz = self.axes.get_yaxis_text1_transform(self._padPixels) + + t = TextWithDash( x=0, y=loc, fontproperties=FontProperties(size=rcParams['ytick.labelsize']), color=rcParams['ytick.color'], - verticalalignment='center', - horizontalalignment='right', + verticalalignment=vert, + horizontalalignment=horiz, dashdirection=0, xaxis=False, ) - t.set_transform(self.axes.get_yaxis_text1_transform(self._padPixels)) + t.set_transform(trans) #t.set_transform( self.axes.transData ) self._set_artist_props(t) return t @@ -374,16 +379,18 @@ 'Get the default Text instance' # x in axes coords, y in data coords #t = Text( + trans, vert, horiz = self.axes.get_yaxis_text2_transform(self._padPixels) + t = TextWithDash( x=1, y=loc, fontproperties=FontProperties(size=rcParams['ytick.labelsize']), color=rcParams['ytick.color'], - verticalalignment='center', + verticalalignment=vert, dashdirection=1, xaxis=False, - horizontalalignment='left', + horizontalalignment=horiz, ) - t.set_transform(self.axes.get_yaxis_text2_transform(self._padPixels)) + t.set_transform(trans) self._set_artist_props(t) return t @@ -392,7 +399,6 @@ # x in axes coords, y in data coords l = Line2D( (0,), (loc,), color='k', - antialiased=False, marker = self._ytickmarkers[0], linestyle = 'None', markersize=self._size, @@ -405,7 +411,6 @@ 'Get the default line2D instance' # x in axes coords, y in data coords l = Line2D( (1,), (0,), color='k', - antialiased=False, marker = self._ytickmarkers[1], linestyle = 'None', markersize=self._size, @@ -422,7 +427,6 @@ color=rcParams['grid.color'], linestyle=rcParams['grid.linestyle'], linewidth=rcParams['grid.linewidth'], - antialiased=False, ) l.set_transform(self.axes.get_yaxis_transform()) @@ -523,8 +527,8 @@ def get_children(self): children = [self.label] - majorticks = self.get_major_ticks(len(self.major.locator())) - minorticks = self.get_minor_ticks(len(self.minor.locator())) + majorticks = self.get_major_ticks() + minorticks = self.get_minor_ticks() children.extend(majorticks) children.extend(minorticks) @@ -560,8 +564,8 @@ def set_clip_path(self, clippath, transform=None): Artist.set_clip_path(self, clippath, transform) - majorticks = self.get_major_ticks(len(self.major.locator())) - minorticks = self.get_minor_ticks(len(self.minor.locator())) + majorticks = self.get_major_ticks() + minorticks = self.get_minor_ticks() for child in self.majorTicks + self.minorTicks: child.set_clip_path(clippath, transform) @@ -729,9 +733,11 @@ 'Get the formatter of the minor ticker' return self.minor.formatter - def get_major_ticks(self, numticks): + def get_major_ticks(self, numticks=None): 'get the tick instances; grow as necessary' - + if numticks is None: + numticks = len(self.get_major_locator()()) + if len(self.majorTicks)<numticks: # update the new tick label properties from the old protoTick = self.majorTicks[0] @@ -746,8 +752,11 @@ return ticks - def get_minor_ticks(self, numticks): + def get_minor_ticks(self, numticks=None): 'get the minor tick instances; grow as necessary' + if numticks is None: + numticks = len(self.get_minor_locator()()) + if len(self.minorTicks)<numticks: protoTick = self.minorTicks[0] for i in range(numticks-len(self.minorTicks)): Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-10-03 23:05:30 UTC (rev 3911) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-10-04 17:21:26 UTC (rev 3912) @@ -34,40 +34,22 @@ def draw_path(self, gc, path, transform, rgbFace=None): """ - Handles the caching of the native path associated with the - given path and calls the underlying backend's _draw_path to - actually do the drawing. + Draws a Path instance using the given affine transform. """ - # MGDTODO: Update docstring raise NotImplementedError def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): """ - This method is currently underscore hidden because the - draw_markers method is being used as a sentinel for newstyle - backend drawing + Draws a marker at each of the vertices in path. This includes + all vertices, including control points on curves. To avoid + that behavior, those vertices should be removed before calling + this function. - path - a matplotlib.agg.path_storage instance - - Draw the marker specified in path with graphics context gc at - each of the locations in arrays x and y. trans is a - matplotlib.transforms.Transformation instance used to - transform x and y to display coords. It consists of an - optional nonlinear component and an affine. You can access - these two components as - - if transform.need_nonlinear(): - x,y = transform.nonlinear_only_numerix(x, y) - # the a,b,c,d,tx,ty affine which transforms x and y - vec6 = transform.as_vec6_val() - ...backend dependent affine... + marker_trans is an affine transform applied to the marker. + trans is an affine transform applied to the path. """ - # MGDTODO: Update docstring raise NotImplementedError - def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None): - raise NotImplementedError - def get_image_magnification(self): """ Get the factor by which to magnify images passed to draw_image. @@ -1560,7 +1542,8 @@ self._xypress=[] for i, a in enumerate(self.canvas.figure.get_axes()): if x is not None and y is not None and a.in_axes(event) and a.get_navigate(): - self._xypress.append((x, y, a, i, a.viewLim.frozen(), a.transData.frozen())) + a.start_pan(x, y, event.button) + self._xypress.append((a, i)) self.canvas.mpl_disconnect(self._idDrag) self._idDrag=self.canvas.mpl_connect('motion_notify_event', self.drag_pan) @@ -1597,14 +1580,12 @@ lims.append( (xmin, xmax, ymin, ymax) ) # Store both the original and modified positions pos.append( ( - copy.copy(a.get_position(True)), - copy.copy(a.get_position() )) ) + a.get_position(True).frozen(), + a.get_position().frozen() ) ) self._views.push(lims) self._positions.push(pos) self.set_history_buttons() - - def release(self, event): 'this will be called whenever mouse button is released' pass @@ -1613,6 +1594,8 @@ 'the release mouse button callback in pan/zoom mode' self.canvas.mpl_disconnect(self._idDrag) self._idDrag=self.canvas.mpl_connect('motion_notify_event', self.mouse_move) + for a, ind in self._xypress: + a.end_pan() if not self._xypress: return self._xypress = None self._button_pressed=None @@ -1623,12 +1606,10 @@ def drag_pan(self, event): 'the drag callback in pan/zoom mode' - for lastx, lasty, a, ind, old_lim, old_trans in self._xypress: + for a, ind in self._xypress: #safer to use the recorded button at the press than current button: #multiple button can get pressed during motion... - dx, dy = event.x - lastx, event.y - lasty - a.drag_pan(self._button_pressed, event.key, lastx, lasty, dx, dy, - old_lim, old_trans) + a.drag_pan(self._button_pressed, event.key, event.x, event.y) self.dynamic_update() def release_zoom(self, event): Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-10-03 23:05:30 UTC (rev 3911) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-10-04 17:21:26 UTC (rev 3912) @@ -96,15 +96,6 @@ The renderer handles all the drawing primitives using a graphics context instance that controls the colors/styles """ - # MGDTODO: Renderers seem to get created and destroyed fairly - # often so the paths are cached at the class (not instance) level. - # However, this dictionary is only directly used by RendererBase, - # so it seems funny to define it here. However, if we didn't, the - # native paths would be shared across renderers, which is - # obviously bad. Seems like a good use of metaclasses, but that - # also seems like a heavy solution for a minor problem. - _native_paths = weakref.WeakKeyDictionary() - debug=1 texd = {} # a cache of tex image rasters def __init__(self, width, height, dpi): @@ -130,12 +121,10 @@ if __debug__: verbose.report('RendererAgg.__init__ done', 'debug-annoying') - # MGDTODO: Just adding helpful asserts. This can be removed in the future def draw_path(self, gc, path, trans, rgbFace=None): assert trans.is_affine self._renderer.draw_path(gc, path, trans.frozen(), rgbFace) - # MGDTODO: Just adding helpful asserts. This can be removed in the future def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): assert marker_trans.is_affine assert trans.is_affine Modified: branches/transforms/lib/matplotlib/legend.py =================================================================== --- branches/transforms/lib/matplotlib/legend.py 2007-10-03 23:05:30 UTC (rev 3911) +++ branches/transforms/lib/matplotlib/legend.py 2007-10-04 17:21:26 UTC (rev 3912) @@ -256,10 +256,10 @@ bboxesText = [t.get_window_extent(renderer) for t in self.texts] bboxesHandles = [h.get_window_extent(renderer) for h in self.legendHandles if h is not None] - bboxesAll = bboxesText bboxesAll.extend(bboxesHandles) bbox = Bbox.union(bboxesAll) + self.save = bbox ibox = bbox.inverse_transformed(self.get_transform()) @@ -558,7 +558,7 @@ handle.set_height(h/2) # Set the data for the legend patch - bbox = copy.copy(self._get_handle_text_bbox(renderer)) + bbox = self._get_handle_text_bbox(renderer).frozen() bbox = bbox.expanded(1 + self.pad, 1 + self.pad) l, b, w, h = bbox.bounds Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-10-03 23:05:30 UTC (rev 3911) +++ branches/transforms/lib/matplotlib/lines.py 2007-10-04 17:21:26 UTC (rev 3912) @@ -393,7 +393,6 @@ def recache(self): #if self.axes is None: print 'recache no axes' #else: print 'recache units', self.axes.xaxis.units, self.axes.yaxis.units - # MGDTODO: Deal with units x = ma.asarray(self.convert_xunits(self._xorig), float) y = ma.asarray(self.convert_yunits(self._yorig), float) @@ -414,12 +413,12 @@ self._x = self._xy[:, 0] # just a view self._y = self._xy[:, 1] # just a view self._logcache = None + # Masked arrays are now handled by the Path class itself self._path = Path(self._xy, closed=False) self._transformed_path = TransformedPath(self._path, self.get_transform()) - # MGDTODO: If _draw_steps is removed, remove the following line also - self._step_path = None + def set_transform(self, t): """ set the Transformation instance used by this artist @@ -434,47 +433,8 @@ if len(x)<2: return 1 return npy.alltrue(x[1:]-x[0:-1]>=0) - # MGDTODO: Remove me (seems to be used for old-style interface only) - def _get_plottable(self): - # If log scale is set, only pos data will be returned - - x, y = self._x, self._y - - # MGDTODO: (log-scaling) - -# try: logx = self.get_transform().get_funcx().get_type()==LOG10 -# except RuntimeError: logx = False # non-separable - -# try: logy = self.get_transform().get_funcy().get_type()==LOG10 -# except RuntimeError: logy = False # non-separable - - if True: - return x, y - - if self._logcache is not None: - waslogx, waslogy, xcache, ycache = self._logcache - if logx==waslogx and waslogy==logy: - return xcache, ycache - - Nx = len(x) - Ny = len(y) - - if logx: indx = npy.greater(x, 0) - else: indx = npy.ones(len(x)) - - if logy: indy = npy.greater(y, 0) - else: indy = npy.ones(len(y)) - - ind, = npy.nonzero(npy.logical_and(indx, indy)) - x = npy.take(x, ind) - y = npy.take(y, ind) - - self._logcache = logx, logy, x, y - return x, y - - def draw(self, renderer): - #renderer.open_group('line2d') + renderer.open_group('line2d') if not self._visible: return self._newstyle = hasattr(renderer, 'draw_markers') @@ -498,7 +458,6 @@ lineFunc = getattr(self, funcname) lineFunc(renderer, gc, *self._transformed_path.get_transformed_path_and_affine()) - # MGDTODO: Deal with markers if self._marker is not None: gc = renderer.new_gc() self._set_gc_clip(gc) @@ -509,7 +468,7 @@ markerFunc = getattr(self, funcname) markerFunc(renderer, gc, *self._transformed_path.get_transformed_path_and_affine()) - #renderer.close_group('line2d') + renderer.close_group('line2d') def get_antialiased(self): return self._antialiased def get_color(self): return self._color @@ -694,29 +653,7 @@ def _draw_nothing(self, *args, **kwargs): pass - - def _draw_steps(self, renderer, gc, path): - # We generate the step function path on-the-fly, and then cache it. - # The cache may be later invalidated when the data changes - # (in self.recache()) - - # MGDTODO: Untested -- using pylab.step doesn't actually trigger - # this code -- the path is "stepped" before even getting to this - # class. Perhaps this should be removed here, since it is not as - # powerful as what is in axes.step() anyway. - if self._step_path is None: - vertices = self._path.vertices - codes = self._path.codes - siz = len(vertices) - if siz<2: return - new_vertices = npy.zeros((2*siz, 2), vertices.dtype) - new_vertices[0:-1:2, 0], new_vertices[1:-1:2, 0], newvertices[-1, 0] = vertices[:, 0], vertices[1:, 0], vertices[-1, 0] - new_vertices[0:-1:2, 1], new_vertices[1::2, 1] = vertices[:, 1], vertices[:, 1] - self._step_path = Path(new_vertices, closed=False) - gc.set_linestyle('solid') - renderer.draw_path(gc, self._step_path, self.get_transform()) - - + def _draw_solid(self, renderer, gc, path, trans): gc.set_linestyle('solid') renderer.draw_path(gc, path, trans) Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-10-03 23:05:30 UTC (rev 3911) +++ branches/transforms/lib/matplotlib/patches.py 2007-10-04 17:21:26 UTC (rev 3912) @@ -12,8 +12,6 @@ import matplotlib.mlab as mlab import matplotlib.artist as artist from matplotlib.path import Path -# MGDTODO: Maybe this belongs elsewhere -from matplotlib.backends._backend_agg import point_in_path # these are not available for the object inspector until after the # class is build so we define an initial set here for the init @@ -93,8 +91,8 @@ # method. if callable(self._contains): return self._contains(self,mouseevent) - inside = point_in_path(mouseevent.x, mouseevent.y, self.get_path(), - self.get_transform().frozen()) + inside = self.get_path().contains_point( + (mouseevent.x, mouseevent.y), self.get_transform()) return inside, {} def update_from(self, other): @@ -236,8 +234,8 @@ def get_window_extent(self, renderer=None): - trans_path = self.get_path().transformed(self.get_path_transform()) - return Bbox.unit().update_from_data(trans_path.vertices) + return Bbox.from_lbrt( + get_path_extents(self.get_path(), self.get_patch_transform())) def set_lw(self, val): @@ -341,7 +339,9 @@ Patch.__init__(self, **kwargs) - self._bbox = transforms.Bbox.from_lbwh(xy[0], xy[1], width, height) + left, right = self.convert_xunits((xy[0], xy[0] + width)) + bottom, top = self.convert_yunits((xy[1], xy[1] + height)) + self._bbox = transforms.Bbox.from_lbrt(left, bottom, right, top) self._rect_transform = transforms.BboxTransform( transforms.Bbox.unit(), self._bbox) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd @@ -352,10 +352,6 @@ """ return Path.unit_rectangle() - # MGDTODO: Convert units -# left, right = self.convert_xunits((x, x + self.width)) -# bottom, top = self.convert_yunits((y, y + self.height)) - def get_patch_transform(self): return self._rect_transform Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-10-03 23:05:30 UTC (rev 3911) +++ branches/transforms/lib/matplotlib/path.py 2007-10-04 17:21:26 UTC (rev 3912) @@ -1,3 +1,9 @@ +""" +Contains a class for managing paths (polylines). + +October 2007 Michael Droettboom +""" + import math import numpy as npy @@ -3,7 +9,47 @@ from numpy import ma as ma +from matplotlib.backends._backend_agg import point_in_path, get_path_extents +from matplotlib.cbook import simple_linear_interpolation + KAPPA = 4.0 * (npy.sqrt(2) - 1) / 3.0 class Path(object): + """ + Path represents a series of possibly disconnected, possibly + closed, line and curve segments. + + The underlying storage is made up of two parallel numpy arrays: + vertices: an Nx2 float array of vertices + codes: an N-length uint8 array of vertex types + + These two arrays always have the same length in the first + dimension. Therefore, to represent a cubic curve, you must + provide three vertices as well as three codes "CURVE3". + + The code types are: + + STOP : 1 vertex (ignored) + A marker for the end of the entire path (currently not + required and ignored) + + MOVETO : 1 vertex + Pick up the pen and move to the given vertex. + + LINETO : 1 vertex + Draw a line from the current position to the given vertex. + + CURVE3 : 1 control point, 1 endpoint + Draw a quadratic Bezier curve from the current position, + with the given control point, to the given end point. + + CURVE4 : 2 control points, 1 endpoint + Draw a cubic Bezier curve from the current position, with + the given control points, to the given end point. + + CLOSEPOLY : 1 vertex (ignored) + Draw a line segment to the start point of the current + polyline. + """ + # Path codes STOP = 0 # 1 vertex @@ -13,19 +59,31 @@ CURVE3 = 3 # 2 vertices CURVE4 = 4 # 3 vertices CLOSEPOLY = 5 # 1 vertex - ### - # MGDTODO: I'm not sure these are supported by PS/PDF/SVG, - # so if they don't, we probably shouldn't - CURVEN = 6 - CATROM = 7 - UBSPLINE = 8 - #### NUM_VERTICES = [1, 1, 1, 2, 3, 1] code_type = npy.uint8 def __init__(self, vertices, codes=None, closed=True): + """ + Create a new path with the given vertices and codes. + + vertices is an Nx2 numpy float array. + + codes is an N-length numpy array of type Path.code_type. + + See the docstring of Path for a description of the various + codes. + + These two arrays must have the same length in the first + dimension. + + If codes is None, vertices will be treated as a series of line + segments. Additionally, if closed is also True, the polyline + will closed. If vertices contains masked values, the + resulting path will be compressed, with MOVETO codes inserted + in the correct places to jump over the masked regions. + """ vertices = ma.asarray(vertices, npy.float_) if codes is None: @@ -82,6 +140,11 @@ vertices = property(_get_vertices) def iter_endpoints(self): + """ + Iterates over all of the endpoints in the path. Unlike + iterating directly over the vertices array, curve control + points are skipped over. + """ i = 0 NUM_VERTICES = self.NUM_VERTICES vertices = self.vertices @@ -95,11 +158,57 @@ i += 1 def transformed(self, transform): + """ + Return a transformed copy of the path. + + See transforms.TransformedPath for a path that will cache the + transformed result and automatically update when the transform + changes. + """ return Path(transform.transform(self.vertices), self.codes) - + + def contains_point(self, point, transform=None): + """ + Returns True if the path contains the given point. + + If transform is not None, the path will be transformed before + performing the test. + """ + if transform is None: + from transforms import IdentityTransform + transform = IdentityTransform + return point_in_path(point[0], point[1], self, transform.frozen()) + + def get_extents(self, transform=None): + """ + Returns the extents (xmin, ymin, xmax, ymax) of the path. + + Unlike computing the extents on the vertices alone, this + algorithm will take into account the curves and deal with + control points appropriately. + """ + from transforms import Bbox, IdentityTransform + if transform is None: + transform = IdentityTransform + return Bbox.from_lbrt(*get_path_extents(self, transform)) + + def interpolated(self, steps): + """ + Returns a new path resampled to length N x steps. + Does not currently handle interpolating curves. + """ + vertices = simple_linear_interpolation(self.vertices, steps) + codes = self.codes + new_codes = Path.LINETO * npy.ones(((len(codes) - 1) * steps + 1, )) + new_codes[0::steps] = codes + return Path(vertices, new_codes) + _unit_rectangle = None #@classmethod def unit_rectangle(cls): + """ + Returns a Path of the unit rectangle from (0, 0) to (1, 1). + """ if cls._unit_rectangle is None: cls._unit_rectangle = \ Path([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]) @@ -109,9 +218,14 @@ _unit_regular_polygons = {} #@classmethod def unit_regular_polygon(cls, numVertices): + """ + Returns a Path for a unit regular polygon with the given + numVertices and radius of 1.0, centered at (0, 0). + """ path = cls._unit_regular_polygons.get(numVertices) if path is None: - theta = 2*npy.pi/numVertices * npy.arange(numVertices).reshape((numVertices, 1)) + theta = (2*npy.pi/numVertices * + npy.arange(numVertices).reshape((numVertices, 1))) # This initial rotation is to make sure the polygon always # "points-up" theta += npy.pi / 2.0 @@ -124,6 +238,10 @@ _unit_circle = None #@classmethod def unit_circle(cls): + """ + Returns a Path of the unit circle. The circle is approximated + using cubic Bezier curves. + """ if cls._unit_circle is None: offset = KAPPA vertices = npy.array( @@ -158,6 +276,10 @@ #@classmethod def arc(cls, theta1, theta2, is_wedge=False): + """ + Returns an arc on the unit circle from angle theta1 to angle + theta2 (in degrees). + """ # From Masionobe, L. 2003. "Drawing an elliptical arc using # polylines, quadratic or cubic Bezier curves". # @@ -234,5 +356,9 @@ arc = classmethod(arc) def wedge(cls, theta1, theta2): + """ + Returns a wedge of the unit circle from angle theta1 to angle + theta2 (in degrees). + """ return cls.arc(theta1, theta2, True) wedge = classmethod(wedge) Modified: branches/transforms/lib/matplotlib/projections/polar.py =================================================================== --- branches/transforms/lib/matplotlib/projections/polar.py 2007-10-03 23:05:30 UTC (rev 3911) +++ branches/transforms/lib/matplotlib/projections/polar.py 2007-10-04 17:21:26 UTC (rev 3912) @@ -2,9 +2,12 @@ import numpy as npy +from matplotlib.artist import kwdocd from matplotlib.axes import Axes +from matplotlib import cbook from matplotlib.patches import Circle -from matplotlib.ticker import Locator +from matplotlib.path import Path +from matplotlib.ticker import Formatter, Locator from matplotlib.transforms import Affine2D, Affine2DBase, Bbox, BboxTransform, \ IdentityTransform, Transform, TransformWrapper @@ -16,6 +19,10 @@ output_dims = 2 is_separable = False + def __init__(self, resolution): + Transform.__init__(self) + self._resolution = resolution + def transform(self, tr): xy = npy.zeros(tr.shape, npy.float_) t = tr[:, 0:1] @@ -27,6 +34,12 @@ return xy transform_non_affine = transform + def transform_path(self, path): + if len(path.vertices) == 2: + path = path.interpolated(self._resolution) + return Path(self.transform(path.vertices), path.codes) + transform_path_non_affine = transform_path + def inverted(self): return PolarAxes.InvertedPolarTransform() @@ -64,10 +77,35 @@ def inverted(self): return PolarAxes.PolarTransform() - class ThetaLocator(Locator): - pass + class ThetaFormatter(Formatter): + def __call__(self, x, pos=None): + return u"%d\u00b0" % ((x / npy.pi) * 180.0) + + class RadialLocator(Locator): + def __init__(self, base): + self.base = base + + def __call__(self): + ticks = self.base() + # MGDTODO: Use numpy + return [x for x in ticks if x > 0] + + def autoscale(self): + return self.base.autoscale() + + def pan(self, numsteps): + return self.base.pan(numsteps) + + def zoom(self, direction): + return self.base.zoom(direction) + + def refresh(self): + return self.base.refresh() + + RESOLUTION = 100 def __init__(self, *args, **kwargs): + self._rpad = 0.05 Axes.__init__(self, *args, **kwargs) self.set_aspect('equal', adjustable='box', anchor='C') self.cla() @@ -76,55 +114,105 @@ def cla(self): Axes.cla(self) - self.xaxis.set_major_locator(PolarAxes.ThetaLocator()) - - def _set_transData(self): + self.xaxis.set_major_formatter(self.ThetaFormatter()) + angles = npy.arange(0.0, 360.0, 45.0) + self.set_thetagrids(angles) + self.yaxis.set_major_locator(self.RadialLocator(self.yaxis.get_major_locator())) + + def _set_lim_and_transforms(self): + self.dataLim = Bbox([[0.0, 0.0], [npy.pi * 2.0, 1.0]]) + self.viewLim = Bbox.unit() + self.transAxes = BboxTransform(Bbox.unit(), self.bbox) + + # Transforms the x and y axis separately by a scale factor + # It is assumed that this part will have non-linear components + self.transScale = TransformWrapper(IdentityTransform()) + # A (possibly non-linear) projection on the (already scaled) data - self.transProjection = self.PolarTransform() + self.transProjection = self.PolarTransform(self.RESOLUTION) # An affine transformation on the data, generally to limit the # range of the axes self.transProjectionAffine = self.PolarAffine(self.viewLim) self.transData = self.transScale + self.transProjection + \ - self.transProjectionAffine + self.transAxes + (self.transProjectionAffine + self.transAxes) self._xaxis_transform = ( - self.PolarTransform() + + self.transProjection + self.PolarAffine(Bbox.unit()) + self.transAxes) + self._theta_label1_position = Affine2D().translate(0.0, 1.1) + self._xaxis_text1_transform = ( + self._theta_label1_positi... [truncated message content] |