Revision: 7303
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7303&view=rev
Author: efiring
Date: 2009-07-28 22:43:15 +0000 (Tue, 28 Jul 2009)
Log Message:
-----------
Speed up quiver for large numbers of arrows; key tip given by Ray Speth.
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/collections.py
trunk/matplotlib/lib/matplotlib/quiver.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2009-07-28 20:56:07 UTC (rev 7302)
+++ trunk/matplotlib/CHANGELOG 2009-07-28 22:43:15 UTC (rev 7303)
@@ -1,3 +1,5 @@
+2009-07-28 Quiver speed improved, thanks to tip by Ray Speth. -EF
+
2009-07-27 Simplify argument handling code for plot method. -EF
2009-07-25 Allow "plot(1, 2, 'r*')" to work. - EF
Modified: trunk/matplotlib/lib/matplotlib/collections.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/collections.py 2009-07-28 20:56:07 UTC
(rev 7302)
+++ trunk/matplotlib/lib/matplotlib/collections.py 2009-07-28 22:43:15 UTC
(rev 7303)
@@ -670,6 +670,9 @@
def set_verts(self, verts, closed=True):
'''This allows one to delay initialization of the vertices.'''
+ if np.ma.isMaskedArray(verts):
+ verts = verts.astype(np.float_).filled(np.nan)
+ # This is much faster than having Path do it one at a time.
if closed:
self._paths = []
for xy in verts:
Modified: trunk/matplotlib/lib/matplotlib/quiver.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/quiver.py 2009-07-28 20:56:07 UTC (rev
7302)
+++ trunk/matplotlib/lib/matplotlib/quiver.py 2009-07-28 22:43:15 UTC (rev
7303)
@@ -253,8 +253,12 @@
self._set_transform()
_pivot = self.Q.pivot
self.Q.pivot = self.pivot[self.labelpos]
+ # Hack: save and restore the Umask
+ _mask = self.Q.Umask
+ self.Q.Umask = ma.nomask
self.verts = self.Q._make_verts(np.array([self.U]),
np.zeros((1,)))
+ self.Q.Umask = _mask
self.Q.pivot = _pivot
kw = self.Q.polykw
kw.update(self.kw)
@@ -388,9 +392,9 @@
X, Y, U, V, C = [None]*5
args = list(args)
if len(args) == 3 or len(args) == 5:
- 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)
+ C = np.asanyarray(args.pop(-1))
+ V = np.asanyarray(args.pop(-1))
+ U = np.asanyarray(args.pop(-1))
if U.ndim == 1:
nr, nc = 1, U.shape[0]
else:
@@ -430,10 +434,21 @@
collections.PolyCollection.draw(self, renderer)
def set_UVC(self, U, V, C=None):
- self.U = U.ravel()
- self.V = V.ravel()
+ U = ma.masked_invalid(U, copy=False).ravel()
+ V = ma.masked_invalid(V, copy=False).ravel()
+ mask = ma.mask_or(U.mask, V.mask, copy=False, shrink=True)
if C is not None:
- self.set_array(C.ravel())
+ C = ma.masked_invalid(C, copy=False).ravel()
+ mask = ma.mask_or(mask, C.mask, copy=False, shrink=True)
+ if mask is ma.nomask:
+ C = C.filled()
+ else:
+ C = ma.array(C, mask=mask, copy=False)
+ self.U = U.filled(1)
+ self.V = V.filled(1)
+ self.Umask = mask
+ if C is not None:
+ self.set_array(C)
self._new_UV = True
def _set_transform(self):
@@ -463,32 +478,33 @@
def _angles(self, U, V, eps=0.001):
xy = self.ax.transData.transform(self.XY)
- uv = ma.hstack((U[:,np.newaxis], V[:,np.newaxis])).filled(0)
+ uv = np.hstack((U[:,np.newaxis], V[:,np.newaxis]))
xyp = self.ax.transData.transform(self.XY + eps * uv)
dxy = xyp - xy
- ang = ma.arctan2(dxy[:,1], dxy[:,0])
+ ang = np.arctan2(dxy[:,1], dxy[:,0])
return ang
def _make_verts(self, U, V):
- uv = ma.asarray(U+V*1j)
- a = ma.absolute(uv)
+ uv = (U+V*1j)
+ a = np.absolute(uv)
if self.scale is None:
sn = max(10, math.sqrt(self.N))
- scale = 1.8 * a.mean() * sn / self.span # crude auto-scaling
+ scale = 1.8 * a[~self.Umask].mean() * sn / self.span # crude
auto-scaling
self.scale = scale
length = a/(self.scale*self.width)
X, Y = self._h_arrows(length)
if self.angles == 'xy':
- theta = self._angles(U, V).filled(0)
+ theta = self._angles(U, V)
elif self.angles == 'uv':
- theta = np.angle(uv.filled(0))
+ theta = np.angle(uv)
else:
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]
- XY = ma.concatenate((xy.real, xy.imag), axis=2)
+ XY = np.concatenate((xy.real, xy.imag), axis=2)
+
return XY
@@ -502,8 +518,8 @@
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)
-
+ #length = np.minimum(length, 2 ** 16)
+ np.clip(length, 0, 2**16, out=length)
# x, y: normal horizontal arrow
x = np.array([0, -self.headaxislength,
-self.headlength, 0], np.float64)
@@ -514,21 +530,20 @@
x0 = np.array([0, minsh-self.headaxislength,
minsh-self.headlength, minsh], np.float64)
y0 = 0.5 * np.array([1, 1, self.headwidth, 0], np.float64)
- ii = [0,1,2,3,2,1,0]
+ ii = [0,1,2,3,2,1,0,0]
X = x.take(ii, 1)
Y = y.take(ii, 1)
- Y[:, 3:] *= -1
+ Y[:, 3:-1] *= -1
X0 = x0.take(ii)
Y0 = y0.take(ii)
- Y0[3:] *= -1
+ Y0[3:-1] *= -1
shrink = length/minsh
X0 = shrink * X0[np.newaxis,:]
Y0 = shrink * Y0[np.newaxis,:]
- short = np.repeat(length < minsh, 7, axis=1)
- #print 'short', length < minsh
+ short = np.repeat(length < minsh, 8, axis=1)
# Now select X0, Y0 if short, otherwise X, Y
- X = ma.where(short, X0, X)
- Y = ma.where(short, Y0, Y)
+ np.putmask(X, short, X0)
+ np.putmask(Y, short, Y0)
if self.pivot[:3] == 'mid':
X -= 0.5 * X[:,3, np.newaxis]
elif self.pivot[:3] == 'tip':
@@ -538,14 +553,18 @@
tooshort = length < self.minlength
if tooshort.any():
# Use a heptagonal dot:
- th = np.arange(0,7,1, np.float64) * (np.pi/3.0)
+ th = np.arange(0,8,1, np.float64) * (np.pi/3.0)
x1 = np.cos(th) * self.minlength * 0.5
y1 = np.sin(th) * self.minlength * 0.5
X1 = np.repeat(x1[np.newaxis, :], N, axis=0)
Y1 = np.repeat(y1[np.newaxis, :], N, axis=0)
- tooshort = ma.repeat(tooshort, 7, 1)
- X = ma.where(tooshort, X1, X)
- Y = ma.where(tooshort, Y1, Y)
+ tooshort = np.repeat(tooshort, 8, 1)
+ np.putmask(X, tooshort, X1)
+ np.putmask(Y, tooshort, Y1)
+ if self.Umask is not ma.nomask:
+ mask = np.repeat(self.Umask[:,np.newaxis], 8, 1)
+ X = ma.array(X, mask=mask, copy=False)
+ Y = ma.array(Y, mask=mask, copy=False)
return X, Y
quiver_doc = _quiver_doc
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now. http://p.sf.net/sfu/bobj-july
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins