From: <md...@us...> - 2007-10-05 19:25:35
|
Revision: 3924 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3924&view=rev Author: mdboom Date: 2007-10-05 12:25:33 -0700 (Fri, 05 Oct 2007) Log Message: ----------- Simplified sharing axes again. Plowing through -- making more examples work. First pass at updating collections (LineCollection mostly works) Modified Paths: -------------- branches/transforms/examples/clippath_test.py 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/backends/backend_agg.py branches/transforms/lib/matplotlib/cbook.py branches/transforms/lib/matplotlib/collections.py branches/transforms/lib/matplotlib/image.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/text.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h Added Paths: ----------- branches/transforms/src/agg_py_path_iterator.h Modified: branches/transforms/examples/clippath_test.py =================================================================== --- branches/transforms/examples/clippath_test.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/examples/clippath_test.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -13,7 +13,7 @@ self.poly = RegularPolygon( (200, 200), numVertices=10, radius=100, facecolor='yellow', alpha=0.25, - transform=transforms.identity_transform()) + transform=transforms.IdentityTransform()) ax.add_patch(self.poly) self.canvas.mpl_connect('button_press_event', self.onpress) @@ -21,7 +21,6 @@ self.canvas.mpl_connect('motion_notify_event', self.onmove) self.x, self.y = None, None - def onpress(self, event): self.x, self.y = event.x, event.y @@ -42,17 +41,7 @@ self._clip() def _clip(self): - fig = self.ax.figure - l,b,w,h = fig.bbox.get_bounds() - path = agg.path_storage() - - for i, xy in enumerate(self.poly.get_verts()): - x,y = xy - y = h-y - if i==0: path.move_to(x,y) - else: path.line_to(x,y) - path.close_polygon() - self.line.set_clip_path(path) + self.line.set_clip_path(self.poly.get_path(), self.poly.get_transform()) self.canvas.draw_idle() Modified: branches/transforms/lib/matplotlib/artist.py =================================================================== --- branches/transforms/lib/matplotlib/artist.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/artist.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -335,6 +335,11 @@ 'Return artist clip path' return self._clippath + def get_transformed_clip_path_and_affine(self): + if self._clippath is not None: + return self._clippath.get_transformed_path_and_affine() + return None, None + def set_clip_on(self, b): """ Set whether artist uses clipping Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -488,13 +488,9 @@ self._sharey = sharey if sharex is not None: self._shared_x_axes.join(self, sharex) - if sharey is not None: + 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 - if sharex: sharex._masterx = True - if sharey: sharey._mastery = True + self.set_label(label) self.set_figure(fig) @@ -822,7 +818,8 @@ Use self._aspect and self._adjustable to modify the axes box or the view limits. ''' - + #MGDTODO: Numpify + if self._aspect == 'auto': self.set_position( self._originalPosition , 'active') return @@ -834,7 +831,7 @@ #Ensure at drawing time that any Axes involved in axis-sharing # does not have its position changed. - if self._masterx or self._mastery or self._sharex or self._sharey: + if self in self._shared_x_axes or self in self._shared_y_axes: self._adjustable = 'datalim' figW,figH = self.get_figure().get_size_inches() @@ -847,6 +844,11 @@ return + 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) + l,b,w,h = self.get_position(original=True).bounds box_aspect = fig_aspect * (h/w) data_ratio = box_aspect / A @@ -858,8 +860,8 @@ #print 'good enough already' return dL = self.dataLim - xr = 1.05 * dL.width() - yr = 1.05 * dL.height() + xr = 1.05 * dL.width + yr = 1.05 * dL.height xmarg = xsize - xr ymarg = ysize - yr Ysize = data_ratio * xsize @@ -871,10 +873,10 @@ #print 'xmin, xmax, ymin, ymax', xmin, xmax, ymin, ymax #print 'xsize, Xsize, ysize, Ysize', xsize, Xsize, ysize, Ysize - changex = ((self._sharey or self._mastery) and not - (self._sharex or self._masterx)) - changey = ((self._sharex or self._masterx) and not - (self._sharey or self._mastery)) + changex = (self in self._shared_y_axes + and self not in self._shared_x_axes) + changey = (self in self._shared_x_axes + and self not in self._shared_y_axes) if changex and changey: warnings.warn("adjustable='datalim' cannot work with shared x and y axes") return @@ -2200,7 +2202,8 @@ %(Line2D)s """ - trans = mtransforms.blend_xy_sep_transform(self.transAxes, self.transData) + trans = mtransforms.blended_transform_factory( + self.transAxes, self.transData) l, = self.plot([xmin,xmax], [y,y], transform=trans, scalex=False, **kwargs) return l @@ -2236,7 +2239,8 @@ %(Line2D)s """ - trans = mtransforms.blend_xy_sep_transform( self.transData, self.transAxes ) + trans = mtransforms.blended_transform_factory( + self.transData, self.transAxes) l, = self.plot([x,x], [ymin,ymax] , transform=trans, scaley=False, **kwargs) return l @@ -2275,7 +2279,8 @@ %(Polygon)s """ # convert y axis units - trans = mtransforms.blend_xy_sep_transform( self.transAxes, self.transData) + trans = mtransforms.blended_transform_factory( + self.transAxes, self.transData) verts = (xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin) p = mpatches.Polygon(verts, **kwargs) p.set_transform(trans) @@ -2315,7 +2320,8 @@ %(Polygon)s """ # convert x axis units - trans = mtransforms.blend_xy_sep_transform(self.transData, self.transAxes) + trans = mtransforms.blended_transform_factory( + self.transData, self.transAxes) verts = [(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)] p = mpatches.Polygon(verts, **kwargs) p.set_transform(trans) @@ -2386,7 +2392,7 @@ return coll hlines.__doc__ = cbook.dedent(hlines.__doc__) - def vlines(self, x, ymin, ymax, colors='k', linestyle='solid', + def vlines(self, x, ymin, ymax, colors='k', linestyles='solid', label='', **kwargs): """ VLINES(x, ymin, ymax, color='k') @@ -2438,7 +2444,7 @@ for thisx, (thisymin, thisymax) in zip(x,Y)] #print 'creating line collection' coll = mcoll.LineCollection(verts, colors=colors, - linestyle=linestyle, label=label) + linestyles=linestyles, label=label) self.add_collection(coll) coll.update(kwargs) @@ -3660,7 +3666,7 @@ else: lower = y-yerr[0] upper = y+yerr[1] - + barcols.append( self.vlines(x, lower, upper, **lines_kw) ) if capsize > 0: Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/axis.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -1098,9 +1098,9 @@ default resets the tick positions to the default: ticks on both positions, labels at bottom. - ACCEPTS: [ 'top' | 'bottom' | 'both' | 'default' ] + ACCEPTS: [ 'top' | 'bottom' | 'both' | 'default' | 'none' ] """ - assert position == 'top' or position == 'bottom' or position == 'both' or position == 'default' + assert position in ('top', 'bottom', 'both', 'default', 'none') ticks = list( self.get_major_ticks() ) # a copy @@ -1124,6 +1124,10 @@ t.tick2On = True t.label1On = True t.label2On = False + elif position == 'none': + for t in ticks: + t.tick1On = False + t.tick2On = False else: for t in ticks: t.tick1On = True @@ -1306,9 +1310,9 @@ default resets the tick positions to the default: ticks on both positions, labels on the left. - ACCEPTS: [ 'left' | 'right' | 'both' | 'default' ] + ACCEPTS: [ 'left' | 'right' | 'both' | 'default' | 'none' ] """ - assert position == 'left' or position == 'right' or position == 'both' or position == 'default' + assert position in ('left', 'right', 'both', 'default', 'none') ticks = list( self.get_major_ticks() ) # a copy ticks.extend( self.get_minor_ticks() ) @@ -1334,6 +1338,10 @@ t.tick2On = True t.label1On = True t.label2On = False + elif position == 'none': + for t in ticks: + t.tick1On = False + t.tick2On = False else: self.set_offset_position('left') for t in ticks: Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -83,322 +83,322 @@ ## 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): - """ - 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 +# def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2, +# rotation): +# """ +# 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 - If the color rgbFace is not None, fill the arc with it. - """ - raise NotImplementedError +# If the color rgbFace is not None, fill the arc with it. +# """ +# raise NotImplementedError - def draw_line_collection(self, segments, transform, clipbox, - colors, linewidths, linestyle, antialiaseds, - offsets, transOffset): - """ - This is a function for optimized line drawing. If you need to draw - many line segments with similar properties, it is faster to avoid the - overhead of all the object creation etc. The lack of total - configurability is compensated for with efficiency. Hence we don't use - a GC and many of the line props it supports. See - matplotlib.collections for more details. +# def draw_line_collection(self, segments, transform, clipbox, +# colors, linewidths, linestyle, antialiaseds, +# offsets, transOffset): +# """ +# This is a function for optimized line drawing. If you need to draw +# many line segments with similar properties, it is faster to avoid the +# overhead of all the object creation etc. The lack of total +# configurability is compensated for with efficiency. Hence we don't use +# a GC and many of the line props it supports. See +# matplotlib.collections for more details. - segments is a sequence of ( line0, line1, line2), where linen = - is an Mx2 array with columns x, y. Each line can be a - different length +# segments is a sequence of ( line0, line1, line2), where linen = +# is an Mx2 array with columns x, y. Each line can be a +# different length - transform is used to Transform the lines +# transform is used to Transform the lines - clipbox is a xmin, ymin, width, height clip rect +# clipbox is a xmin, ymin, width, height clip rect - colors is a tuple of RGBA tuples +# colors is a tuple of RGBA tuples - linewidths is a tuple of linewidths - *** really should be called 'dashes' not 'linestyle', since - we call gc.set_dashes() not gc.set_linestyle() *** +# linewidths is a tuple of linewidths +# *** really should be called 'dashes' not 'linestyle', since +# we call gc.set_dashes() not gc.set_linestyle() *** - linestyle is an (offset, onoffseq) tuple or None,None for solid +# linestyle is an (offset, onoffseq) tuple or None,None for solid - antialiseds is a tuple of ones or zeros indicating whether the - segment should be aa or not +# antialiseds is a tuple of ones or zeros indicating whether the +# segment should be aa or not - offsets, if not None, is an Nx2 array of x,y offsets to - translate the lines by after transform is used to transform - the offset coords +# offsets, if not None, is an Nx2 array of x,y offsets to +# translate the lines by after transform is used to transform +# the offset coords - This function could be overridden in the backend to possibly implement - faster drawing, but it is already much faster than using draw_lines() - by itself. - """ +# This function could be overridden in the backend to possibly implement +# faster drawing, but it is already much faster than using draw_lines() +# by itself. +# """ - newstyle = getattr(self, 'draw_markers', None) is not None - identity = transforms.identity_transform() - gc = self.new_gc() - if clipbox is not None: - gc.set_clip_rectangle(clipbox.get_bounds()) - gc.set_dashes(*linestyle) +# newstyle = getattr(self, 'draw_markers', None) is not None +# identity = transforms.identity_transform() +# gc = self.new_gc() +# if clipbox is not None: +# gc.set_clip_rectangle(clipbox.get_bounds()) +# gc.set_dashes(*linestyle) - Nc = len(colors) - Nlw = len(linewidths) - Naa = len(antialiaseds) - Nsegments = len(segments) +# Nc = len(colors) +# Nlw = len(linewidths) +# Naa = len(antialiaseds) +# Nsegments = len(segments) - usingOffsets = offsets is not None - Noffsets = 0 - if usingOffsets: - Noffsets = offsets.shape[0] - offsets = transOffset.numerix_xy(offsets) +# usingOffsets = offsets is not None +# Noffsets = 0 +# if usingOffsets: +# Noffsets = offsets.shape[0] +# offsets = transOffset.numerix_xy(offsets) - for i in xrange(max(Noffsets, Nsegments)): - color = colors[i % Nc] - rgb = color[0], color[1], color[2] - alpha = color[-1] +# for i in xrange(max(Noffsets, Nsegments)): +# color = colors[i % Nc] +# rgb = color[0], color[1], color[2] +# alpha = color[-1] - gc.set_foreground(rgb, isRGB=True) - gc.set_alpha( alpha ) - gc.set_linewidth( linewidths[i % Nlw] ) - gc.set_antialiased( antialiaseds[i % Naa] ) - seg = segments[i % Nsegments] - if not len(seg): continue - xy = transform.numerix_xy(seg) - if usingOffsets: - xy = xy + offsets[i % Noffsets] +# gc.set_foreground(rgb, isRGB=True) +# gc.set_alpha( alpha ) +# gc.set_linewidth( linewidths[i % Nlw] ) +# gc.set_antialiased( antialiaseds[i % Naa] ) +# seg = segments[i % Nsegments] +# if not len(seg): continue +# xy = transform.numerix_xy(seg) +# if usingOffsets: +# xy = xy + offsets[i % Noffsets] - if newstyle: self.draw_lines(gc, xy[:,0], xy[:,1], identity) - else: self.draw_lines(gc, xy[:,0], xy[:,1]) +# if newstyle: self.draw_lines(gc, xy[:,0], xy[:,1], identity) +# else: self.draw_lines(gc, xy[:,0], xy[:,1]) - def draw_line(self, gc, x1, y1, x2, y2): - """ - Draw a single line from x1,y1 to x2,y2 - """ - raise NotImplementedError +# def draw_line(self, gc, x1, y1, x2, y2): +# """ +# Draw a single line from x1,y1 to x2,y2 +# """ +# raise NotImplementedError - def draw_lines(self, gc, x, y, transform=None): - """ - x and y are equal length arrays, draw lines connecting each - point in x, y - """ - raise NotImplementedError +# def draw_lines(self, gc, x, y, transform=None): +# """ +# x and y are equal length arrays, draw lines connecting each +# point in x, y +# """ +# raise NotImplementedError - def draw_point(self, gc, x, y): - """ - Draw a single point at x,y - Where 'point' is a device-unit point (or pixel), not a matplotlib point - """ - raise NotImplementedError +# def draw_point(self, gc, x, y): +# """ +# Draw a single point at x,y +# Where 'point' is a device-unit point (or pixel), not a matplotlib point +# """ +# raise NotImplementedError - def draw_quad_mesh(self, meshWidth, meshHeight, colors, - xCoords, yCoords, clipbox, - transform, offsets, transOffset, showedges): - """ - Draw a quadrilateral mesh - See documentation in QuadMesh class in collections.py for details - """ - # print "draw_quad_mesh not found, using function in backend_bases" - verts = npy.zeros(((meshWidth * meshHeight), 4, 2), npy.float32) - indices = npy.arange((meshWidth + 1) * (meshHeight + 1)) - indices = npy.compress((indices + 1) % (meshWidth + 1), indices) - indices = indices[:(meshWidth * meshHeight)] - verts[:, 0, 0] = npy.take(xCoords, indices) - verts[:, 0, 1] = npy.take(yCoords, indices) - verts[:, 1, 0] = npy.take(xCoords, (indices + 1)) - verts[:, 1, 1] = npy.take(yCoords, (indices + 1)) - verts[:, 2, 0] = npy.take(xCoords, (indices + meshWidth + 2)) - verts[:, 2, 1] = npy.take(yCoords, (indices + meshWidth + 2)) - verts[:, 3, 0] = npy.take(xCoords, (indices + meshWidth + 1)) - verts[:, 3, 1] = npy.take(yCoords, (indices + meshWidth + 1)) - if (showedges): - edgecolors = colors - else: - edgecolors = (0, 0, 0, 0), - self.draw_poly_collection(verts, transform, - clipbox, colors, edgecolors, - (0.25,), (0,), offsets, transOffset) +# def draw_quad_mesh(self, meshWidth, meshHeight, colors, +# xCoords, yCoords, clipbox, +# transform, offsets, transOffset, showedges): +# """ +# Draw a quadrilateral mesh +# See documentation in QuadMesh class in collections.py for details +# """ +# # print "draw_quad_mesh not found, using function in backend_bases" +# verts = npy.zeros(((meshWidth * meshHeight), 4, 2), npy.float32) +# indices = npy.arange((meshWidth + 1) * (meshHeight + 1)) +# indices = npy.compress((indices + 1) % (meshWidth + 1), indices) +# indices = indices[:(meshWidth * meshHeight)] +# verts[:, 0, 0] = npy.take(xCoords, indices) +# verts[:, 0, 1] = npy.take(yCoords, indices) +# verts[:, 1, 0] = npy.take(xCoords, (indices + 1)) +# verts[:, 1, 1] = npy.take(yCoords, (indices + 1)) +# verts[:, 2, 0] = npy.take(xCoords, (indices + meshWidth + 2)) +# verts[:, 2, 1] = npy.take(yCoords, (indices + meshWidth + 2)) +# verts[:, 3, 0] = npy.take(xCoords, (indices + meshWidth + 1)) +# verts[:, 3, 1] = npy.take(yCoords, (indices + meshWidth + 1)) +# if (showedges): +# edgecolors = colors +# else: +# edgecolors = (0, 0, 0, 0), +# self.draw_poly_collection(verts, transform, +# clipbox, colors, edgecolors, +# (0.25,), (0,), offsets, transOffset) - def draw_poly_collection( - self, verts, transform, clipbox, facecolors, edgecolors, - linewidths, antialiaseds, offsets, transOffset): - """ - Draw a polygon collection +# def draw_poly_collection( +# self, verts, transform, clipbox, facecolors, edgecolors, +# linewidths, antialiaseds, offsets, transOffset): +# """ +# Draw a polygon collection - verts are a sequence of polygon vectors, where each polygon - vector is a sequence of x,y tuples of vertices +# verts are a sequence of polygon vectors, where each polygon +# vector is a sequence of x,y tuples of vertices - facecolors and edgecolors are a sequence of RGBA tuples - linewidths are a sequence of linewidths - antialiaseds are a sequence of 0,1 integers whether to use aa +# facecolors and edgecolors are a sequence of RGBA tuples +# linewidths are a sequence of linewidths +# antialiaseds are a sequence of 0,1 integers whether to use aa - If a linewidth is zero or an edgecolor alpha is zero, the - line will be omitted; similarly, the fill will be omitted - if the facecolor alpha is zero. - """ - ## line and/or fill OK - Nface = len(facecolors) - Nedge = len(edgecolors) - Nlw = len(linewidths) - Naa = len(antialiaseds) +# If a linewidth is zero or an edgecolor alpha is zero, the +# line will be omitted; similarly, the fill will be omitted +# if the facecolor alpha is zero. +# """ +# ## line and/or fill OK +# Nface = len(facecolors) +# Nedge = len(edgecolors) +# Nlw = len(linewidths) +# Naa = len(antialiaseds) - usingOffsets = offsets is not None - Noffsets = 0 - Nverts = len(verts) - if usingOffsets: - Noffsets = len(offsets) +# usingOffsets = offsets is not None +# Noffsets = 0 +# Nverts = len(verts) +# if usingOffsets: +# Noffsets = len(offsets) - N = max(Noffsets, Nverts) +# N = max(Noffsets, Nverts) - gc = self.new_gc() - if clipbox is not None: - gc.set_clip_rectangle(clipbox.get_bounds()) +# gc = self.new_gc() +# if clipbox is not None: +# gc.set_clip_rectangle(clipbox.get_bounds()) - for i in xrange(N): - polyverts = ma.filled(verts[i % Nverts], npy.nan) - if npy.any(npy.isnan(polyverts)): - continue - linewidth = linewidths[i % Nlw] - rf,gf,bf,af = facecolors[i % Nface] - re,ge,be,ae = edgecolors[i % Nedge] - if af==0: - if ae==0 or linewidth == 0: - continue - rgbFace = None - alpha = ae - else: - rgbFace = rf,gf,bf - if ae==0: - alpha = af - gc.set_linewidth(0) - else: - # the draw_poly interface can't handle separate alphas for - # edge and face so we'll just use the maximum - alpha = max(af,ae) - gc.set_foreground( (re,ge,be), isRGB=True) - gc.set_linewidth( linewidths[i % Nlw] ) - #print 'verts', zip(thisxverts, thisyverts) +# for i in xrange(N): +# polyverts = ma.filled(verts[i % Nverts], npy.nan) +# if npy.any(npy.isnan(polyverts)): +# continue +# linewidth = linewidths[i % Nlw] +# rf,gf,bf,af = facecolors[i % Nface] +# re,ge,be,ae = edgecolors[i % Nedge] +# if af==0: +# if ae==0 or linewidth == 0: +# continue +# rgbFace = None +# alpha = ae +# else: +# rgbFace = rf,gf,bf +# if ae==0: +# alpha = af +# gc.set_linewidth(0) +# else: +# # the draw_poly interface can't handle separate alphas for +# # edge and face so we'll just use the maximum +# alpha = max(af,ae) +# gc.set_foreground( (re,ge,be), isRGB=True) +# gc.set_linewidth( linewidths[i % Nlw] ) +# #print 'verts', zip(thisxverts, thisyverts) - gc.set_antialiased( antialiaseds[i % Naa] ) # Used for fill only? - gc.set_alpha( alpha ) - tverts = transform.seq_xy_tups(polyverts) - if usingOffsets: - xo,yo = transOffset.xy_tup(offsets[i % Noffsets]) - tverts = [(x+xo,y+yo) for x,y in tverts] +# gc.set_antialiased( antialiaseds[i % Naa] ) # Used for fill only? +# gc.set_alpha( alpha ) +# tverts = transform.seq_xy_tups(polyverts) +# if usingOffsets: +# xo,yo = transOffset.xy_tup(offsets[i % Noffsets]) +# tverts = [(x+xo,y+yo) for x,y in tverts] - self.draw_polygon(gc, rgbFace, tverts) +# self.draw_polygon(gc, rgbFace, tverts) - def draw_polygon(self, gc, rgbFace, points): - """ - Draw a polygon using the GraphicsContext instance gc. - points is a len vertices tuple, each element - giving the x,y coords a vertex +# def draw_polygon(self, gc, rgbFace, points): +# """ +# Draw a polygon using the GraphicsContext instance gc. +# points is a len vertices tuple, each element +# giving the x,y coords a vertex - If the color rgbFace is not None, fill the polygon with it - """ - raise NotImplementedError +# If the color rgbFace is not None, fill the polygon with it +# """ +# raise NotImplementedError - def draw_rectangle(self, gcEdge, rgbFace, x, y, width, height): - """ - Draw a non-filled rectangle using the GraphicsContext instance gcEdge, - with lower left at x,y with width and height. +# def draw_rectangle(self, gcEdge, rgbFace, x, y, width, height): +# """ +# Draw a non-filled rectangle using the GraphicsContext instance gcEdge, +# with lower left at x,y with width and height. - If rgbFace is not None, fill the rectangle with it. - """ - 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) +# If rgbFace is not None, fill the rectangle with it. +# """ +# 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): - """ - Draw a regular poly collection +# def draw_regpoly_collection( +# self, clipbox, offsets, transOffset, verts, sizes, +# facecolors, edgecolors, linewidths, antialiaseds): +# """ +# Draw a regular poly collection - offsets - is a sequence is x,y tuples - transOffset - maps this to display coords +# offsets - is a sequence is x,y tuples +# transOffset - maps this to display coords - verts - are the vertices of the regular polygon at the origin +# verts - are the vertices of the regular polygon at the origin - sizes are the area of the circle that circumscribes the - polygon in points^2 +# sizes are the area of the circle that circumscribes the +# polygon in points^2 - facecolors and edgecolors are a sequence of RGBA tuples - linewidths are a sequence of linewidths - antialiaseds are a sequence of 0,1 integers whether to use aa - """ - ## line and/or fill OK - gc = self.new_gc() - if clipbox is not None: - gc.set_clip_rectangle(clipbox.get_bounds()) +# facecolors and edgecolors are a sequence of RGBA tuples +# linewidths are a sequence of linewidths +# antialiaseds are a sequence of 0,1 integers whether to use aa +# """ +# ## line and/or fill OK +# gc = self.new_gc() +# if clipbox is not None: +# gc.set_clip_rectangle(clipbox.get_bounds()) - xverts, yverts = zip(*verts) - xverts = npy.asarray(xverts) - yverts = npy.asarray(yverts) +# xverts, yverts = zip(*verts) +# xverts = npy.asarray(xverts) +# yverts = npy.asarray(yverts) - Nface = len(facecolors) - Nedge = len(edgecolors) - Nlw = len(linewidths) - Naa = len(antialiaseds) - Nsizes = len(sizes) +# Nface = len(facecolors) +# Nedge = len(edgecolors) +# Nlw = len(linewidths) +# Naa = len(antialiaseds) +# Nsizes = len(sizes) - for i, loc in enumerate(offsets): - xo,yo = transOffset.xy_tup(loc) - #print 'xo, yo', loc, (xo, yo) - scale = sizes[i % Nsizes] +# for i, loc in enumerate(offsets): +# xo,yo = transOffset.xy_tup(loc) +# #print 'xo, yo', loc, (xo, yo) +# scale = sizes[i % Nsizes] - thisxverts = scale*xverts + xo - thisyverts = scale*yverts + yo - #print 'xverts', xverts +# thisxverts = scale*xverts + xo +# thisyverts = scale*yverts + yo +# #print 'xverts', xverts - linewidth = linewidths[i % Nlw] - rf,gf,bf,af = facecolors[i % Nface] - re,ge,be,ae = edgecolors[i % Nedge] - if af==0: - if ae==0 or linewidth == 0: - continue - rgbFace = None - alpha = ae - else: - rgbFace = rf,gf,bf - if ae==0: - alpha = af - gc.set_linewidth(0) - else: - # the draw_poly interface can't handle separate alphas for - # edge and face so we'll just use the maximum - alpha = max(af,ae) - gc.set_foreground( (re,ge,be), isRGB=True) - gc.set_linewidth( linewidths[i % Nlw] ) - #print 'verts', zip(thisxverts, thisyverts) +# linewidth = linewidths[i % Nlw] +# rf,gf,bf,af = facecolors[i % Nface] +# re,ge,be,ae = edgecolors[i % Nedge] +# if af==0: +# if ae==0 or linewidth == 0: +# continue +# rgbFace = None +# alpha = ae +# else: +# rgbFace = rf,gf,bf +# if ae==0: +# alpha = af +# gc.set_linewidth(0) +# else: +# # the draw_poly interface can't handle separate alphas for +# # edge and face so we'll just use the maximum +# alpha = max(af,ae) +# gc.set_foreground( (re,ge,be), isRGB=True) +# gc.set_linewidth( linewidths[i % Nlw] ) +# #print 'verts', zip(thisxverts, thisyverts) - gc.set_antialiased( antialiaseds[i % Naa] ) # Used for fill only? - gc.set_alpha( alpha ) - #print 'verts', zip(thisxverts, thisyverts) - self.draw_polygon(gc, rgbFace, zip(thisxverts, thisyverts)) +# gc.set_antialiased( antialiaseds[i % Naa] ) # Used for fill only? +# gc.set_alpha( alpha ) +# #print 'verts', zip(thisxverts, thisyverts) +# self.draw_polygon(gc, rgbFace, zip(thisxverts, thisyverts)) - def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!'): - raise NotImplementedError +# def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!'): +# raise NotImplementedError - def draw_text(self, gc, x, y, s, prop, angle, ismath=False): - """ - Draw the text.Text instance s at x,y (display coords) with font - properties instance prop at angle in degrees, using GraphicsContext gc +# def draw_text(self, gc, x, y, s, prop, angle, ismath=False): +# """ +# Draw the text.Text instance s at x,y (display coords) with font +# properties instance prop at angle in degrees, using GraphicsContext gc - **backend implementers note** +# **backend implementers note** - When you are trying to determine if you have gotten your bounding box - right (which is what enables the text layout/alignment to work - properly), it helps to change the line in text.py +# When you are trying to determine if you have gotten your bounding box +# right (which is what enables the text layout/alignment to work +# properly), it helps to change the line in text.py - if 0: bbox_artist(self, renderer) +# if 0: bbox_artist(self, renderer) - to if 1, and then the actual bounding box will be blotted along with - your text. - """ - raise NotImplementedError +# to if 1, and then the actual bounding box will be blotted along with +# your text. +# """ +# raise NotImplementedError def flipy(self): """return true if y small numbers are top for renderer @@ -594,6 +594,7 @@ """ Set the clip path and transformation """ + assert path is None or isinstance(path, transforms.TransformedPath) self._clippath = path def set_dashes(self, dash_offset, dash_list): Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -129,6 +129,13 @@ assert marker_trans.is_affine assert trans.is_affine self._renderer.draw_markers(gc, marker_path, marker_trans.frozen(), path, trans.frozen(), rgbFace) + + def draw_path_collection(self, master_transform, clipbox, clippath, clippath_trans, + paths, transforms, facecolors, edgecolors, linewidths, linestyles, antialiaseds): + assert master_transform.is_affine + self._renderer.draw_path_collection( + master_transform.frozen(), clipbox, clippath, clippath_trans, + paths, transforms, facecolors, edgecolors, linewidths, linestyles, antialiaseds) def draw_mathtext(self, gc, x, y, s, prop, angle): """ Modified: branches/transforms/lib/matplotlib/cbook.py =================================================================== --- branches/transforms/lib/matplotlib/cbook.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/cbook.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -981,12 +981,16 @@ >>> g.joined('a', 'c') True >>> g.joined('a', 'd') - False""" + False + """ def __init__(self, init=[]): mapping = self._mapping = {} for x in init: mapping[x] = [x] - + + def __contains__(self, item): + return item in self._mapping + def join(self, a, *args): """ Join given arguments into the same set. @@ -1019,7 +1023,7 @@ def __iter__(self): """ - Returns an iterator returning each of the disjoint sets as a list. + Returns an iterator yielding each of the disjoint sets as a list. """ seen = set() for elem, group in self._mapping.iteritems(): Modified: branches/transforms/lib/matplotlib/collections.py =================================================================== --- branches/transforms/lib/matplotlib/collections.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/collections.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -17,7 +17,11 @@ import matplotlib.artist as artist import matplotlib.backend_bases as backend_bases import matplotlib.nxutils as nxutils +import matplotlib.path as path +# MGDTODO: Now that everything draws through draw_path_collection, +# perhaps more stuff could be moved into the Collection base class +# here class Collection(artist.Artist): """ @@ -616,9 +620,10 @@ linewidths = None, colors = None, antialiaseds = None, - linestyle = 'solid', - offsets = None, - transOffset = None,#transforms.identity_transform(), + linestyles = 'solid', + # MGDTODO: Deal with offsets (mayb +# offsets = None, +# transOffset = None,#transforms.identity_transform(), norm = None, cmap = None, pickradius = 5, @@ -663,13 +668,11 @@ matrix _A is not None (ie a call to set_array has been made), at draw time a call to scalar mappable will be made to set the colors. """ - Collection.__init__(self) cm.ScalarMappable.__init__(self, norm, cmap) if linewidths is None : linewidths = (mpl.rcParams['lines.linewidth'], ) - if colors is None : colors = (mpl.rcParams['lines.color'],) if antialiaseds is None : @@ -678,19 +681,20 @@ self._colors = _colors.colorConverter.to_rgba_list(colors) self._aa = self._get_value(antialiaseds) self._lw = self._get_value(linewidths) - self.set_linestyle(linestyle) + self.set_linestyles(linestyles) self._uniform_offsets = None - if offsets is not None: - offsets = npy.asarray(offsets) - if len(offsets.shape) == 1: - offsets = offsets[npy.newaxis,:] # Make it Nx2. - if transOffset is None: - if offsets is not None: - self._uniform_offsets = offsets - offsets = None - transOffset = transforms.identity_transform() - self._offsets = offsets - self._transOffset = transOffset + # MGDTODO: Deal with offsets +# if offsets is not None: +# offsets = npy.asarray(offsets) +# if len(offsets.shape) == 1: +# offsets = offsets[npy.newaxis,:] # Make it Nx2. +# if transOffset is None: +# if offsets is not None: +# self._uniform_offsets = offsets +# offsets = None +# transOffset = transforms.IdentityTransform() +# self._offsets = offsets +# self._transOffset = transOffset self.set_segments(segments) self.pickradius = pickradius self.update(kwargs) @@ -712,9 +716,10 @@ mx,my = mouseevent.x,mouseevent.y transform = self.get_transform() + # MGDTODO: Numpify ind = [] for this in xrange(len(self._segments)): - xy = transform.seq_xy_tups(self._segments[this]) + xy = transform.transform_point(self._segments[this]) this_ind = ML.segment_hits(mx,my,xy[:,0],xy[:,1],self.pickradius) ind.extend([(this,k) for k in this_ind]) return len(ind)>0,dict(ind=ind) @@ -722,45 +727,47 @@ def set_pickradius(self,pickradius): self.pickradius = 5 def get_pickradius(self): return self.pickradius - def get_transoffset(self): - if self._transOffset is None: - self._transOffset = transforms.identity_transform() - return self._transOffset + # MGDTODO: Support offsets (maybe) +# def get_transoffset(self): +# if self._transOffset is None: +# self._transOffset = transforms.identity_transform() +# return self._transOffset def set_segments(self, segments): if segments is None: return - self._segments = [npy.asarray(seg) for seg in segments] - if self._uniform_offsets is not None: - self._add_offsets() + self._paths = [path.Path(seg, closed=False) for seg in segments] + +# if self._uniform_offsets is not None: +# self._add_offsets() set_verts = set_segments # for compatibility with PolyCollection - def _add_offsets(self): - segs = self._segments - offsets = self._uniform_offsets - Nsegs = len(segs) - Noffs = offsets.shape[0] - if Noffs == 1: - for i in range(Nsegs): - segs[i] = segs[i] + i * offsets - else: - for i in range(Nsegs): - io = i%Noffs - segs[i] = segs[i] + offsets[io:io+1] + # MGDTODO: Support offsets (maybe) +# def _add_offsets(self): +# segs = self._segments +# offsets = self._uniform_offsets +# Nsegs = len(segs) +# Noffs = offsets.shape[0] +# if Noffs == 1: +# for i in range(Nsegs): +# segs[i] = segs[i] + i * offsets +# else: +# for i in range(Nsegs): +# io = i%Noffs +# segs[i] = segs[i] + offsets[io:io+1] - def draw(self, renderer): if not self.get_visible(): return renderer.open_group('linecollection') transform = self.get_transform() - transoffset = self.get_transoffset() + # MGDTODO: Deal with offsets (maybe) +# transoffset = self.get_transoffset() - transform.freeze() - transoffset.freeze() + # segments = self._segments + # MGDTODO: Deal with offsets (maybe) + # offsets = self._offsets - segments = self._segments - offsets = self._offsets - + # MGDTODO: Transform the paths (since we don't keep track of segments anymore if self.have_units(): segments = [] for segment in self._segments: @@ -768,20 +775,18 @@ xs = self.convert_xunits(xs) ys = self.convert_yunits(ys) segments.append(zip(xs, ys)) - if self._offsets is not None: - xs = self.convert_xunits(self._offsets[:0]) - ys = self.convert_yunits(self._offsets[:1]) - offsets = zip(xs, ys) - +# if self._offsets is not None: +# xs = self.convert_xunits(self._offsets[:0]) +# ys = self.convert_yunits(self._offsets[:1]) +# offsets = zip(xs, ys) + self.update_scalarmappable() #print 'calling renderer draw line collection' - renderer.draw_line_collection( - segments, transform, self.clipbox, - self._colors, self._lw, self._ls, self._aa, offsets, - transoffset) - transform.thaw() - transoffset.thaw() - + clippath, clippath_trans = self.get_transformed_clip_path_and_affine() + renderer.draw_path_collection( + transform, self.clipbox, clippath, clippath_trans, + self._paths, [None], [None], + self._colors, self._lw, self._ls, self._aa) renderer.close_group('linecollection') def set_linewidth(self, lw): @@ -795,18 +800,34 @@ self._lw = self._get_value(lw) - def set_linestyle(self, ls): + def set_linestyles(self, ls): """ Set the linestyles(s) for the collection. ACCEPTS: ['solid' | 'dashed', 'dashdot', 'dotted' | (offset, on-off-dash-seq) ] """ - if cbook.is_string_like(ls): - dashes = backend_bases.GraphicsContextBase.dashd[ls] - elif cbook.iterable(ls) and len(ls)==2: - dashes = ls - else: raise ValueError('Do not know how to convert %s to dashes'%ls) + try: + if cbook.is_string_like(ls): + dashes = [backend_bases.GraphicsContextBase.dashd[ls]] + elif cbook.iterable(ls): + try: + dashes = [] + for x in ls: + if cbook.is_string_like(x): + dashes.append(backend_bases.GraphicsContextBase.dashd[ls]) + elif cbook.iterator(x) and len(x) == 2: + dashes.append(x) + else: + raise ValueError() + except ValueError: + if len(ls)==2: + dashes = ls + else: + raise ValueError() + else: + raise ValueError() + except ValueError: + raise ValueError('Do not know how to convert %s to dashes'%ls) - self._ls = dashes def set_color(self, c): @@ -860,23 +881,6 @@ return self._colors get_colors = get_color # for compatibility with old versions - def get_verts(self, dataTrans=None): - '''Return vertices in data coordinates. - The calculation is incomplete in general; it is based - on the segments or the offsets, whichever is using - dataTrans as its transformation, so it does not take - into account the combined effect of segments and offsets. - ''' - verts = [] - if self._offsets is None: - for seg in self._segments: - verts.extend(seg) - return [tuple(xy) for xy in verts] - if self.get_transoffset() == dataTrans: - return [tuple(xy) for xy in self._offsets] - raise NotImplementedError('Vertices in data coordinates are calculated\n' - + 'with offsets only if _transOffset == dataTrans.') - def update_scalarmappable(self): """ If the scalar mappable array is not none, update colors Modified: branches/transforms/lib/matplotlib/image.py =================================================================== --- branches/transforms/lib/matplotlib/image.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/image.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -181,7 +181,6 @@ if not self.get_visible(): return im = self.make_image(renderer.get_image_magnification()) l, b, widthDisplay, heightDisplay = self.axes.bbox.bounds - print self.axes.bbox.frozen() renderer.draw_image(l, b, im, self.axes.bbox.frozen()) def contains(self, mouseevent): Modified: branches/transforms/lib/matplotlib/legend.py =================================================================== --- branches/transforms/lib/matplotlib/legend.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/legend.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -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 transforms import Bbox, BboxTransform +from transforms import Affine2D, Bbox, BboxTransform def line_cuts_bbox(line, bbox): """ Return True if and only if line cuts bbox. """ @@ -164,8 +164,9 @@ else: raise TypeError("Legend needs either Axes or Figure as parent") self.parent = parent - self.set_transform( BboxTransform(Bbox.unit(), parent.bbox) ) - + self._offsetTransform = Affine2D() + self.set_transform( self._offsetTransform + BboxTransform(Bbox.unit(), parent.bbox) ) + if loc is None: loc = rcParams["legend.loc"] if not self.isaxes and loc in [0,'best']: @@ -429,24 +430,8 @@ def _offset(self, ox, oy): 'Move all the artists by ox,oy (axes coords)' - for t in self.texts: - x,y = t.get_position() - t.set_position( (x+ox, y+oy) ) + self._offsetTransform.clear().translate(ox, oy) - for h in self.legendHandles: - if isinstance(h, Line2D): - x,y = h.get_xdata(orig=False), h.get_ydata(orig=False) - h.set_data( x+ox, y+oy) - elif isinstance(h, Rectangle): - h.xy[0] = h.xy[0] + ox - h.xy[1] = h.xy[1] + oy - elif isinstance(h, RegularPolygon): - h.verts = [(x + ox, y + oy) for x, y in h.verts] - - x, y = self.legendPatch.get_x(), self.legendPatch.get_y() - self.legendPatch.set_x(x+ox) - self.legendPatch.set_y(y+oy) - def _find_best_position(self, width, height, consider=None): """Determine the best location to place the legend. Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/lines.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -349,6 +349,7 @@ self._picker = p def get_window_extent(self, renderer): + # MGDTODO: Numpify xy = self.get_transform().transform(self._xy) x = xy[:, 0] @@ -690,7 +691,7 @@ def _draw_pixel(self, renderer, gc, path, path_trans): rgbFace = self._get_rgb_face() transform = Affine2D().translate(-0.5, -0.5) - renderer.draw_markers(gc, Path.unit_rectangle, transform, + renderer.draw_markers(gc, Path.unit_rectangle(), transform, path, path_trans, rgbFace) Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/patches.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -221,8 +221,11 @@ path = self.get_path() transform = self.get_transform() - - renderer.draw_path(gc, path, transform, rgbFace) + # MGDTODO: Use a transformed path here? + tpath = transform.transform_path_non_affine(path) + affine = transform.get_affine() + + renderer.draw_path(gc, tpath, affine, rgbFace) #renderer.close_group('patch') @@ -234,8 +237,7 @@ def get_window_extent(self, renderer=None): - return Bbox.from_lbrt( - get_path_extents(self.get_path(), self.get_patch_transform())) + return self.get_path().get_extents(self.get_transform()) def set_lw(self, val): @@ -441,21 +443,49 @@ Valid kwargs are: %(Patch)s """ + self._xy = xy + self._orientation = orientation + self._radius = radius + self._path = Path.unit_regular_polygon(numVertices) + self._poly_transform = transforms.Affine2D() + self._update_transform() + Patch.__init__(self, **kwargs) + + __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd - self._path = Path.unit_regular_polygon(numVertices) - self._poly_transform = transforms.Affine2D() \ - .scale(radius) \ - .rotate(orientation) \ - .translate(*xy) + def _update_transform(self): + self._poly_transform.clear() \ + .scale(self.radius) \ + .rotate(self.orientation) \ + .translate(*self.xy) - __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd + def _get_xy(self): + return self._xy + def _set_xy(self, xy): + self._xy = xy + self._update_transform() + xy = property(_get_xy, _set_xy) + def _get_orientation(self): + return self._orientation + def _set_orientation(self, xy): + self._orientation = xy + self._update_transform() + orientation = property(_get_orientation, _set_orientation) + + def _get_radius(self): + return self._radius + def _set_radius(self, xy): + self._radius = xy + self._update_transform() + radius = property(_get_radius, _set_radius) + def get_path(self): return self._path def get_patch_transform(self): - return self._poly_transform + return self._poly_transform class Polygon(Patch): """ @@ -492,10 +522,8 @@ """ Patch.__init__(self, **kwargs) - self.theta1 = theta1 - self.theta2 = theta2 self._path = Path.wedge(theta1, theta2) - self._path_transform = transforms.Affine2D() \ + self._patch_transform = transforms.Affine2D() \ .scale(r).translate(*center) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd @@ -503,7 +531,7 @@ return self._path def get_patch_transform(self): - return self._path_transform + return self._patch_transform class Arrow(Polygon): """ @@ -515,6 +543,12 @@ cx,cy = (x1+x2)/2.,(y1+y2)/2. return "Arrow(%g,%g)"%(cx,cy) + _path = Path( [ + [ 0.0, 0.1 ], [ 0.0, -0.1], + [ 0.8, -0.1 ], [ 0.8, -0.3], + [ 1.0, 0.0 ], [ 0.8, 0.3], + [ 0.8, 0.1 ] ] ) + def __init__( self, x, y, dx, dy, width=1.0, **kwargs ): """Draws an arrow, starting at (x,y), direction and length given by (dx,dy) the width of the arrow is scaled by width @@ -522,22 +556,23 @@ 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], - [ 1.0, 0.0 ], [ 0.8, 0.3], - [ 0.8, 0.1 ] ] ) L = npy.sqrt(dx**2+dy**2) or 1 # account for div by zero - arrow[:,0] *= L - arrow[:,1] *= width cx = float(dx)/L sx = float(dy)/L - M = npy.array( [ [ cx, sx],[ -sx, cx ] ] ) - verts = npy.dot( arrow, M )+ [x,y] - Polygon.__init__( self, [ tuple(t) for t in verts ], **kwargs ) + + trans1 = transforms.Affine2D().scale(L, width) + trans2 = transforms.Affine2D.from_values(cx, sx, -sx, cx, 0.0, 0.0) + trans3 = transforms.Affine2d().translate(x, y) + trans = trans1 + trans2 + trans3 + self._patch_transform = trans.frozen() __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd + def get_path(self): + return self._path + + def get_patch_transform(self): + return self._patch_transform + class FancyArrow(Polygon): """Like Arrow, but lets you set head width and head height independently.""" @@ -614,7 +649,7 @@ Polygon.__init__(self, map(tuple, verts), **kwargs) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd -class YAArrow(Polygon): +class YAArrow(Patch): """ Yet another arrow class @@ -640,25 +675,25 @@ %(Patch)s """ - # MGDTODO: Implement me self.dpi = dpi self.xytip = xytip self.xybase = xybase self.width = width self.frac = frac self.headwidth = headwidth - verts = self.get_verts() - Polygon.__init__(self, verts, **kwargs) + Patch.__init__(self, **kwargs) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd - - - def get_verts(self): + 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...) + # the base vertices x1, y1 = self.xytip x2, y2 = self.xybase - k1 = self.width*self.dpi.get()/72./2. - k2 = self.headwidth*self.dpi.get()/72./2. + k1 = self.width*self.dpi/72./2. + k2 = self.headwidth*self.dpi/72./2. xb1, yb1, xb2, yb2 = self.getpoints(x1, y1, x2, y2, k1) # a point on the segment 20% of the distance from the tip to the base @@ -669,12 +704,14 @@ xc1, yc1, xc2, yc2 = self.getpoints(x1, y1, xm, ym, k1) xd1, yd1, xd2, yd2 = self.getpoints(x1, y1, xm, ym, k2) - xs = self.convert_xunits([xb1, xb2, xc2, xd2, x1, xd1, xc1]) ys = self.convert_yunits([yb1, yb2, yc2, yd2, y1, yd1, yc1]) - return zip(xs, ys) + return Path(zip(xs, ys)) + def get_patch_transform(self): + return transforms.IdentityTransform() + def getpoints(self, x1,y1,x2,y2, k): """ for line segment defined by x1,y1 and x2,y2, return the points on Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/path.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -87,12 +87,14 @@ vertices = ma.asarray(vertices, npy.float_) if codes is None: - if closed: + if len(vertices) == 0: + codes = npy.zeros((0, ), self.code_type) + elif closed: codes = self.LINETO * npy.ones( vertices.shape[0] + 1, self.code_type) codes[0] = self.MOVETO - codes[-1] = self.CLOSEPOLY - vertices = npy.concatenate((vertices, [[0.0, 0.0]])) + codes[-1] = self.LINETO + vertices = npy.concatenate((vertices, [vertices[0]])) else: codes = self.LINETO * npy.ones( vertices.shape[0], self.code_type) @@ -187,9 +189,9 @@ algorithm will take into account the curves and deal with control points appropriately. """ - from transforms import Bbox, IdentityTransform + from transforms import Affine2D, Bbox if transform is None: - transform = IdentityTransform + transform = Affine2D() return Bbox.from_lbrt(*get_path_extents(self, transform)) def i... [truncated message content] |