Revision: 4377
          http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4377&view=rev
Author:   efiring
Date:     2007-11-18 11:06:49 -0800 (Sun, 18 Nov 2007)

Log Message:
-----------
Add experimental "pcolorfast" for fast interactive pcolor plots

This will need more discussion and work, but it illustrates
the potential for very fast pcolor-type plotting with all
three grid types: uniform, irregular but rectilinear, and
general quadrilateral.

Modified Paths:
--------------
    trunk/matplotlib/lib/matplotlib/axes.py
    trunk/matplotlib/lib/matplotlib/image.py

Modified: trunk/matplotlib/lib/matplotlib/axes.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/axes.py     2007-11-18 19:02:55 UTC (rev 
4376)
+++ trunk/matplotlib/lib/matplotlib/axes.py     2007-11-18 19:06:49 UTC (rev 
4377)
@@ -3706,8 +3706,8 @@
             xs = [thisx for thisx, b in zip(xs, mask) if b]
             ys = [thisy for thisy, b in zip(ys, mask) if b]
             return xs, ys
-            
 
+
         if capsize > 0:
             plot_kw = {
                 'ms':2*capsize,
@@ -3733,16 +3733,16 @@
                     # can't use numpy logical indexing since left and
                     # y are lists
                     leftlo, ylo = xywhere(left, y, xlolims)
-                    
+
                     caplines.extend( self.plot(leftlo, ylo, ls='None', 
marker=mlines.CARETLEFT, **plot_kw) )
                     xlolims = ~xlolims
-                    leftlo, ylo = xywhere(left, y, xlolims)                    
+                    leftlo, ylo = xywhere(left, y, xlolims)
                     caplines.extend( self.plot(leftlo, ylo, 'k|', **plot_kw) )
                 else:
                     caplines.extend( self.plot(left, y, 'k|', **plot_kw) )
 
                 if xuplims.any():
-                    
+
                     rightup, yup = xywhere(right, y, xuplims)
                     caplines.extend( self.plot(rightup,  yup, ls='None', 
marker=mlines.CARETRIGHT, **plot_kw) )
                     xuplims = ~xuplims
@@ -3775,7 +3775,7 @@
 
                 if uplims.any():
                     xup, upperup = xywhere(x, upper, uplims)
-                    
+
                     caplines.extend( self.plot(xup, upperup, ls='None', 
marker=mlines.CARETUP, **plot_kw) )
                     uplims = ~uplims
                     xup, upperup = xywhere(x, upper, uplims)
@@ -4762,6 +4762,177 @@
         return collection
     pcolormesh.__doc__ = cbook.dedent(pcolormesh.__doc__) % martist.kwdocd
 
+    def pcolorfast(self, *args, **kwargs):
+        """
+        Experimental; this is a version of pcolor that
+        does not draw lines, that provides the fastest
+        possible rendering with the Agg backend, and that
+        can handle any quadrilateral grid.
+
+        pcolor(*args, **kwargs): pseudocolor plot of a 2-D array
+
+        Function signatures
+
+          pcolor(C, **kwargs)
+          pcolor(xr, yr, C, **kwargs)
+          pcolor(x, y, C, **kwargs)
+          pcolor(X, Y, C, **kwargs)
+
+        C is the 2D array of color values corresponding to quadrilateral
+        cells. Let (nr, nc) be its shape.  C may be a masked array.
+
+        pcolor(C, **kwargs) is equivalent to
+        pcolor([0,nc], [0,nr], C, **kwargs)
+
+        xr, yr specify the ranges of x and y corresponding to the rectangular
+        region bounding C.  If xr = [x0, x1] and yr = [y0,y1] then
+        x goes from x0 to x1 as the second index of C goes from 0 to nc,
+        etc.  (x0, y0) is the outermost corner of cell (0,0), and (x1, y1)
+        is the outermost corner of cell (nr-1, nc-1).  All cells are
+        rectangles of the same size.  This is the fastest version.
+
+        x, y are 1D arrays of length nc+1 and nr+1, respectively, giving
+        the x and y boundaries of the cells.  Hence the cells are
+        rectangular but the grid may be nonuniform.  The speed is
+        intermediate.  (The grid is checked, and if found to be
+        uniform the fast version is used.)
+
+        X and Y are 2D arrays with shape (nr+1, nc+1) that specify
+        the (x,y) coordinates of the corners of the colored
+        quadrilaterals; the quadrilateral for C[i,j] has corners at
+        (X[i,j],Y[i,j]), (X[i,j+1],Y[i,j+1]), (X[i+1,j],Y[i+1,j]),
+        (X[i+1,j+1],Y[i+1,j+1]).  The cells need not be rectangular.
+        This is the most general, but the slowest to render.  It may
+        produce faster and more compact output using ps, pdf, and
+        svg backends, however.
+
+        Note that the the column index corresponds to the x-coordinate,
+        and the row index corresponds to y; for details, see
+        the "Grid Orientation" section below.
+
+        Optional keyword args are shown with their defaults below (you must
+        use kwargs for these):
+
+          * cmap = cm.jet : a cm Colormap instance from cm
+
+          * norm = Normalize() : mcolors.Normalize instance
+            is used to scale luminance data to 0,1.
+
+          * vmin=None and vmax=None : vmin and vmax are used in conjunction
+            with norm to normalize luminance data.  If either are None, the
+            min and max of the color array C is used.  If you pass a norm
+            instance, vmin and vmax will be None
+
+          * alpha=1.0 : the alpha blending value
+
+        Return value is an image if a regular or rectangular grid
+        is specified, and a QuadMesh collection in the general
+        quadrilateral case.
+
+        """
+
+        if not self._hold: self.cla()
+
+        alpha = kwargs.pop('alpha', 1.0)
+        norm = kwargs.pop('norm', None)
+        cmap = kwargs.pop('cmap', None)
+        vmin = kwargs.pop('vmin', None)
+        vmax = kwargs.pop('vmax', None)
+        if norm is not None: assert(isinstance(norm, mcolors.Normalize))
+        if cmap is not None: assert(isinstance(cmap, mcolors.Colormap))
+
+        C = args[-1]
+        nr, nc = C.shape
+        if len(args) == 1:
+            style = "image"
+            x = [0, nc+1]
+            y = [0, nr+1]
+        elif len(args) == 3:
+            x, y = args[:2]
+            x = npy.asarray(x)
+            y = npy.asarray(y)
+            if x.ndim == 1 and y.ndim == 1:
+                if x.size == 2 and y.size == 2:
+                    style = "image"
+                else:
+                    dx = npy.diff(x)
+                    dy = npy.diff(y)
+                    if (npy.ptp(dx) < 0.01*npy.abs(dx.mean()) and
+                        npy.ptp(dy) < 0.01*npy.abs(dy.mean())):
+                        style = "image"
+                    style = "pcolorimage"
+            elif x.ndim == 2 and y.ndim == 2:
+                style = "quadmesh"
+            else:
+                raise TypeError("arguments do not match valid signatures")
+        else:
+            raise TypeError("need 1 argument or 3 arguments")
+
+        if style == "quadmesh":
+
+            # convert to one dimensional arrays
+            # This should also be moved to the QuadMesh class
+            C = ma.ravel(C) # data point in each cell is value at lower left 
corner
+            X = x.ravel()
+            Y = y.ravel()
+            Nx = nc+1
+            Ny = nr+1
+
+            # The following needs to be cleaned up; the renderer
+            # requires separate contiguous arrays for X and Y,
+            # but the QuadMesh class requires the 2D array.
+            coords = npy.empty(((Nx * Ny), 2), npy.float64)
+            coords[:, 0] = X
+            coords[:, 1] = Y
+
+            # The QuadMesh class can also be changed to
+            # handle relevant superclass kwargs; the initializer
+            # should do much more than it does now.
+            collection = mcoll.QuadMesh(nc, nr, coords, 0)
+            collection.set_alpha(alpha)
+            collection.set_array(C)
+            collection.set_cmap(cmap)
+            collection.set_norm(norm)
+            self.add_collection(collection)
+            xl, xr, yb, yt = X.min(), X.max(), Y.min(), Y.max()
+            ret = collection
+
+        else:
+            # One of the image styles:
+            xl, xr, yb, yt = x[0], x[-1], y[0], y[-1]
+        if style == "image":
+
+            im = mimage.AxesImage(self, cmap, norm,
+                                        interpolation='nearest',
+                                        origin='lower',
+                                        extent=(xl, xr, yb, yt),
+                                         **kwargs)
+            im.set_data(C)
+            im.set_alpha(alpha)
+            self.images.append(im)
+            ret = im
+
+        if style == "pcolorimage":
+            im = mimage.PcolorImage(self, x, y, C,
+                                    cmap=cmap,
+                                    norm=norm,
+                                    alpha=alpha,
+                                    **kwargs)
+            self.images.append(im)
+            ret = im
+
+        self._set_artist_props(ret)
+        if vmin is not None or vmax is not None:
+            ret.set_clim(vmin, vmax)
+        else:
+            ret.autoscale_None()
+        self.update_datalim(npy.array([[xl, yb], [xr, yt]]))
+        self.autoscale_view(tight=True)
+        return ret
+
+
+
+
     def contour(self, *args, **kwargs):
         kwargs['filled'] = False
         return mcontour.ContourSet(self, *args, **kwargs)
@@ -4822,14 +4993,14 @@
         ticks on bottom and the returned axes will have ticks on the
         top
         """
-        
+
         ax2 = self.figure.add_axes(self.get_position(), sharey=self, 
frameon=False)
         ax2.xaxis.tick_top()
         ax2.xaxis.set_label_position('top')
         self.xaxis.tick_bottom()
         return ax2
-    
 
+
     #### Data analysis
 
 

Modified: trunk/matplotlib/lib/matplotlib/image.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/image.py    2007-11-18 19:02:55 UTC (rev 
4376)
+++ trunk/matplotlib/lib/matplotlib/image.py    2007-11-18 19:06:49 UTC (rev 
4377)
@@ -410,9 +410,107 @@
             raise RuntimeError('Cannot change colors after loading data')
         cm.ScalarMappable.set_cmap(self, norm)
 
+class PcolorImage(martist.Artist, cm.ScalarMappable):
+    def __init__(self, ax,
+                 x=None,
+                 y=None,
+                 A=None,
+                 cmap = None,
+                 norm = None,
+                 **kwargs
+                ):
+        """
+        cmap defaults to its rc setting
 
+        cmap is a colors.Colormap instance
+        norm is a colors.Normalize instance to map luminance to 0-1
 
+        Additional kwargs are matplotlib.artist properties
 
+        """
+        martist.Artist.__init__(self)
+        cm.ScalarMappable.__init__(self, norm, cmap)
+        self.axes = ax
+        self._rgbacache = None
+        self.update(kwargs)
+        self.set_data(x, y, A)
+
+    def make_image(self, magnification=1.0):
+        if self._A is None:
+            raise RuntimeError('You must first set the image array')
+        fc = self.axes.get_frame().get_facecolor()
+        bg = mcolors.colorConverter.to_rgba(fc, 0)
+        bg = (npy.array(bg)*255).astype(npy.uint8)
+        x0, y0, v_width, v_height = self.axes.viewLim.get_bounds()
+        l, b, width, height = self.axes.bbox.get_bounds()
+        width *= magnification
+        height *= magnification
+        if self.check_update('array'):
+            A = self.to_rgba(self._A, alpha=self._alpha, bytes=True)
+            self._rgbacache = A
+            if self._A.ndim == 2:
+                self.is_grayscale = self.cmap.is_gray()
+        else:
+            A = self._rgbacache
+        im = _image.pcolor2(self._Ax, self._Ay, A,
+                           height, width,
+                           (x0, x0+v_width, y0, y0+v_height),
+                           bg)
+        im.is_grayscale = self.is_grayscale
+        return im
+
+    def draw(self, renderer, *args, **kwargs):
+        if not self.get_visible(): return
+        im = self.make_image(renderer.get_image_magnification())
+        l, b, widthDisplay, heightDisplay = self.axes.bbox.get_bounds()
+        renderer.draw_image(l, b, im, self.axes.bbox)
+
+
+    def set_data(self, x, y, A):
+        A = ma.asarray(A)
+        if x is None:
+            x = npy.arange(0, A.shape[1]+1, dtype=npy.float64)
+        else:
+            x = npy.asarray(x, npy.float64).ravel()
+        if y is None:
+            y = npy.arange(0, A.shape[0]+1, dtype=npy.float64)
+        else:
+            y = npy.asarray(y, npy.float64).ravel()
+
+        if A.shape[:2] != (y.size-1, x.size-1):
+            print A.shape
+            print y.size
+            print x.size
+            raise ValueError("Axes don't match array shape")
+        if A.ndim not in [2, 3]:
+            raise ValueError("A must be 2D or 3D")
+        if A.ndim == 3 and A.shape[2] == 1:
+            A.shape = A.shape[:2]
+        self.is_grayscale = False
+        if A.ndim == 3:
+            if A.shape[2] in [3, 4]:
+                if (A[:,:,0] == A[:,:,1]).all() and (A[:,:,0] == 
A[:,:,2]).all():
+                    self.is_grayscale = True
+            else:
+                raise ValueError("3D arrays must have RGB or RGBA as last dim")
+        self._A = A
+        self._Ax = x
+        self._Ay = y
+        self.update_dict['array'] = True
+
+    def set_array(self, *args):
+        raise NotImplementedError('Method not supported')
+
+    def set_alpha(self, alpha):
+        """
+        Set the alpha value used for blending - not supported on
+        all backends
+
+        ACCEPTS: float
+        """
+        martist.Artist.set_alpha(self, alpha)
+        self.update_dict['array'] = True
+
 class FigureImage(martist.Artist, cm.ScalarMappable):
     def __init__(self, fig,
                  cmap = None,


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to