Revision: 4004 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4004&view=rev Author: mdboom Date: 2007-10-25 12:16:11 -0700 (Thu, 25 Oct 2007)
Log Message: ----------- Increased coverage of backend_driver.py to include almost everything in axes.py. Lots of little bug fixes. Modified Paths: -------------- branches/transforms/PASSED_DEMOS branches/transforms/examples/arrow_demo.py branches/transforms/examples/backend_driver.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_pdf.py branches/transforms/lib/matplotlib/backends/backend_ps.py branches/transforms/lib/matplotlib/backends/backend_svg.py branches/transforms/lib/matplotlib/backends/backend_template.py branches/transforms/lib/matplotlib/cbook.py branches/transforms/lib/matplotlib/collections.py branches/transforms/lib/matplotlib/contour.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/path.py branches/transforms/lib/matplotlib/scale.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/lib/matplotlib/widgets.py branches/transforms/src/_gtkagg.cpp Added Paths: ----------- branches/transforms/examples/equal_aspect_ratio.py branches/transforms/examples/hline_demo.py Modified: branches/transforms/PASSED_DEMOS =================================================================== --- branches/transforms/PASSED_DEMOS 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/PASSED_DEMOS 2007-10-25 19:16:11 UTC (rev 4004) @@ -60,7 +60,7 @@ dynamic_demo_wx.py [REQUIRES NON-AGG WX RENDERER, WHICH IS NOT YET IMPLEMENTED] dynamic_image_gtkagg.py O dynamic_image_wxagg2.py O -dynamic_image_wxagg.py +dynamic_image_wxagg.py [REQUIRES NON-AGG WX RENDERER, WHICH IS NOT YET IMPLEMENTED] ellipse_demo.py O ellipse_rotated.py O embedding_in_gtk2.py [REQUIRES NON-AGG GDK RENDERER, WHICH IS NOT YET IMPLEMENTED] Modified: branches/transforms/examples/arrow_demo.py =================================================================== --- branches/transforms/examples/arrow_demo.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/examples/arrow_demo.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -280,6 +280,7 @@ if __name__ == '__main__': from sys import argv + d = None if len(argv) > 1: if argv[1] == 'full': d = all_on_max @@ -293,7 +294,7 @@ elif argv[1] == 'sample': d = sample_data scaled = True - else: + if d is None: d = all_on_max scaled=False if len(argv) > 2: Modified: branches/transforms/examples/backend_driver.py =================================================================== --- branches/transforms/examples/backend_driver.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/examples/backend_driver.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -22,10 +22,16 @@ files = ( 'alignment_test.py', 'arctest.py', + 'arrow_demo.py', 'axes_demo.py', + 'axhspan_demo.py', 'bar_stacked.py', 'barchart_demo.py', + 'boxplot_demo.py', + 'broken_barh.py', + 'barh_demo.py', 'color_demo.py', + 'colorbar_only.py', 'contour_demo.py', 'contourf_demo.py', 'csd_demo.py', @@ -33,6 +39,8 @@ 'customize_rc.py', 'date_demo1.py', 'date_demo2.py', + 'equal_aspect_ratio.py', + 'errorbar_limits.py', 'figimage_demo.py', 'figlegend_demo.py', 'figtext.py', @@ -40,6 +48,7 @@ 'finance_demo.py', 'fonts_demo_kw.py', 'histogram_demo.py', + 'hline_demo.py', 'image_demo.py', 'image_demo2.py', 'image_masked.py', @@ -66,11 +75,18 @@ 'polar_demo.py', 'polar_scatter.py', 'psd_demo.py', + 'quadmesh_demo.py', 'quiver_demo.py', 'scatter_demo.py', 'scatter_demo2.py', + 'scatter_star_poly.py', + 'shared_axis_demo.py', + 'shared_axis_across_figures.py', 'simple_plot.py', 'specgram_demo.py', + 'spy_demos.py', + 'stem_plot.py', + 'step_demo.py', 'stock_demo.py', 'subplot_demo.py', # 'set_and_get.py', @@ -104,7 +120,7 @@ def run(arglist): os.system(' '.join(arglist)) -def drive(backend, python='python', switches = []): +def drive(backend, python=['python'], switches = []): exclude = failbackend.get(backend, []) switchstring = ' '.join(switches) @@ -151,17 +167,20 @@ tmpfile.write('savefig("%s", dpi=150)' % outfile) tmpfile.close() - run([python, tmpfile_name, switchstring]) + run(python + [tmpfile_name, switchstring]) #os.system('%s %s %s' % (python, tmpfile_name, switchstring)) os.remove(tmpfile_name) if __name__ == '__main__': times = {} default_backends = ['Agg', 'PS', 'SVG', 'PDF', 'Template'] - if sys.platform == 'win32': - python = r'c:\Python24\python.exe' + if '--coverage' in sys.argv: + python = ['coverage.py', '-x'] + sys.argv.remove('--coverage') + elif sys.platform == 'win32': + python = [r'c:\Python24\python.exe'] else: - python = 'python' + python = ['python'] all_backends = [b.lower() for b in mplbe.all_backends] all_backends.extend(['cairo.png', 'cairo.ps', 'cairo.pdf', 'cairo.svg']) backends = [] Added: branches/transforms/examples/equal_aspect_ratio.py =================================================================== --- branches/transforms/examples/equal_aspect_ratio.py (rev 0) +++ branches/transforms/examples/equal_aspect_ratio.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -0,0 +1,23 @@ +#!/usr/bin/env python +""" +Example: simple line plot. +Show how to make a plot that has equal aspect ratio +""" +from pylab import * + +t = arange(0.0, 1.0+0.01, 0.01) +s = cos(2*2*pi*t) +plot(t, s, '-', lw=2) + +xlabel('time (s)') +ylabel('voltage (mV)') +title('About as simple as it gets, folks') +grid(True) + +axes().set_aspect('equal', 'datalim') + + +#savefig('simple_plot.png') +savefig('equal_aspect') + +show() Property changes on: branches/transforms/examples/equal_aspect_ratio.py ___________________________________________________________________ Name: svn:executable + * Added: branches/transforms/examples/hline_demo.py =================================================================== --- branches/transforms/examples/hline_demo.py (rev 0) +++ branches/transforms/examples/hline_demo.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -0,0 +1,21 @@ +#!/usr/bin/env python +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((s1*e1))+.05 + + +t = arange(0.0, 5.0, 0.1) +s = f(t) +nse = normal(0.0, 0.3, t.shape) * s + +plot(s+nse, t, 'b^') +hlines(t, [0], s) +xlabel('time (s)') +title('Comparison of model with data') +show() + Property changes on: branches/transforms/examples/hline_demo.py ___________________________________________________________________ Name: svn:executable + * Modified: branches/transforms/lib/matplotlib/artist.py =================================================================== --- branches/transforms/lib/matplotlib/artist.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/artist.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -1,5 +1,5 @@ from __future__ import division -import sys, re +import sys, re, warnings from cbook import iterable, flatten from transforms import Affine2D, Bbox, IdentityTransform, TransformedBbox, \ TransformedPath @@ -174,7 +174,7 @@ """ if callable(self._contains): return self._contains(self,mouseevent) #raise NotImplementedError,str(self.__class__)+" needs 'contains' method" - print str(self.__class__)+" needs 'contains' method" + warnings.warn("'%s' needs 'contains' method" % self.__class__.__name__) return False,{} def set_contains(self,picker): Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -821,16 +821,15 @@ Use self._aspect and self._adjustable to modify the axes box or the view limits. ''' - #MGDTODO: Numpify - - if self._aspect == 'auto': + aspect = self.get_aspect() + if aspect == 'auto': self.set_position( self._originalPosition , 'active') return - if self._aspect == 'equal': + if aspect == 'equal': A = 1 else: - A = self._aspect + A = aspect #Ensure at drawing time that any Axes involved in axis-sharing # does not have its position changed. @@ -843,7 +842,7 @@ 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') + self.set_position(pb1.anchored(self.get_anchor(), pb), 'active') return xmin,xmax = self.get_xbound() @@ -1040,7 +1039,7 @@ a.set_clip_path(self.axesPatch) a._remove_method = lambda h: self.artists.remove(h) - def add_collection(self, collection, autolim=False): + def add_collection(self, collection, autolim=True): 'add a Collection instance to Axes' label = collection.get_label() if not label: @@ -1127,8 +1126,8 @@ self.ignore_existing_data_limits = False def update_datalim_bounds(self, bounds): - # MGDTODO: Document me - self.dataLim.bounds = Bbox.union([self.dataLim, bounds]).bounds + 'Update the datalim to include the given Bbox' + self.dataLim.set(Bbox.union([self.dataLim, bounds])) def _get_verts_in_data_coords(self, trans, xys): if trans == self.transData: @@ -2017,8 +2016,9 @@ Note this algorithm calculates distance to the vertices of the polygon, so if you want to pick a patch, click on the edge! """ + # MGDTODO: Needs updating if trans is not None: - xywin = trans.xy_tup((x,y)) + xywin = trans.transform_point((x,y)) else: xywin = x,y @@ -2036,12 +2036,12 @@ def dist(a): if isinstance(a, Text): bbox = a.get_window_extent() - l,b,w,h = bbox.get_bounds() + l,b,w,h = bbox.bounds verts = (l,b), (l,b+h), (l+w,b+h), (l+w, b) xt, yt = zip(*verts) elif isinstance(a, Patch): - verts = a.get_verts() - tverts = a.get_transform().seq_xy_tups(verts) + path = a.get_path() + tverts = a.get_transform().transform_path(path) xt, yt = zip(*tverts) elif isinstance(a, mlines.Line2D): xdata = a.get_xdata(orig=False) @@ -3278,19 +3278,19 @@ self.hold(holdstate) # restore previous hold state if adjust_xlim: - xmin, xmax = self.dataLim.intervalx().get_bounds() + xmin, xmax = self.dataLim.intervalx xmin = npy.amin(width) if xerr is not None: xmin = xmin - npy.amax(xerr) xmin = max(xmin*0.9, 1e-100) - self.dataLim.intervalx().set_bounds(xmin, xmax) + self.dataLim.intervalx = (xmin, xmax) if adjust_ylim: - ymin, ymax = self.dataLim.intervaly().get_bounds() + ymin, ymax = self.dataLim.intervaly ymin = npy.amin(height) if yerr is not None: ymin = ymin - npy.amax(yerr) ymin = max(ymin*0.9, 1e-100) - self.dataLim.intervaly().set_bounds(ymin, ymax) + self.dataLim.intervaly = (ymin, ymax) self.autoscale_view() return patches bar.__doc__ = cbook.dedent(bar.__doc__) % martist.kwdocd @@ -4197,7 +4197,7 @@ def quiver(self, *args, **kw): q = mquiver.Quiver(self, *args, **kw) - self.add_collection(q) + self.add_collection(q, False) self.update_datalim_numerix(q.X, q.Y) self.autoscale_view() return q @@ -5170,6 +5170,7 @@ 'get the subplot geometry, eg 2,2,3' return self._rows, self._cols, self._num+1 + # COVERAGE NOTE: Never used internally or from examples def change_geometry(self, numrows, numcols, num): 'change subplot geometry, eg from 1,1,1 to 2,2,3' self._rows = numrows @@ -5238,6 +5239,7 @@ def is_last_col(self): return self.colNum==self.numCols-1 + # COVERAGE NOTE: Never used internally or from examples def label_outer(self): """ set the visible property on ticklabels so xticklabels are Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -223,7 +223,7 @@ baseline (descent), in display coords of the string s with FontPropertry prop """ - return 1,1,1 + raise NotImplementedError def new_gc(self): """ Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -1180,11 +1180,12 @@ def get_image_magnification(self): return self.image_magnification - def draw_image(self, x, y, im, bbox): + def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None): #print >>sys.stderr, "draw_image called" + # MGDTODO: Support clippath here gc = self.new_gc() - gc.set_clip_rectangle(bbox.get_bounds()) + gc.set_clip_rectangle(bbox.bounds) self.check_gc(gc) h, w = im.get_size_out() @@ -1714,13 +1715,19 @@ """ cmds = [] for params, cmd in self.commands: - ours = [ getattr(self, p) for p in params ] - theirs = [ getattr(other, p) for p in params ] - try: - different = ours != theirs - except ValueError: - different = ours.shape != theirs.shape or npy.any(ours != theirs) - if ours is not theirs: + different = False + for p in params: + ours = getattr(self, p) + theirs = getattr(other, p) + try: + different = bool(ours != theirs) + except ValueError: + different = ours.shape != theirs.shape or npy.any(ours != theirs) + if different: + break + + if different: + theirs = [getattr(other, p) for p in params] cmds.extend(cmd(self, *theirs)) for p in params: setattr(self, p, getattr(other, p)) Modified: branches/transforms/lib/matplotlib/backends/backend_ps.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -994,12 +994,12 @@ tmpfile = os.path.join(gettempdir(), md5.md5(outfile).hexdigest()) fh = file(tmpfile, 'w') - self.figure.dpi.set(72) # ignore the dpi kwarg + self.figure.dpi = 72 # ignore the dpi kwarg width, height = self.figure.get_size_inches() xo = 0 yo = 0 - l, b, w, h = self.figure.bbox.get_bounds() + l, b, w, h = self.figure.bbox.bounds llx = xo lly = yo urx = llx + w Modified: branches/transforms/lib/matplotlib/backends/backend_svg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_svg.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/backends/backend_svg.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -193,7 +193,8 @@ details = 'xlink:href="#%s" x="%f" y="%f"' % (name, x, y) self._draw_svg_element('use', details, gc, rgbFace) - def draw_image(self, x, y, im, bbox): + def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None): + # MGDTODO: Support clippath here trans = [1,0,0,1,0,0] transstr = '' if rcParams['svg.image_noscale']: Modified: branches/transforms/lib/matplotlib/backends/backend_template.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_template.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/backends/backend_template.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -66,24 +66,23 @@ rotation): pass - def draw_image(self, x, y, im, bbox): + def draw_path(self, gc, path, transform, rgbFace=None): pass - def draw_line(self, gc, x1, y1, x2, y2): + def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): pass - def draw_lines(self, gc, x, y): + # draw_path_collection is optional, and we get more correct + # relative timings by leaving it out. +# def draw_path_collection(self, master_transform, cliprect, clippath, +# clippath_trans, paths, all_transforms, offsets, +# offsetTrans, facecolors, edgecolors, linewidths, +# linestyles, antialiaseds): +# pass + + def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None): pass - def draw_point(self, gc, x, y): - pass - - def draw_polygon(self, gcEdge, rgbFace, points): - pass - - def draw_rectangle(self, gcEdge, rgbFace, x, y, width, height): - pass - def draw_text(self, gc, x, y, s, prop, angle, ismath=False): pass Modified: branches/transforms/lib/matplotlib/cbook.py =================================================================== --- branches/transforms/lib/matplotlib/cbook.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/cbook.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -174,7 +174,6 @@ def __str__(self): return '<a list of %d %s objects>' % (len(self), self.type) -# MGDTODO: This is very incomplete def strip_math(s): 'remove latex formatting from mathtext' remove = (r'\rm', '\cal', '\tt', '\it', '\\', '{', '}') Modified: branches/transforms/lib/matplotlib/collections.py =================================================================== --- branches/transforms/lib/matplotlib/collections.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/collections.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -126,13 +126,21 @@ return self._transforms def get_datalim(self, transData): + transform = self.get_transform() + transOffset = self._transOffset + offsets = self._offsets + paths = self.get_paths() + if not transform.is_affine: + paths = [transform.transform_path_non_affine(p) for p in paths] + transform = transform.get_affine() + if not transOffset.is_affine: + offsets = transOffset.transform_non_affine(offsets) + transOffset = transOffset.get_affine() + result = path.get_path_collection_extents( - self.get_transform().frozen(), - self.get_paths(), - self.get_transforms(), - self._offsets, - self._transOffset.frozen()) - result = result.transformed(transData.inverted()) + transform.frozen(), paths, self.get_transforms(), + npy.asarray(offsets, npy.float_), transOffset.frozen()) + result = result.inverse_transformed(transData) return result def draw(self, renderer): @@ -143,7 +151,6 @@ offsets = self._offsets paths = self.get_paths() - # MGDTODO: Test me if self.have_units(): paths = [] for path in self._paths: @@ -163,7 +170,6 @@ if clippath_trans is not None: clippath_trans = clippath_trans.frozen() - # MGDTODO: This may benefit from using TransformedPath if not transform.is_affine: paths = [transform.transform_path_non_affine(path) for path in paths] transform = transform.get_affine() @@ -193,7 +199,6 @@ paths = [transform.transform_path_non_affine(path) for path in paths] transform = transform.get_affine() - # MGDTODO: Don't pick when outside of clip path / clip box ind = path.point_in_path_collection( mouseevent.x, mouseevent.y, self._pickradius, transform.frozen(), paths, self.get_transforms(), @@ -201,45 +206,6 @@ self._transOffset.frozen(), len(self._facecolors)) return len(ind)>0,dict(ind=ind) - # MGDTODO: Update - def get_transformed_patches(self): - """ - get a sequence of the polygons in the collection in display (transformed) space - - The ith element in the returned sequence is a list of x,y - vertices defining the ith polygon - """ - - verts = self._verts - offsets = self._offsets - usingOffsets = offsets is not None - transform = self.get_transform() - transOffset = self.get_transoffset() - Noffsets = 0 - Nverts = len(verts) - if usingOffsets: - Noffsets = len(offsets) - - N = max(Noffsets, Nverts) - - data = [] - #print 'verts N=%d, Nverts=%d'%(N, Nverts), verts - #print 'offsets; Noffsets=%d'%Noffsets - for i in xrange(N): - #print 'i%%Nverts=%d'%(i%Nverts) - polyverts = verts[i % Nverts] - if npy.any(npy.isnan(polyverts)): - continue - #print 'thisvert', i, polyverts - tverts = transform.seq_xy_tups(polyverts) - if usingOffsets: - #print 'using offsets' - xo,yo = transOffset.xy_tup(offsets[i % Noffsets]) - tverts = [(x+xo,y+yo) for x,y in tverts] - - data.append(tverts) - return data - def set_pickradius(self,pickradius): self.pickradius = 5 def get_pickradius(self): return self.pickradius @@ -414,8 +380,8 @@ self._meshHeight = meshHeight self._coordinates = coordinates self._showedges = showedges - - # MGDTODO: Numpify + + # MGDTODO: Is it possible to Numpify this? coordinates = coordinates.reshape((meshHeight + 1, meshWidth + 1, 2)) c = coordinates paths = [] @@ -542,24 +508,6 @@ def get_paths(self): return self._paths - - # MGDTODO: Update - def get_transformed_patches(self): - # Shouldn't need all these calls to asarray; - # the variables should be converted when stored. - # Similar speedups with numpy should be attainable - # in many other places. - verts = npy.asarray(self._verts) - offsets = npy.asarray(self._offsets) - Npoly = len(offsets) - scales = npy.sqrt(npy.asarray(self._sizes)*self._dpi.get()/72.0) - Nscales = len(scales) - if Nscales >1: - scales = npy.resize(scales, (Npoly, 1, 1)) - transOffset = self.get_transoffset() - xyo = transOffset.numerix_xy(offsets) - polys = scales * verts + xyo[:, npy.newaxis, :] - return polys class StarPolygonCollection(RegularPolyCollection): Modified: branches/transforms/lib/matplotlib/contour.py =================================================================== --- branches/transforms/lib/matplotlib/contour.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/contour.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -464,7 +464,7 @@ ls = mpl.rcParams['contour.negative_linestyle'] col.set_linestyle(ls) col.set_label('_nolegend_') - self.ax.add_collection(col) + self.ax.add_collection(col, False) self.collections.append(col) self.changed() # set the colors x0 = ma.minimum(x) Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/lines.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -25,6 +25,7 @@ (TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN, CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN) = range(8) +# COVERAGE NOTE: Never called internally or from examples def unmasked_index_ranges(mask, compressed = True): ''' Calculate the good data ranges in a masked 1-D npy.array, based on mask. @@ -72,45 +73,6 @@ 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. - """ - # Process single points specially - if len(x) < 2: - res, = npy.nonzero( (cx - x)**2 + (cy - y)**2 <= radius**2 ) - return res - - # We need to lop the last element off a lot. - xr,yr = x[:-1],y[:-1] - - # Only look at line segments whose nearest point to C on the line - # lies within the segment. - dx,dy = x[1:]-xr, y[1:]-yr - Lnorm_sq = dx**2+dy**2 # Possibly want to eliminate Lnorm==0 - u = ( (cx-xr)*dx + (cy-yr)*dy )/Lnorm_sq - candidates = (u>=0) & (u<=1) - #if any(candidates): print "candidates",xr[candidates] - - # Note that there is a little area near one side of each point - # which will be near neither segment, and another which will - # be near both, depending on the angle of the lines. The - # following radius test eliminates these ambiguities. - point_hits = (cx - x)**2 + (cy - y)**2 <= radius**2 - #if any(point_hits): print "points",xr[candidates] - candidates = candidates & ~point_hits[:-1] & ~point_hits[1:] - - # For those candidates which remain, determine how far they lie away - # from the line. - px,py = xr+u*dx,yr+u*dy - line_hits = (cx-px)**2 + (cy-py)**2 <= radius**2 - #if any(line_hits): print "lines",xr[candidates] - line_hits = line_hits & candidates - points, = point_hits.ravel().nonzero() - lines, = line_hits.ravel().nonzero() - #print points,lines - return npy.concatenate((points,lines)) - class Line2D(Artist): lineStyles = _lineStyles = { # hidden names deprecated '-' : '_draw_solid', @@ -381,12 +343,17 @@ else: x, y = args + not_masked = 0 if not ma.isMaskedArray(x): x = npy.asarray(x) + not_masked += 1 if not ma.isMaskedArray(y): y = npy.asarray(y) - if ((x.shape != self._xorig.shape or npy.any(x != self._xorig)) or - (y.shape != self._yorig.shape or npy.any(y != self._yorig))): + not_masked += 1 + + if (not_masked < 2 or + ((x.shape != self._xorig.shape or npy.any(x != self._xorig)) or + (y.shape != self._yorig.shape or npy.any(y != self._yorig)))): self._xorig = x self._yorig = y self.recache() Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/patches.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -224,7 +224,6 @@ path = self.get_path() transform = self.get_transform() - # MGDTODO: Use a transformed path here? tpath = transform.transform_path_non_affine(path) affine = transform.get_affine() @@ -328,7 +327,7 @@ def __str__(self): return str(self.__class__).split('.')[-1] \ - + "(%g,%g;%gx%g)"%(self.xy[0],self.xy[1],self.width,self.height) + + "(%g,%g;%gx%g)" % tuple(self._bbox.bounds) def __init__(self, xy, width, height, **kwargs): """ @@ -433,7 +432,7 @@ A regular polygon patch. """ def __str__(self): - return "Poly%d(%g,%g)"%(self.numVertices,self.xy[0],self.xy[1]) + return "Poly%d(%g,%g)"%(self._numVertices,self._xy[0],self._xy[1]) def __init__(self, xy, numVertices, radius=5, orientation=0, **kwargs): @@ -447,6 +446,7 @@ %(Patch)s """ self._xy = xy + self._numVertices = numVertices self._orientation = orientation self._radius = radius self._path = Path.unit_regular_polygon(numVertices) @@ -483,6 +483,13 @@ self._radius = xy self._update_transform() radius = property(_get_radius, _set_radius) + + def _get_numvertices(self): + return self._numVertices + def _set_numvertices(self, numVertices): + self._numVertices = numVertices + self._path = Path.unit_regular_polygon(numVertices) + numvertices = property(_get_numvertices, _set_numvertices) def get_path(self): return self._path @@ -495,7 +502,7 @@ A general polygon patch. """ def __str__(self): - return "Poly(%g, %g)" % tuple(self._path.vertices[0]) + return "Poly((%g, %g) ...)" % tuple(self._path.vertices[0]) def __init__(self, xy, **kwargs): """ @@ -507,15 +514,17 @@ """ Patch.__init__(self, **kwargs) self._path = Path(xy, closed=True) - self.xy = self._path.vertices __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd def get_path(self): return self._path - def update(self): - self._path = Path(self.xy, closed=True) - + def _get_xy(self): + return self._path.vertices + def _set_xy(self, vertices): + self._path = Path(vertices, closed=True) + xy = property(_get_xy, _set_xy) + class Wedge(Patch): def __str__(self): return "Wedge(%g,%g)"%self.xy[0] @@ -539,16 +548,14 @@ def get_patch_transform(self): return self._patch_transform - + +# COVERAGE NOTE: Not used internally or from examples class Arrow(Polygon): """ An arrow patch """ def __str__(self): - x1,y1 = self.xy[0] - x2,y2 = self.xy[1] - cx,cy = (x1+x2)/2.,(y1+y2)/2. - return "Arrow(%g,%g)"%(cx,cy) + return "Arrow()" _path = Path( [ [ 0.0, 0.1 ], [ 0.0, -0.1], @@ -584,10 +591,7 @@ """Like Arrow, but lets you set head width and head height independently.""" def __str__(self): - x1,y1 = self.xy[0] - x2,y2 = self.xy[1] - cx,cy = (x1+x2)/2.,(y1+y2)/2. - return "FancyArrow(%g,%g)"%(cx,cy) + return "FancyArrow()" def __init__(self, x, y, dx, dy, width=0.001, length_includes_head=False, \ head_width=None, head_length=None, shape='full', overhang=0, \ @@ -608,7 +612,6 @@ %(Patch)s """ - # MGDTODO: Implement me if head_width is None: head_width = 3 * width if head_length is None: @@ -664,10 +667,7 @@ x1,y1 and a base at x2, y2. """ def __str__(self): - x1,y1 = self.xy[0] - x2,y2 = self.xy[1] - cx,cy = (x1+x2)/2.,(y1+y2)/2. - return "YAArrow(%g,%g)"%(cx,cy) + return "YAArrow()" def __init__(self, dpi, xytip, xybase, width=4, frac=0.1, headwidth=12, **kwargs): """ @@ -692,9 +692,8 @@ __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd def get_path(self): - # MGDTODO: Since this is dpi dependent, we need to recompute - # the path every time. Perhaps this can be plugged through the - # dpi transform instead (if only we know how to get it...) + # Since this is dpi dependent, we need to recompute the path + # every time. # the base vertices x1, y1 = self.xytip @@ -786,13 +785,16 @@ """ Patch.__init__(self, **kwargs) - self.center = xy - self.width, self.height = width, height - self.angle = angle - self._patch_transform = transforms.Affine2D() \ - .scale(self.width * 0.5, self.height * 0.5) \ - .rotate_deg(angle) \ - .translate(*xy) + self._center = xy + self._width, self._height = width, height + self._angle = angle + self._recompute_transform() + + def _recompute_transform(self): + self._patch_transform = transforms.Affine2D() \ + .scale(self._width * 0.5, self._height * 0.5) \ + .rotate_deg(self._angle) \ + .translate(*self._center) def get_path(self): """ @@ -808,7 +810,28 @@ x, y = self.get_transform().inverted().transform_point((ev.x, ev.y)) return (x*x + y*y) <= 1.0, {} + def _get_center(self): + return self._center + def _set_center(self, center): + self._center = center + self._recompute_transform() + center = property(_get_center, _set_center) + def _get_xy(self): + return self._xy + def _set_xy(self, xy): + self._xy = xy + self._recompute_transform() + xy = property(_get_xy, _set_xy) + + def _get_angle(self): + return self._angle + def _set_angle(self, angle): + self._angle = angle + self._recompute_transform() + angle = property(_get_angle, _set_angle) + + class Circle(Ellipse): """ A circle patch @@ -816,8 +839,7 @@ def __str__(self): return "Circle((%g,%g),r=%g)"%(self.center[0],self.center[1],self.radius) - def __init__(self, xy, radius=5, - **kwargs): + def __init__(self, xy, radius=5, **kwargs): """ Create true circle at center xy=(x,y) with given radius; unlike circle polygon which is a polygonal approcimation, this @@ -837,122 +859,6 @@ __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd -class PolygonInteractor: - """ - An polygon editor. - - Key-bindings - - 't' toggle vertex markers on and off. When vertex markers are on, - you can move them, delete them - - 'd' delete the vertex under point - - 'i' insert a vertex at point. You must be within epsilon of the - line connecting two existing vertices - - """ - - showverts = True - epsilon = 5 # max pixel distance to count as a vertex hit - - def __str__(self): - return "PolygonInteractor" - - def __init__(self, poly): - if poly.figure is None: - raise RuntimeError('You must first add the polygon to a figure or canvas before defining the interactor') - canvas = poly.figure.canvas - self.poly = poly - self.poly.verts = list(self.poly.verts) - x, y = zip(*self.poly.verts) - self.line = lines.Line2D(x,y,marker='o', markerfacecolor='r') - #self._update_line(poly) - - cid = self.poly.add_callback(self.poly_changed) - self._ind = None # the active vert - - canvas.mpl_connect('button_press_event', self.button_press_callback) - canvas.mpl_connect('key_press_event', self.key_press_callback) - canvas.mpl_connect('button_release_event', self.button_release_callback) - canvas.mpl_connect('motion_notify_event', self.motion_notify_callback) - self.canvas = canvas - - - def poly_changed(self, poly): - 'this method is called whenever the polygon object is called' - # only copy the artist props to the line (except visibility) - vis = self.line.get_visible() - artist.Artist.update_from(self.line, poly) - self.line.set_visible(vis) # don't use the poly visibility state - - - def get_ind_under_point(self, event): - 'get the index of the vertex under point if within epsilon tolerance' - x, y = zip(*self.poly.verts) - - # display coords - xt, yt = self.poly.get_transform().numerix_x_y(x, y) - d = npy.sqrt((xt-event.x)**2 + (yt-event.y)**2) - ind, = npy.nonzero(npy.equal(d, npy.amin(d))) - - if d[ind]>=self.epsilon: - ind = None - - return ind - - def button_press_callback(self, event): - 'whenever a mouse button is pressed' - if not self.showverts: return - if event.inaxes==None: return - if event.button != 1: return - self._ind = self.get_ind_under_point(event) - - def button_release_callback(self, event): - 'whenever a mouse button is released' - if not self.showverts: return - if event.button != 1: return - self._ind = None - - def key_press_callback(self, event): - 'whenever a key is pressed' - if not event.inaxes: return - if event.key=='t': - self.showverts = not self.showverts - self.line.set_visible(self.showverts) - if not self.showverts: self._ind = None - elif event.key=='d': - ind = self.get_ind_under_point(event) - if ind is not None: - self.poly.verts = [tup for i,tup in enumerate(self.poly.verts) if i!=ind] - self.line.set_data(zip(*self.poly.verts)) - elif event.key=='i': - xys = self.poly.get_transform().seq_xy_tups(self.poly.verts) - p = event.x, event.y # display coords - for i in range(len(xys)-1): - s0 = xys[i] - s1 = xys[i+1] - d = mlab.dist_point_to_segment(p, s0, s1) - if d<=self.epsilon: - self.poly.verts.insert(i+1, (event.xdata, event.ydata)) - self.line.set_data(zip(*self.poly.verts)) - break - - - self.canvas.draw() - - def motion_notify_callback(self, event): - 'on mouse movement' - if not self.showverts: return - if self._ind is None: return - if event.inaxes is None: return - if event.button != 1: return - x,y = event.xdata, event.ydata - self.poly.verts[self._ind] = x,y - self.line.set_data(zip(*self.poly.verts)) - self.canvas.draw_idle() - - def bbox_artist(artist, renderer, props=None, fill=True): """ This is a debug function to draw a rectangle around the bounding Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/path.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -405,4 +405,7 @@ wedge = classmethod(wedge) def get_path_collection_extents(*args): + from transforms import Bbox + if len(args[1]) == 0: + raise ValueError("No paths provided") return Bbox.from_extents(*_path.get_path_collection_extents(*args)) Modified: branches/transforms/lib/matplotlib/scale.py =================================================================== --- branches/transforms/lib/matplotlib/scale.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/scale.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -9,8 +9,6 @@ from transforms import Affine1DBase, IntervalTransform, Transform, \ composite_transform_factory, IdentityTransform -# MGDTODO: Should the tickers/locators be moved here? - class ScaleBase(object): def set_default_locators_and_formatters(self, axis): raise NotImplementedError Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/transforms.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -32,7 +32,7 @@ import cbook from path import Path -DEBUG = True +DEBUG = False if DEBUG: import warnings @@ -276,7 +276,7 @@ size = property(_get_size) def _get_bounds(self): - ((x0, y0), (x1, y1)) = self.get_points() + x0, y0, x1, y1 = self.get_points().flatten() return (x0, y0, x1 - x0, y1 - y0) bounds = property(_get_bounds) @@ -608,21 +608,24 @@ def invalidate(self): self._check(self._points) TransformNode.invalidate(self) - + + _unit_values = npy.array([[0.0, 0.0], [1.0, 1.0]], npy.float_) [EMAIL PROTECTED] def unit(): """ Create a new unit BBox from (0, 0) to (1, 1). """ - return Bbox.from_extents(0., 0., 1., 1.) + return Bbox(Bbox._unit_values.copy()) unit = staticmethod(unit) [EMAIL PROTECTED] - def from_bounds(left, bottom, width, height): + def from_bounds(x0, y0, width, height): """ - Create a new Bbox from left, bottom, width and height. + Create a new Bbox from x0, y0, width and height. + + width and height may be negative. """ - return Bbox.from_extents(left, bottom, left + width, bottom + height) + return Bbox.from_extents(x0, y0, x0 + width, y0 + height) from_bounds = staticmethod(from_bounds) [EMAIL PROTECTED] @@ -663,7 +666,6 @@ when False, include the existing bounds of the Bbox. when None, use the last value passed to Bbox.ignore(). """ - # MGDTODO: It may be more efficient for some callers to use update_from_data_xy instead if ignore is None: ignore = self._ignore @@ -830,7 +832,11 @@ def get_points(self): if self._invalid: - self._points = self._transform.transform(self._bbox.get_points()) + points = self._transform.transform(self._bbox.get_points()) + if ma.isMaskedArray(points): + points.putmask(0.0) + points = npy.asarray(points) + self._points = points self._invalid = 0 return self._points @@ -1429,8 +1435,8 @@ if DEBUG: _transform = transform def transform(self, points): - # MGDTODO: The major speed trap here is just converting to - # the points to an array in the first place. If we can use + # 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 ma.isMaskedArray(points) and not isinstance(points, npy.ndarray)): @@ -2074,7 +2080,7 @@ """ assert boxin.is_bbox assert boxout.is_bbox - + Affine2DBase.__init__(self) self._boxin = boxin self._boxout = boxout @@ -2092,6 +2098,8 @@ outl, outb, outw, outh = self._boxout.bounds x_scale = outw / inw y_scale = outh / inh + if DEBUG and (x_scale == 0 or y_scale == 0): + raise ValueError("Transforming from or to a singular bounding box.") self._mtx = npy.array([[x_scale, 0.0 , (-inl*x_scale+outl)], [0.0 , y_scale, (-inb*y_scale+outb)], [0.0 , 0.0 , 1.0 ]], @@ -2175,18 +2183,17 @@ return vmin, vmax -# MGDTODO: Optimize (perhaps in an extension) def interval_contains(interval, val): a, b = interval - return (((a < b) - and (a <= val and b >= val)) - or (b <= val and a >= val)) + return ( + ((a < b) and (a <= val and b >= val)) + or (b <= val and a >= val)) def interval_contains_open(interval, val): a, b = interval - return (((a < b) - and (a < val and b > val)) - or (b < val and a > val)) + return ( + ((a < b) and (a < val and b > val)) + or (b < val and a > val)) if __name__ == '__main__': import copy Modified: branches/transforms/lib/matplotlib/widgets.py =================================================================== --- branches/transforms/lib/matplotlib/widgets.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/widgets.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -240,9 +240,10 @@ self.set_val(val) def set_val(self, val): - self.poly.xy[-1] = val, 0 - self.poly.xy[-2] = val, 1 - self.poly.update() + xy = self.poly.xy + xy[-1] = val, 0 + xy[-2] = val, 1 + self.poly.xy = xy self.valtext.set_text(self.valfmt%val) if self.drawon: self.ax.figure.canvas.draw() self.val = val Modified: branches/transforms/src/_gtkagg.cpp =================================================================== --- branches/transforms/src/_gtkagg.cpp 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/src/_gtkagg.cpp 2007-10-25 19:16:11 UTC (rev 4004) @@ -70,7 +70,6 @@ } else { //bbox is not None; copy the image in the bbox - // MGDTODO: Use PyArray rather than buffer interface here PyObject* clipbox = args[2].ptr(); PyArrayObject* bbox = NULL; double l, b, r, t; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ Matplotlib-checkins mailing list Matplotlib-checkins@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins