## matplotlib-checkins

 SF.net SVN: matplotlib:[5864] trunk/matplotlib/lib/matplotlib/quiver.py From: - 2008-07-25 03:53:22 ```Revision: 5864 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5864&view=rev Author: efiring Date: 2008-07-25 03:53:18 +0000 (Fri, 25 Jul 2008) Log Message: ----------- Fix quiver whitespace Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/quiver.py Modified: trunk/matplotlib/lib/matplotlib/quiver.py =================================================================== --- trunk/matplotlib/lib/matplotlib/quiver.py 2008-07-25 03:41:21 UTC (rev 5863) +++ trunk/matplotlib/lib/matplotlib/quiver.py 2008-07-25 03:53:18 UTC (rev 5864) @@ -5,8 +5,8 @@ direction of the vector, with the size of the arrow related to the magnitude of the vector. -Barbs are like quiver in that they point along a vector, but -the magnitude of the vector is given schematically by the presence of barbs +Barbs are like quiver in that they point along a vector, but +the magnitude of the vector is given schematically by the presence of barbs or flags on the barb. This will also become a home for things such as standard @@ -23,7 +23,7 @@ import matplotlib.artist as martist import matplotlib.font_manager as font_manager from matplotlib.cbook import delete_masked_points -from matplotlib.patches import CirclePolygon +from matplotlib.patches import CirclePolygon import math @@ -506,63 +506,63 @@ quiver_doc = _quiver_doc -_barbs_doc = """ -Plot a 2-D field of barbs. - -call signatures:: - - barb(U, V, **kw) - barb(U, V, C, **kw) - barb(X, Y, U, V, **kw) - barb(X, Y, U, V, C, **kw) - -Arguments: - - *X*, *Y*: - The x and y coordinates of the barb locations - (default is head of barb; see *pivot* kwarg) - - *U*, *V*: - give the *x* and *y* components of the barb shaft - - *C*: - an optional array used to map colors to the barbs - -All arguments may be 1-D or 2-D arrays or sequences. If *X* and *Y* -are absent, they will be generated as a uniform grid. If *U* and *V* -are 2-D arrays but *X* and *Y* are 1-D, and if len(*X*) and len(*Y*) -match the column and row dimensions of *U*, then *X* and *Y* will be -expanded with :func:`numpy.meshgrid`. - -*U*, *V*, *C* may be masked arrays, but masked *X*, *Y* are not -supported at present. - -Keyword arguments: - - *length*: - Length of the barb in points; the other parts of the barb - are scaled against this. - Default is 9 - - *pivot*: [ 'tip' | 'middle' ] - The part of the arrow that is at the grid point; the arrow +_barbs_doc = """ +Plot a 2-D field of barbs. + +call signatures:: + + barb(U, V, **kw) + barb(U, V, C, **kw) + barb(X, Y, U, V, **kw) + barb(X, Y, U, V, C, **kw) + +Arguments: + + *X*, *Y*: + The x and y coordinates of the barb locations + (default is head of barb; see *pivot* kwarg) + + *U*, *V*: + give the *x* and *y* components of the barb shaft + + *C*: + an optional array used to map colors to the barbs + +All arguments may be 1-D or 2-D arrays or sequences. If *X* and *Y* +are absent, they will be generated as a uniform grid. If *U* and *V* +are 2-D arrays but *X* and *Y* are 1-D, and if len(*X*) and len(*Y*) +match the column and row dimensions of *U*, then *X* and *Y* will be +expanded with :func:`numpy.meshgrid`. + +*U*, *V*, *C* may be masked arrays, but masked *X*, *Y* are not +supported at present. + +Keyword arguments: + + *length*: + Length of the barb in points; the other parts of the barb + are scaled against this. + Default is 9 + + *pivot*: [ 'tip' | 'middle' ] + The part of the arrow that is at the grid point; the arrow rotates about this point, hence the name *pivot*. - Default is 'tip' - - *barbcolor*: [ color | color sequence ] - Specifies the color all parts of the barb except any flags. - This parameter is analagous to the *edgecolor* parameter - for polygons, which can be used instead. However this parameter - will override facecolor. - - *flagcolor*: [ color | color sequence ] - Specifies the color of any flags on the barb. - This parameter is analagous to the *facecolor* parameter - for polygons, which can be used instead. However this parameter - will override facecolor. If this is not set (and *C* has not either) - then *flagcolor* will be set to match *barbcolor* so that the barb - has a uniform color. If *C* has been set, *flagcolor* has no effect. - + Default is 'tip' + + *barbcolor*: [ color | color sequence ] + Specifies the color all parts of the barb except any flags. + This parameter is analagous to the *edgecolor* parameter + for polygons, which can be used instead. However this parameter + will override facecolor. + + *flagcolor*: [ color | color sequence ] + Specifies the color of any flags on the barb. + This parameter is analagous to the *facecolor* parameter + for polygons, which can be used instead. However this parameter + will override facecolor. If this is not set (and *C* has not either) + then *flagcolor* will be set to match *barbcolor* so that the barb + has a uniform color. If *C* has been set, *flagcolor* has no effect. + *sizes*: A dictionary of coefficients specifying the ratio of a given feature to the length of the barb. Only those values one wishes to override @@ -576,7 +576,7 @@ A flag on whether the empty barbs (circles) that are drawn should be filled with the flag color. If they are not filled, they will be drawn such that no color is applied to the center. - Default is False + Default is False *rounding*: A flag to indicate whether the vector magnitude should be rounded when @@ -588,7 +588,7 @@ *barb_increments*: A dictionary of increments specifying values to associate with different parts of the barb. Only those values one wishes to override need to be - included. + included. 'half' - half barbs (Default is 5) 'full' - full barbs (Default is 10) 'flag' - flags (default is 50) @@ -602,66 +602,66 @@ wind barbs having these features point towards low pressure in the Northern Hemisphere.) Default is False - -Barbs are traditionally used in meteorology as a way to plot the speed -and direction of wind observations, but can technically be used to plot -any two dimensional vector quantity. As opposed to arrows, which give -vector magnitude by the length of the arrow, the barbs give more quantitative -information about the vector magnitude by putting slanted lines or a triangle -for various increments in magnitude, as show schematically below: - - /\ \ - / \ \ - / \ \ \ -/ \ \ \ ------------------------------- - + +Barbs are traditionally used in meteorology as a way to plot the speed +and direction of wind observations, but can technically be used to plot +any two dimensional vector quantity. As opposed to arrows, which give +vector magnitude by the length of the arrow, the barbs give more quantitative +information about the vector magnitude by putting slanted lines or a triangle +for various increments in magnitude, as show schematically below: + + /\ \ + / \ \ + / \ \ \ +/ \ \ \ +------------------------------ + The largest increment is given by a triangle (or "flag"). After those come full -lines (barbs). The smallest increment is a half line. There is only, of -course, ever at most 1 half line. If the magnitude is small and only needs a -single half-line and no full lines or triangles, the half-line is offset from -the end of the barb so that it can be easily distinguished from barbs with a -single full line. The magnitude for the barb shown above would nominally be -65, using the standard increments of 50, 10, and 5. - -linewidths and edgecolors can be used to customize the barb. -Additional :class:`~matplotlib.collections.PolyCollection` -keyword arguments: - -%(PolyCollection)s -""" % martist.kwdocd +lines (barbs). The smallest increment is a half line. There is only, of +course, ever at most 1 half line. If the magnitude is small and only needs a +single half-line and no full lines or triangles, the half-line is offset from +the end of the barb so that it can be easily distinguished from barbs with a +single full line. The magnitude for the barb shown above would nominally be +65, using the standard increments of 50, 10, and 5. -class Barbs(collections.PolyCollection): - ''' - Specialized PolyCollection for barbs. - +linewidths and edgecolors can be used to customize the barb. +Additional :class:`~matplotlib.collections.PolyCollection` +keyword arguments: + +%(PolyCollection)s +""" % martist.kwdocd + +class Barbs(collections.PolyCollection): + ''' + Specialized PolyCollection for barbs. + The only API method is set_UVC(), which can be used to change the size, orientation, and color of the arrows. Locations are changed using the set_offsets() collection method.Possibly this method will be useful in animations. - - There is one internal function _find_tails() which finds exactly - what should be put on the barb given the vector magnitude. From there - _make_barbs() is used to find the vertices of the polygon to represent the - barb based on this information. - ''' - #This may be an abuse of polygons here to render what is essentially maybe - #1 triangle and a series of lines. It works fine as far as I can tell - #however. - def __init__(self, ax, *args, **kw): - self._pivot = kw.pop('pivot', 'tip') - self._length = kw.pop('length', 7) - barbcolor = kw.pop('barbcolor', None) - flagcolor = kw.pop('flagcolor', None) + + There is one internal function _find_tails() which finds exactly + what should be put on the barb given the vector magnitude. From there + _make_barbs() is used to find the vertices of the polygon to represent the + barb based on this information. + ''' + #This may be an abuse of polygons here to render what is essentially maybe + #1 triangle and a series of lines. It works fine as far as I can tell + #however. + def __init__(self, ax, *args, **kw): + self._pivot = kw.pop('pivot', 'tip') + self._length = kw.pop('length', 7) + barbcolor = kw.pop('barbcolor', None) + flagcolor = kw.pop('flagcolor', None) self.sizes = kw.pop('sizes', dict()) self.fill_empty = kw.pop('fill_empty', False) self.barb_increments = kw.pop('barb_increments', dict()) self.rounding = kw.pop('rounding', True) self.flip = kw.pop('flip_barb', False) - #Flagcolor and and barbcolor provide convenience parameters for setting - #the facecolor and edgecolor, respectively, of the barb polygon. We - #also work here to make the flag the same color as the rest of the barb + #Flagcolor and and barbcolor provide convenience parameters for setting + #the facecolor and edgecolor, respectively, of the barb polygon. We + #also work here to make the flag the same color as the rest of the barb #by default if None in (barbcolor, flagcolor): kw['edgecolors'] = 'face' @@ -671,109 +671,109 @@ kw['facecolors'] = barbcolor else: #Set to facecolor passed in or default to black - kw.setdefault('facecolors', 'k') + kw.setdefault('facecolors', 'k') else: kw['edgecolors'] = barbcolor kw['facecolors'] = flagcolor - - #Parse out the data arrays from the various configurations supported + + #Parse out the data arrays from the various configurations supported x, y, u, v, c = self._parse_args(*args) self.x = x - self.y = y - xy = np.hstack((x[:,np.newaxis], y[:,np.newaxis])) + self.y = y + xy = np.hstack((x[:,np.newaxis], y[:,np.newaxis])) - #Make a collection + #Make a collection barb_size = self._length**2 / 4 #Empirically determined collections.PolyCollection.__init__(self, [], (barb_size,), offsets=xy, - transOffset=ax.transData, **kw) - self.set_transform(transforms.IdentityTransform()) + transOffset=ax.transData, **kw) + self.set_transform(transforms.IdentityTransform()) self.set_UVC(u, v, c) - - __init__.__doc__ = """ - The constructor takes one required argument, an Axes - instance, followed by the args and kwargs described - by the following pylab interface documentation: - %s""" % _barbs_doc - - def _find_tails(self, mag, rounding=True, half=5, full=10, flag=50): + + __init__.__doc__ = """ + The constructor takes one required argument, an Axes + instance, followed by the args and kwargs described + by the following pylab interface documentation: + %s""" % _barbs_doc + + def _find_tails(self, mag, rounding=True, half=5, full=10, flag=50): '''Find how many of each of the tail pieces is necessary. Flag specifies the increment for a flag, barb for a full barb, and half for - half a barb. Mag should be the magnitude of a vector (ie. >= 0). - - This returns a tuple of: - (number of flags, number of barbs, half_flag, empty_flag) - half_flag is a boolean whether half of a barb is needed, since there + half a barb. Mag should be the magnitude of a vector (ie. >= 0). + + This returns a tuple of: + (number of flags, number of barbs, half_flag, empty_flag) + half_flag is a boolean whether half of a barb is needed, since there should only ever be one half on a given barb. Empty flag is an array of flags to easily tell if a barb is empty (too low to plot any - barbs/flags.''' + barbs/flags.''' #If rounding, round to the nearest multiple of half, the smallest #increment if rounding: mag = half * (mag / half + 0.5).astype(np.int) - - num_flags = np.floor(mag / flag).astype(np.int) - mag = np.mod(mag, flag) - - num_barb = np.floor(mag / full).astype(np.int) - mag = np.mod(mag, full) - + + num_flags = np.floor(mag / flag).astype(np.int) + mag = np.mod(mag, flag) + + num_barb = np.floor(mag / full).astype(np.int) + mag = np.mod(mag, full) + half_flag = mag >= half empty_flag = ~(half_flag | (num_flags > 0) | (num_barb > 0)) - - return num_flags, num_barb, half_flag, empty_flag - + + return num_flags, num_barb, half_flag, empty_flag + def _make_barbs(self, u, v, nflags, nbarbs, half_barb, empty_flag, length, - pivot, sizes, fill_empty, flip): + pivot, sizes, fill_empty, flip): '''This function actually creates the wind barbs. u and v are components of the vector in the x and y directions, respectively. nflags, nbarbs, and half_barb, empty_flag are, respectively, the number of flags, number of barbs, flag for half a barb, and flag for empty - barb, ostensibly obtained from _find_tails. length is the length of - the barb staff in points. pivot specifies the point on the barb around - which the entire barb should be rotated. Right now valid options are + barb, ostensibly obtained from _find_tails. length is the length of + the barb staff in points. pivot specifies the point on the barb around + which the entire barb should be rotated. Right now valid options are 'head' and 'middle'. sizes is a dictionary of coefficients specifying the ratio of a given feature to the length of the barb. These features include: - + spacing - space between features (flags, full/half barbs) height - height (distance from shaft of top) of a flag or full barb width - width of a flag, twice the width of a full barb - emptybarb - radius of the circle used for low magnitudes - + emptybarb - radius of the circle used for low magnitudes + fill_empty specifies whether the circle representing an empty barb should be filled or not (this changes the drawing of the polygon). flip is a flag indicating whether the features should be flipped to the other side of the barb (useful for winds in the southern hemisphere. - - This function returns list of arrays of vertices, defining a polygon for - each of the wind barbs. These polygons have been rotated to properly + + This function returns list of arrays of vertices, defining a polygon for + each of the wind barbs. These polygons have been rotated to properly align with the vector direction.''' - - #These control the spacing and size of barb elements relative to the - #length of the shaft - spacing = length * sizes.get('spacing', 0.125) - full_height = length * sizes.get('height', 0.4) + + #These control the spacing and size of barb elements relative to the + #length of the shaft + spacing = length * sizes.get('spacing', 0.125) + full_height = length * sizes.get('height', 0.4) full_width = length * sizes.get('width', 0.25) - empty_rad = length * sizes.get('emptybarb', 0.15) - - #Controls y point where to pivot the barb. - pivot_points = dict(tip=0.0, middle=-length/2.) + empty_rad = length * sizes.get('emptybarb', 0.15) + #Controls y point where to pivot the barb. + pivot_points = dict(tip=0.0, middle=-length/2.) + #Check for flip if flip: full_height = -full_height - - endx = 0.0 - endy = pivot_points[pivot.lower()] - - #Get the appropriate angle for the vector components. The offset is due - #to the way the barb is initially drawn, going down the y-axis. This - #makes sense in a meteorological mode of thinking since there 0 degrees - #corresponds to north (the y-axis traditionally) - angles = -(ma.arctan2(v, u) + np.pi/2) - + + endx = 0.0 + endy = pivot_points[pivot.lower()] + + #Get the appropriate angle for the vector components. The offset is due + #to the way the barb is initially drawn, going down the y-axis. This + #makes sense in a meteorological mode of thinking since there 0 degrees + #corresponds to north (the y-axis traditionally) + angles = -(ma.arctan2(v, u) + np.pi/2) + #Used for low magnitude. We just get the vertices, so if we make it #out here, it can be reused. The center set here should put the #center of the circle at the location(offset), rather than at the @@ -784,7 +784,7 @@ else: #If we don't want the empty one filled, we make a degenerate polygon #that wraps back over itself - empty_barb = np.concatenate((circ, circ[::-1])) + empty_barb = np.concatenate((circ, circ[::-1])) barb_list = [] for index, angle in np.ndenumerate(angles): @@ -795,77 +795,77 @@ #orientation barb_list.append(empty_barb) continue - - poly_verts = [(endx, endy)] - offset = length - - #Add vertices for each flag - for i in range(nflags[index]): + + poly_verts = [(endx, endy)] + offset = length + + #Add vertices for each flag + for i in range(nflags[index]): #The spacing that works for the barbs is a little to much for - #the flags, but this only occurs when we have more than 1 flag. - if offset != length: offset += spacing / 2. - poly_verts.extend([[endx, endy + offset], - [endx + full_height, endy - full_width/2 + offset], - [endx, endy - full_width + offset]]) - - offset -= full_width + spacing - + #the flags, but this only occurs when we have more than 1 flag. + if offset != length: offset += spacing / 2. + poly_verts.extend([[endx, endy + offset], + [endx + full_height, endy - full_width/2 + offset], + [endx, endy - full_width + offset]]) + + offset -= full_width + spacing + #Add vertices for each barb. These really are lines, but works #great adding 3 vertices that basically pull the polygon out and - #back down the line - for i in range(nbarbs[index]): - poly_verts.extend([(endx, endy + offset), - (endx + full_height, endy + offset + full_width/2), - (endx, endy + offset)]) - - offset -= spacing - - #Add the vertices for half a barb, if needed - if half_barb[index]: - #If the half barb is the first on the staff, traditionally it is - #offset from the end to make it easy to distinguish from a barb - #with a full one - if offset == length: - poly_verts.append((endx, endy + offset)) - offset -= 1.5 * spacing - poly_verts.extend([(endx, endy + offset), - (endx + full_height/2, endy + offset + full_width/4), - (endx, endy + offset)]) - - #Rotate the barb according the angle. Making the barb first and then - #rotating it made the math for drawing the barb really easy. Also, - #the transform framework makes doing the rotation simple. + #back down the line + for i in range(nbarbs[index]): + poly_verts.extend([(endx, endy + offset), + (endx + full_height, endy + offset + full_width/2), + (endx, endy + offset)]) + + offset -= spacing + + #Add the vertices for half a barb, if needed + if half_barb[index]: + #If the half barb is the first on the staff, traditionally it is + #offset from the end to make it easy to distinguish from a barb + #with a full one + if offset == length: + poly_verts.append((endx, endy + offset)) + offset -= 1.5 * spacing + poly_verts.extend([(endx, endy + offset), + (endx + full_height/2, endy + offset + full_width/4), + (endx, endy + offset)]) + + #Rotate the barb according the angle. Making the barb first and then + #rotating it made the math for drawing the barb really easy. Also, + #the transform framework makes doing the rotation simple. poly_verts = transforms.Affine2D().rotate(-angle).transform( - poly_verts) - barb_list.append(poly_verts) - - return barb_list - - #Taken shamelessly from Quiver - def _parse_args(self, *args): - X, Y, U, V, C = [None]*5 - args = list(args) - if len(args) == 3 or len(args) == 5: - C = ma.asarray(args.pop(-1)).ravel() - V = ma.asarray(args.pop(-1)) + poly_verts) + barb_list.append(poly_verts) + + return barb_list + + #Taken shamelessly from Quiver + def _parse_args(self, *args): + X, Y, U, V, C = [None]*5 + args = list(args) + if len(args) == 3 or len(args) == 5: + C = ma.asarray(args.pop(-1)).ravel() + V = ma.asarray(args.pop(-1)) U = ma.asarray(args.pop(-1)) - nn = np.shape(U) - nc = nn[0] - nr = 1 - if len(nn) > 1: - nr = nn[1] - if len(args) == 2: # remaining after removing U,V,C - X, Y = [np.array(a).ravel() for a in args] - if len(X) == nc and len(Y) == nr: - X, Y = [a.ravel() for a in np.meshgrid(X, Y)] - else: - indexgrid = np.meshgrid(np.arange(nc), np.arange(nr)) - X, Y = [np.ravel(a) for a in indexgrid] - return X, Y, U, V, C + nn = np.shape(U) + nc = nn[0] + nr = 1 + if len(nn) > 1: + nr = nn[1] + if len(args) == 2: # remaining after removing U,V,C + X, Y = [np.array(a).ravel() for a in args] + if len(X) == nc and len(Y) == nr: + X, Y = [a.ravel() for a in np.meshgrid(X, Y)] + else: + indexgrid = np.meshgrid(np.arange(nc), np.arange(nr)) + X, Y = [np.ravel(a) for a in indexgrid] + return X, Y, U, V, C def set_UVC(self, U, V, C=None): self.u = ma.asarray(U).ravel() - self.v = ma.asarray(V).ravel() + self.v = ma.asarray(V).ravel() if C is not None: c = ma.asarray(C).ravel() x,y,u,v,c = delete_masked_points(self.x.ravel(), self.y.ravel(), @@ -874,20 +874,20 @@ x,y,u,v = delete_masked_points(self.x.ravel(), self.y.ravel(), self.u, self.v) - magnitude = np.sqrt(u*u + v*v) + magnitude = np.sqrt(u*u + v*v) flags, barbs, halves, empty = self._find_tails(magnitude, - self.rounding, **self.barb_increments) - + self.rounding, **self.barb_increments) + #Get the vertices for each of the barbs - + plot_barbs = self._make_barbs(u, v, flags, barbs, halves, empty, self._length, self._pivot, self.sizes, self.fill_empty, self.flip) self.set_verts(plot_barbs) - + #Set the color array if C is not None: self.set_array(c) - + #Update the offsets in case the masked data changed xy = np.hstack((x[:,np.newaxis], y[:,np.newaxis])) self._offsets = xy @@ -897,7 +897,7 @@ Set the offsets for the barb polygons. This saves the offets passed in and actually sets version masked as appropriate for the existing U/V data. *offsets* should be a sequence. - + ACCEPTS: sequence of pairs of floats ''' self.x = xy[:,0] @@ -908,5 +908,4 @@ collections.PolyCollection.set_offsets(self, xy) set_offsets.__doc__ = collections.PolyCollection.set_offsets.__doc__ - barbs_doc = _barbs_doc - + barbs_doc = _barbs_doc This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ```
 SF.net SVN: matplotlib:[5865] trunk/matplotlib/lib/matplotlib/quiver.py From: - 2008-07-25 03:55:19 ```Revision: 5865 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5865&view=rev Author: efiring Date: 2008-07-25 03:55:16 +0000 (Fri, 25 Jul 2008) Log Message: ----------- Fix quiverkey with coordinates="inches". Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/quiver.py Modified: trunk/matplotlib/lib/matplotlib/quiver.py =================================================================== --- trunk/matplotlib/lib/matplotlib/quiver.py 2008-07-25 03:53:18 UTC (rev 5864) +++ trunk/matplotlib/lib/matplotlib/quiver.py 2008-07-25 03:55:16 UTC (rev 5865) @@ -289,10 +289,7 @@ elif self.coord == 'figure': self.set_transform(self.Q.ax.figure.transFigure) elif self.coord == 'inches': - dx = ax.figure.dpi - bb = transforms.Bbox.from_extents(0, 0, dx, dy) - trans = transforms.BboxTransformTo(bb) - self.set_transform(trans) + self.set_transform(self.Q.ax.figure.dpi_scale_trans) else: raise ValueError('unrecognized coordinates') quiverkey_doc = _quiverkey_doc This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ```
 SF.net SVN: matplotlib:[5880] trunk/matplotlib/lib/matplotlib/quiver.py From: - 2008-07-25 23:52:48 ```Revision: 5880 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5880&view=rev Author: jdh2358 Date: 2008-07-25 23:52:46 +0000 (Fri, 25 Jul 2008) Log Message: ----------- added set_figure method for quiverkey Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/quiver.py Modified: trunk/matplotlib/lib/matplotlib/quiver.py =================================================================== --- trunk/matplotlib/lib/matplotlib/quiver.py 2008-07-25 23:45:01 UTC (rev 5879) +++ trunk/matplotlib/lib/matplotlib/quiver.py 2008-07-25 23:52:46 UTC (rev 5880) @@ -235,6 +235,7 @@ self._initialized = False self.zorder = Q.zorder + 0.1 + __init__.__doc__ = _quiverkey_doc def _init(self): @@ -294,6 +295,10 @@ raise ValueError('unrecognized coordinates') quiverkey_doc = _quiverkey_doc + def set_figure(self, fig): + Artist.set_figure(self, fig) + self.text.set_figure(fig) + class Quiver(collections.PolyCollection): """ Specialized PolyCollection for arrows. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ```
 SF.net SVN: matplotlib:[5881] trunk/matplotlib/lib/matplotlib/quiver.py From: - 2008-07-25 23:54:41 ```Revision: 5881 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5881&view=rev Author: jdh2358 Date: 2008-07-25 23:54:37 +0000 (Fri, 25 Jul 2008) Log Message: ----------- added set_figure method for quiverkey Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/quiver.py Modified: trunk/matplotlib/lib/matplotlib/quiver.py =================================================================== --- trunk/matplotlib/lib/matplotlib/quiver.py 2008-07-25 23:52:46 UTC (rev 5880) +++ trunk/matplotlib/lib/matplotlib/quiver.py 2008-07-25 23:54:37 UTC (rev 5881) @@ -296,7 +296,7 @@ quiverkey_doc = _quiverkey_doc def set_figure(self, fig): - Artist.set_figure(self, fig) + martist.Artist.set_figure(self, fig) self.text.set_figure(fig) class Quiver(collections.PolyCollection): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ```
 SF.net SVN: matplotlib:[5897] trunk/matplotlib/lib/matplotlib/quiver.py From: - 2008-07-27 00:58:54 ```Revision: 5897 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5897&view=rev Author: efiring Date: 2008-07-27 00:58:51 +0000 (Sun, 27 Jul 2008) Log Message: ----------- Add contains method to QuiverKey Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/quiver.py Modified: trunk/matplotlib/lib/matplotlib/quiver.py =================================================================== --- trunk/matplotlib/lib/matplotlib/quiver.py 2008-07-27 00:07:33 UTC (rev 5896) +++ trunk/matplotlib/lib/matplotlib/quiver.py 2008-07-27 00:58:51 UTC (rev 5897) @@ -293,12 +293,22 @@ self.set_transform(self.Q.ax.figure.dpi_scale_trans) else: raise ValueError('unrecognized coordinates') - quiverkey_doc = _quiverkey_doc def set_figure(self, fig): martist.Artist.set_figure(self, fig) self.text.set_figure(fig) + def contains(self, mouseevent): + # Maybe the dictionary should allow one to + # distinguish between a text hit and a vector hit. + if (self.text.contains(mouseevent)[0] + or self.vector.contains(mouseevent)[0]): + return True, {} + return False, {} + + quiverkey_doc = _quiverkey_doc + + class Quiver(collections.PolyCollection): """ Specialized PolyCollection for arrows. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ```
 SF.net SVN: matplotlib:[6114] trunk/matplotlib/lib/matplotlib/quiver.py From: - 2008-09-18 17:36:12 ```Revision: 6114 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6114&view=rev Author: efiring Date: 2008-09-19 00:36:10 +0000 (Fri, 19 Sep 2008) Log Message: ----------- Change quiver angles kwarg from radians to degrees Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/quiver.py Modified: trunk/matplotlib/lib/matplotlib/quiver.py =================================================================== --- trunk/matplotlib/lib/matplotlib/quiver.py 2008-09-19 00:30:54 UTC (rev 6113) +++ trunk/matplotlib/lib/matplotlib/quiver.py 2008-09-19 00:36:10 UTC (rev 6114) @@ -85,7 +85,7 @@ CCW from the *x*-axis. With 'xy', the arrow points from (x,y) to (x+u, y+v). Alternatively, arbitrary angles may be specified as an array - of values in radians, CCW from the *x*-axis. + of values in degrees, CCW from the *x*-axis. *scale*: [ None | float ] data units per arrow unit, e.g. m/s per plot width; a smaller @@ -481,7 +481,7 @@ elif self.angles == 'uv': theta = np.angle(ma.asarray(uv[..., np.newaxis]).filled(0)) else: - theta = ma.asarray(self.angles).filled(0) + theta = ma.asarray(self.angles*np.pi/180.0).filled(0) xy = (X+Y*1j) * np.exp(1j*theta)*self.width xy = xy[:,:,np.newaxis] XY = ma.concatenate((xy.real, xy.imag), axis=2) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ```
 SF.net SVN: matplotlib:[6474] trunk/matplotlib/lib/matplotlib/quiver.py From: - 2008-12-02 17:55:17 ```Revision: 6474 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6474&view=rev Author: ryanmay Date: 2008-12-02 17:55:15 +0000 (Tue, 02 Dec 2008) Log Message: ----------- Begin and end docstrings on newlines. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/quiver.py Modified: trunk/matplotlib/lib/matplotlib/quiver.py =================================================================== --- trunk/matplotlib/lib/matplotlib/quiver.py 2008-12-02 17:54:44 UTC (rev 6473) +++ trunk/matplotlib/lib/matplotlib/quiver.py 2008-12-02 17:55:15 UTC (rev 6474) @@ -745,7 +745,8 @@ %s""" % _barbs_doc def _find_tails(self, mag, rounding=True, half=5, full=10, flag=50): - '''Find how many of each of the tail pieces is necessary. Flag + ''' + Find how many of each of the tail pieces is necessary. Flag specifies the increment for a flag, barb for a full barb, and half for half a barb. Mag should be the magnitude of a vector (ie. >= 0). @@ -777,7 +778,8 @@ def _make_barbs(self, u, v, nflags, nbarbs, half_barb, empty_flag, length, pivot, sizes, fill_empty, flip): - '''This function actually creates the wind barbs. *u* and *v* + ''' + This function actually creates the wind barbs. *u* and *v* are components of the vector in the *x* and *y* directions, respectively. @@ -817,7 +819,8 @@ This function returns list of arrays of vertices, defining a polygon for each of the wind barbs. These polygons have been rotated to properly - align with the vector direction.''' + align with the vector direction. + ''' #These control the spacing and size of barb elements relative to the #length of the shaft This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ```
 SF.net SVN: matplotlib:[7103] trunk/matplotlib/lib/matplotlib/quiver.py From: - 2009-05-16 01:01:56 ```Revision: 7103 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7103&view=rev Author: efiring Date: 2009-05-16 01:01:49 +0000 (Sat, 16 May 2009) Log Message: ----------- Fixed bugs in quiver affecting angles passed in as a sequence Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/quiver.py Modified: trunk/matplotlib/lib/matplotlib/quiver.py =================================================================== --- trunk/matplotlib/lib/matplotlib/quiver.py 2009-05-14 06:27:58 UTC (rev 7102) +++ trunk/matplotlib/lib/matplotlib/quiver.py 2009-05-16 01:01:49 UTC (rev 7103) @@ -479,11 +479,12 @@ length = a/(self.scale*self.width) X, Y = self._h_arrows(length) if self.angles == 'xy': - theta = self._angles(U, V).filled(0)[:,np.newaxis] + theta = self._angles(U, V).filled(0) elif self.angles == 'uv': - theta = np.angle(ma.asarray(uv[..., np.newaxis]).filled(0)) + theta = np.angle(uv.filled(0)) else: - theta = ma.asarray(self.angles*np.pi/180.0).filled(0) + theta = ma.asarray(self.angles).filled(0)*np.pi/180.0 + theta.shape = (theta.shape[0], 1) # for broadcasting xy = (X+Y*1j) * np.exp(1j*theta)*self.width xy = xy[:,:,np.newaxis] XY = ma.concatenate((xy.real, xy.imag), axis=2) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ```
 SF.net SVN: matplotlib:[7104] trunk/matplotlib/lib/matplotlib/quiver.py From: - 2009-05-16 02:22:59 ```Revision: 7104 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7104&view=rev Author: efiring Date: 2009-05-16 02:22:57 +0000 (Sat, 16 May 2009) Log Message: ----------- Make quiver handle nans and infs Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/quiver.py Modified: trunk/matplotlib/lib/matplotlib/quiver.py =================================================================== --- trunk/matplotlib/lib/matplotlib/quiver.py 2009-05-16 01:01:49 UTC (rev 7103) +++ trunk/matplotlib/lib/matplotlib/quiver.py 2009-05-16 02:22:57 UTC (rev 7104) @@ -388,9 +388,9 @@ X, Y, U, V, C = [None]*5 args = list(args) if len(args) == 3 or len(args) == 5: - C = ma.asarray(args.pop(-1)) - V = ma.asarray(args.pop(-1)) - U = ma.asarray(args.pop(-1)) + C = ma.masked_invalid(args.pop(-1), copy=False) + V = ma.masked_invalid(args.pop(-1), copy=False) + U = ma.masked_invalid(args.pop(-1), copy=False) if U.ndim == 1: nr, nc = 1, U.shape[0] else: @@ -483,7 +483,8 @@ elif self.angles == 'uv': theta = np.angle(uv.filled(0)) else: - theta = ma.asarray(self.angles).filled(0)*np.pi/180.0 + theta = ma.masked_invalid(self.angles, copy=False).filled(0) + theta *= (np.pi/180.0) theta.shape = (theta.shape[0], 1) # for broadcasting xy = (X+Y*1j) * np.exp(1j*theta)*self.width xy = xy[:,:,np.newaxis] @@ -919,9 +920,9 @@ X, Y, U, V, C = [None]*5 args = list(args) if len(args) == 3 or len(args) == 5: - C = ma.asarray(args.pop(-1)).ravel() - V = ma.asarray(args.pop(-1)) - U = ma.asarray(args.pop(-1)) + C = ma.masked_invalid(args.pop(-1), copy=False).ravel() + V = ma.masked_invalid(args.pop(-1), copy=False) + U = ma.masked_invalid(args.pop(-1), copy=False) nn = np.shape(U) nc = nn[0] nr = 1 @@ -937,10 +938,10 @@ return X, Y, U, V, C def set_UVC(self, U, V, C=None): - self.u = ma.asarray(U).ravel() - self.v = ma.asarray(V).ravel() + self.u = ma.masked_invalid(U, copy=False).ravel() + self.v = ma.masked_invalid(V, copy=False).ravel() if C is not None: - c = ma.asarray(C).ravel() + c = ma.masked_invalid(C, copy=False).ravel() x,y,u,v,c = delete_masked_points(self.x.ravel(), self.y.ravel(), self.u, self.v, c) else: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ```
 SF.net SVN: matplotlib:[7207] trunk/matplotlib/lib/matplotlib/quiver.py From: - 2009-06-10 16:41:07 ```Revision: 7207 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7207&view=rev Author: mdboom Date: 2009-06-10 16:41:06 +0000 (Wed, 10 Jun 2009) Log Message: ----------- Bug: 2671465 quiver plot adds unwanted lines to image Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/quiver.py Modified: trunk/matplotlib/lib/matplotlib/quiver.py =================================================================== --- trunk/matplotlib/lib/matplotlib/quiver.py 2009-06-09 22:40:35 UTC (rev 7206) +++ trunk/matplotlib/lib/matplotlib/quiver.py 2009-06-10 16:41:06 UTC (rev 7207) @@ -500,6 +500,10 @@ minsh = self.minshaft * self.headlength N = len(length) length = length.reshape(N, 1) + # This number is chosen based on when pixel values overflow in Agg + # causing rendering errors + length = np.minimum(length, 2 ** 16) + # x, y: normal horizontal arrow x = np.array([0, -self.headaxislength, -self.headlength, 0], np.float64) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ```
 SF.net SVN: matplotlib:[7637] trunk/matplotlib/lib/matplotlib/quiver.py From: - 2009-09-05 18:55:18 ```Revision: 7637 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7637&view=rev Author: efiring Date: 2009-09-05 18:55:08 +0000 (Sat, 05 Sep 2009) Log Message: ----------- Fix bug related to autoscaling and masked values in quiver Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/quiver.py Modified: trunk/matplotlib/lib/matplotlib/quiver.py =================================================================== --- trunk/matplotlib/lib/matplotlib/quiver.py 2009-09-04 20:20:06 UTC (rev 7636) +++ trunk/matplotlib/lib/matplotlib/quiver.py 2009-09-05 18:55:08 UTC (rev 7637) @@ -498,7 +498,11 @@ a = np.absolute(uv) if self.scale is None: sn = max(10, math.sqrt(self.N)) - scale = 1.8 * a[~self.Umask].mean() * sn / self.span # crude auto-scaling + if self.Umask is not ma.nomask: + amean = a[~self.Umask].mean() + else: + amean = a.mean() + scale = 1.8 * amean * sn / self.span # crude auto-scaling self.scale = scale length = a/(self.scale*self.width) X, Y = self._h_arrows(length) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ```
 SF.net SVN: matplotlib:[7836] trunk/matplotlib/lib/matplotlib/quiver.py From: - 2009-10-01 02:28:23 ```Revision: 7836 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7836&view=rev Author: efiring Date: 2009-10-01 02:28:14 +0000 (Thu, 01 Oct 2009) Log Message: ----------- Add scale_units kwarg, additional 'xy' units option. Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/quiver.py Modified: trunk/matplotlib/lib/matplotlib/quiver.py =================================================================== --- trunk/matplotlib/lib/matplotlib/quiver.py 2009-09-30 13:28:37 UTC (rev 7835) +++ trunk/matplotlib/lib/matplotlib/quiver.py 2009-10-01 02:28:14 UTC (rev 7836) @@ -72,7 +72,7 @@ * 'dots' or 'inches': pixels or inches, based on the figure dpi - * 'x' or 'y': *X* or *Y* data units + * 'x', 'y', or 'xy': *X*, *Y*, or sqrt(X^2+Y^2) data units The arrows scale differently depending on the units. For 'x' or 'y', the arrows get larger as one zooms in; for other @@ -81,6 +81,7 @@ height of the axes, respectively, when the the window is resized; for 'dots' or 'inches', resizing does not change the arrows. + *angles*: ['uv' | 'xy' | array] With the default 'uv', the arrow aspect ratio is 1, so that if *U*==*V* the angle of the arrow on the plot is 45 degrees @@ -90,11 +91,21 @@ of values in degrees, CCW from the *x*-axis. *scale*: [ None | float ] - data units per arrow unit, e.g. m/s per plot width; a smaller + data units per arrow length unit, e.g. m/s per plot width; a smaller scale parameter makes the arrow longer. If *None*, a simple autoscaling algorithm is used, based on the average vector length - and the number of vectors. + and the number of vectors. The arrow length unit is given by + the *scale_units* parameter + *scale_units*: None, or any of the *units* options. For example, + if *scale_units* is 'inches', *scale* is 2.0, and (u,v) = (1,0), + then the vector will be 0.5 inches long. If *scale_units* is + 'width', then the vector will be half the width of the axes. + If *scale_units* is 'x' then the vector will be 0.5 x-axis + units. To plot vectors in the x-y plane, with u and v having + the same units as x and y, use + "angles='xy', scale_units='xy', scale=1". + *width*: shaft width in arrow units; default depends on choice of units, above, and number of vectors; a typical starting value is about @@ -390,6 +401,7 @@ self.minshaft = kw.pop('minshaft', 1) self.minlength = kw.pop('minlength', 1) self.units = kw.pop('units', 'width') + self.scale_units = kw.pop('scale_units', None) self.angles = kw.pop('angles', 'uv') self.width = kw.pop('width', None) self.color = kw.pop('color', 'k') @@ -418,7 +430,8 @@ def _init(self): - """initialization delayed until first draw; + """ + Initialization delayed until first draw; allow time for axes setup. """ # It seems that there are not enough event notifications @@ -429,14 +442,15 @@ sx, sy = trans.inverted().transform_point( (ax.bbox.width, ax.bbox.height)) self.span = sx - sn = max(8, min(25, math.sqrt(self.N))) if self.width is None: + sn = max(8, min(25, math.sqrt(self.N))) self.width = 0.06 * self.span / sn @allow_rasterization def draw(self, renderer): self._init() - if self._new_UV or self.angles == 'xy': + if (self._new_UV or self.angles == 'xy' + or self.scale_units in ['x','y', 'xy']): verts = self._make_verts(self.U, self.V) self.set_verts(verts, closed=False) self._new_UV = False @@ -460,27 +474,46 @@ self.set_array(C) self._new_UV = True - def _set_transform(self): + def _dots_per_unit(self, units): + """ + Return a scale factor for converting from units to pixels + """ ax = self.ax - if self.units in ('x', 'y'): - if self.units == 'x': + if units in ('x', 'y', 'xy'): + if units == 'x': dx0 = ax.viewLim.width dx1 = ax.bbox.width - else: + elif units == 'y': dx0 = ax.viewLim.height dx1 = ax.bbox.height + else: # 'xy' is assumed + dxx0 = ax.viewLim.width + dxx1 = ax.bbox.width + dyy0 = ax.viewLim.height + dyy1 = ax.bbox.height + dx1 = np.sqrt(dxx1*dxx1+dyy1*dyy1) + dx0 = np.sqrt(dxx0*dxx0+dyy0*dyy0) dx = dx1/dx0 else: - if self.units == 'width': + if units == 'width': dx = ax.bbox.width - elif self.units == 'height': + elif units == 'height': dx = ax.bbox.height - elif self.units == 'dots': + elif units == 'dots': dx = 1.0 - elif self.units == 'inches': + elif units == 'inches': dx = ax.figure.dpi else: raise ValueError('unrecognized units') + return dx + + def _set_transform(self): + """ + Sets the PolygonCollection transform to go + from arrow width units to pixels. + """ + dx = self._dots_per_unit(self.units) + self._trans_scale = dx # pixels per arrow width unit trans = transforms.Affine2D().scale(dx) self.set_transform(trans) return trans @@ -503,8 +536,18 @@ else: amean = a.mean() scale = 1.8 * amean * sn / self.span # crude auto-scaling - self.scale = scale - length = a/(self.scale*self.width) + # scale is typical arrow length as a multiple + # of the arrow width + if self.scale_units is None: + if self.scale is None: + self.scale = scale + widthu_per_lenu = 1.0 + else: + dx = self._dots_per_unit(self.scale_units) + widthu_per_lenu = dx/self._trans_scale + if self.scale is None: + self.scale = scale * widthu_per_lenu + length = a * (widthu_per_lenu / (self.scale * self.width)) X, Y = self._h_arrows(length) if self.angles == 'xy': theta = self._angles(U, V) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ```
 SF.net SVN: matplotlib:[7993] trunk/matplotlib/lib/matplotlib/quiver.py From: - 2009-11-30 22:50:24 ```Revision: 7993 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7993&view=rev Author: efiring Date: 2009-11-30 21:38:58 +0000 (Mon, 30 Nov 2009) Log Message: ----------- Make the kwarg combination "units='xy', angles='xy', scale=1" work as expected Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/quiver.py Modified: trunk/matplotlib/lib/matplotlib/quiver.py =================================================================== --- trunk/matplotlib/lib/matplotlib/quiver.py 2009-11-30 21:13:34 UTC (rev 7992) +++ trunk/matplotlib/lib/matplotlib/quiver.py 2009-11-30 21:38:58 UTC (rev 7993) @@ -64,7 +64,7 @@ Keyword arguments: - *units*: ['width' | 'height' | 'dots' | 'inches' | 'x' | 'y' ] + *units*: ['width' | 'height' | 'dots' | 'inches' | 'x' | 'y' | 'xy'] arrow units; the arrow dimensions *except for length* are in multiples of this unit. @@ -518,17 +518,33 @@ self.set_transform(trans) return trans - def _angles(self, U, V, eps=0.001): + def _angles_lengths(self, U, V, eps=1): xy = self.ax.transData.transform(self.XY) uv = np.hstack((U[:,np.newaxis], V[:,np.newaxis])) xyp = self.ax.transData.transform(self.XY + eps * uv) dxy = xyp - xy - ang = np.arctan2(dxy[:,1], dxy[:,0]) - return ang + angles = np.arctan2(dxy[:,1], dxy[:,0]) + lengths = np.absolute(dxy[:,0] + dxy[:,1]*1j) / eps + return angles, lengths + + def _make_verts(self, U, V): uv = (U+V*1j) - a = np.absolute(uv) + if self.angles == 'xy' and self.scale_units == 'xy': + # Here eps is 1 so that if we get U, V by diffing + # the X, Y arrays, the vectors will connect the + # points, regardless of the axis scaling (including log). + angles, lengths = self._angles_lengths(U, V, eps=1) + elif self.angles == 'xy' or self.scale_units == 'xy': + # We could refine this by calculating eps based on + # the magnitude of U, V relative to that of X, Y, + # to ensure we are always making small shifts in X, Y. + angles, lengths = self._angles_lengths(U, V, eps=0.001) + if self.scale_units == 'xy': + a = lengths + else: + a = np.absolute(uv) if self.scale is None: sn = max(10, math.sqrt(self.N)) if self.Umask is not ma.nomask: @@ -543,14 +559,17 @@ self.scale = scale widthu_per_lenu = 1.0 else: - dx = self._dots_per_unit(self.scale_units) + if self.scale_units == 'xy': + dx = 1 + else: + dx = self._dots_per_unit(self.scale_units) widthu_per_lenu = dx/self._trans_scale if self.scale is None: self.scale = scale * widthu_per_lenu length = a * (widthu_per_lenu / (self.scale * self.width)) X, Y = self._h_arrows(length) if self.angles == 'xy': - theta = self._angles(U, V) + theta = angles elif self.angles == 'uv': theta = np.angle(uv) else: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ```
 SF.net SVN: matplotlib:[8217] trunk/matplotlib/lib/matplotlib/quiver.py From: - 2010-04-02 18:47:06 ```Revision: 8217 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=8217&view=rev Author: ryanmay Date: 2010-04-02 18:47:00 +0000 (Fri, 02 Apr 2010) Log Message: ----------- Correct calculation of vectors with quiver and angles='xy'. Using just a small eps can result in roundoff problems if X,Y are large (such as with Basemap). Modified Paths: -------------- trunk/matplotlib/lib/matplotlib/quiver.py Modified: trunk/matplotlib/lib/matplotlib/quiver.py =================================================================== --- trunk/matplotlib/lib/matplotlib/quiver.py 2010-04-01 03:41:24 UTC (rev 8216) +++ trunk/matplotlib/lib/matplotlib/quiver.py 2010-04-02 18:47:00 UTC (rev 8217) @@ -537,10 +537,11 @@ # points, regardless of the axis scaling (including log). angles, lengths = self._angles_lengths(U, V, eps=1) elif self.angles == 'xy' or self.scale_units == 'xy': - # We could refine this by calculating eps based on - # the magnitude of U, V relative to that of X, Y, - # to ensure we are always making small shifts in X, Y. - angles, lengths = self._angles_lengths(U, V, eps=0.001) + # Calculate eps based on the extents of the plot + # so that we don't end up with roundoff error from + # adding a small number to a large. + angles, lengths = self._angles_lengths(U, V, + eps=np.abs(self.ax.dataLim.extents).max() * 0.001) if self.scale_units == 'xy': a = lengths else: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ```