David,

I have made some changes in svn that address all but one of the points 
you made:

[....]
> if self.clip:
>                mask = ma.getmaskorNone(val)
>                if mask == None:
>                    val = ma.array(clip(val.filled(vmax), vmin, vmax))
>                else:
>                    val = ma.array(clip(val.filled(vmax), vmin, vmax),
>                                mask=mask)

The real problem here is that I should not have been using 
getmaskorNone().  In numpy.ma, we need nomask, not None, so we want an 
ordinary getmask() call.  ma.array(...., mask=ma.nomask) is very fast, 
so the problem goes away.

> 
> Actually, the problem is in ma.array: with a value of mask to None, it 
> should not make a difference between mask = None or no mask arg, right ? 
But it does, because for numpy it needs to be nomask; it does something 
with None, but whatever it is, it is very slow.

> I didn't change ma.array to keep my change as local as possible. To 
> change only this operation as above gives a speed up from 1.8 s to ~ 1.0 
> s for to_rgba, which means calling show goes from ~ 2.2 s to ~1.4 s. I 
> also changed  
> result = (val-vmin)/float(vmax-vmin)
> 
> to
> 
> invcache    = 1.0 / (vmax - vmin)
> result = (val-vmin) * invcache

This is the one I did not address.  I don't understand how this could be 
making much difference, and some testing using ipython and %prun with 
1-line operations showed little difference with variations on this 
theme.  The fastest would appear to be (and logically should be, I 
think) result = (val-vmin)*(1.0/(vmax-vmin)), but I don't think it makes 
much difference--it looks to me like maybe 10-20 msec, not 100, on my 
Pentium M 1.6 Ghz.  Maybe still worthwhile, so I may yet make the change 
after more careful testing.


> 
> which gives a moderate speed up (around 100 ms for a 8000x256 points 
> array). Once you make both those changes, the clip call is by far the 
> most expensive operation in normalize functor, but the functor is not 
> really expensive anymore compared to the rest, so this is not where I 
> looked at.
> 
> For the where calls in Colormap functor, I was wondering if they are 
> necessary in all cases: some of those calls seem redundant, and it may 
> be possible to detect that before calling them. This should be both 
> easier and faster, at least in this case, than having a fast where ?
> 

You hit the nail squarely: where() is the wrong function to use, and I 
have eliminated it from colors.py.  The much faster replacement is 
putmask, which does as well as direct indexing with a Boolean but works 
with all three numerical packages.  I think that using the fast putmask 
is better than trying to figure out special cases in which there would 
be nothing to put, although I could be convinced otherwise.


> I understand that support of multiple array backend, support of mask 
> arrays have cost consequences. But it looks like it may be possible to 
> speed things up for cases where an array has only meaningful values/no 
> mask.

The big gains here were essentially bug fixes--picking the appropriate 
function (getmask versus getmaskorNone and putmask versus where).

Here is the colors.py diff:

--- trunk/matplotlib/lib/matplotlib/colors.py   2006/12/03 21:54:38     2906
+++ trunk/matplotlib/lib/matplotlib/colors.py   2006/12/14 08:27:04     2923
@@ -30,9 +30,9 @@
  """
  import re

-from numerix import array, arange, take, put, Float, Int, where, \
+from numerix import array, arange, take, put, Float, Int, putmask, \
       zeros, asarray, sort, searchsorted, sometrue, ravel, divide,\
-     ones, typecode, typecodes, alltrue
+     ones, typecode, typecodes, alltrue, clip
  from numerix.mlab import amin, amax
  import numerix.ma as ma
  import numerix as nx
@@ -536,8 +536,9 @@
      lut[0] = y1[0]
      lut[-1] = y0[-1]
      # ensure that the lut is confined to values between 0 and 1 by 
clipping it
-    lut = where(lut > 1., 1., lut)
-    lut = where(lut < 0., 0., lut)
+    clip(lut, 0.0, 1.0)
+    #lut = where(lut > 1., 1., lut)
+    #lut = where(lut < 0., 0., lut)
      return lut


@@ -588,16 +589,16 @@
              vtype = 'array'
              xma = ma.asarray(X)
              xa = xma.filled(0)
-            mask_bad = ma.getmaskorNone(xma)
+            mask_bad = ma.getmask(xma)
          if typecode(xa) in typecodes['Float']:
-            xa = where(xa == 1.0, 0.9999999, xa) # Tweak so 1.0 is in 
range.
+            putmask(xa, xa==1.0, 0.9999999) #Treat 1.0 as slightly less 
than 1.
              xa = (xa * self.N).astype(Int)
-        mask_under = xa < 0
-        mask_over = xa > self.N-1
-        xa = where(mask_under, self._i_under, xa)
-        xa = where(mask_over, self._i_over, xa)
-        if mask_bad is not None: # and sometrue(mask_bad):
-            xa = where(mask_bad, self._i_bad, xa)
+        # Set the over-range indices before the under-range;
+        # otherwise the under-range values get converted to over-range.
+        putmask(xa, xa>self.N-1, self._i_over)
+        putmask(xa, xa<0, self._i_under)
+        if mask_bad is not None and mask_bad.shape == xa.shape:
+            putmask(xa, mask_bad, self._i_bad)
          rgba = take(self._lut, xa)
          if vtype == 'scalar':
              rgba = tuple(rgba[0,:])
@@ -752,7 +753,7 @@
              return 0.*value
          else:
              if clip:
-                mask = ma.getmaskorNone(val)
+                mask = ma.getmask(val)
                  val = ma.array(nx.clip(val.filled(vmax), vmin, vmax),
                                  mask=mask)
              result = (val-vmin)/float(vmax-vmin)
@@ -804,7 +805,7 @@
              return 0.*value
          else:
              if clip:
-                mask = ma.getmaskorNone(val)
+                mask = ma.getmask(val)
                  val = ma.array(nx.clip(val.filled(vmax), vmin, vmax),
                                  mask=mask)
              result = 
(ma.log(val)-nx.log(vmin))/(nx.log(vmax)-nx.log(vmin))


Eric

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Reply via email to