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

Reply via email to