I just fixed a small bug when bins were not filled and C was specified.
Attached is the revised version.
Index: lib/matplotlib/axes.py
===================================================================
--- lib/matplotlib/axes.py	(revision 5892)
+++ lib/matplotlib/axes.py	(working copy)
@@ -4941,24 +4941,35 @@
 
     scatter.__doc__ = cbook.dedent(scatter.__doc__) % martist.kwdocd
 
-    def hexbin(self, x, y, gridsize = 100, bins = None,
+    def hexbin(self, x, y, C = None, gridsize = 100, bins = None,
                     xscale = 'linear', yscale = 'linear',
                     cmap=None, norm=None, vmin=None, vmax=None,
                     alpha=1.0, linewidths=None, edgecolors='none',
+                    reduce_C_function = np.mean,
                     **kwargs):
         """
         call signature::
 
-          hexbin(x, y, gridsize = 100, bins = None,
+          hexbin(x, y, C = None, gridsize = 100, bins = None,
                  xscale = 'linear', yscale = 'linear',
                  cmap=None, norm=None, vmin=None, vmax=None,
                  alpha=1.0, linewidths=None, edgecolors='none'
+                 reduce_C_function = np.mean,
                  **kwargs)
 
         Make a hexagonal binning plot of *x* versus *y*, where *x*,
-        *y* are 1-D sequences of the same length, *N*.
+        *y* are 1-D sequences of the same length, *N*. If *C* is None
+        (the default), this is a histogram of the number of occurences
+        of the observations at (x[i],y[i]).
 
-        *x* and/or *y* may be masked arrays, in which case only
+        If *C* is specified, it specifies values at the coordinate
+        (x[i],y[i]). These values are accumulated for each hexagonal
+        bin and then reduced according to *reduce_C_function*, which
+        defaults to numpy's mean function (np.mean). (If *C* is
+        specified, it must also be a 1-D sequence of the same length
+        as *x* and *y*.)
+
+        *x*, *y* and/or *C* may be masked arrays, in which case only
         unmasked points will be plotted.
 
         Optional keyword arguments:
@@ -5049,7 +5060,7 @@
 
         self._process_unit_info(xdata=x, ydata=y, kwargs=kwargs)
 
-        x, y = cbook.delete_masked_points(x, y)
+        x, y, C = cbook.delete_masked_points(x, y, C)
 
         # Set the size of the hexagon grid
         if iterable(gridsize):
@@ -5087,22 +5098,59 @@
         nx2 = nx
         ny2 = ny
         n = nx1*ny1+nx2*ny2
-        counts = np.zeros(n)
-        lattice1 = counts[:nx1*ny1]
-        lattice2 = counts[nx1*ny1:]
-        lattice1.shape = (nx1,ny1)
-        lattice2.shape = (nx2,ny2)
 
         d1 = (x-ix1)**2 + 3.0 * (y-iy1)**2
         d2 = (x-ix2-0.5)**2 + 3.0 * (y-iy2-0.5)**2
         bdist = (d1<d2)
 
-        for i in range(len(x)):
-            if bdist[i]:
-                lattice1[ix1[i], iy1[i]]+=1
-            else:
-                lattice2[ix2[i], iy2[i]]+=1
+        if C is None:
+            accum = np.zeros(n)
+            # Create appropriate views into "accum" array.
+            lattice1 = accum[:nx1*ny1]
+            lattice2 = accum[nx1*ny1:]
+            lattice1.shape = (nx1,ny1)
+            lattice2.shape = (nx2,ny2)
 
+            for i in range(len(x)):
+                if bdist[i]:
+                    lattice1[ix1[i], iy1[i]]+=1
+                else:
+                    lattice2[ix2[i], iy2[i]]+=1
+        else:
+            # create accumulation arrays
+            lattice1 = np.empty((nx1,ny1),dtype=object)
+            for i in range(nx1):
+                for j in range(ny1):
+                    lattice1[i,j] = []
+            lattice2 = np.empty((nx2,ny2),dtype=object)
+            for i in range(nx2):
+                for j in range(ny2):
+                    lattice2[i,j] = []
+
+            for i in range(len(x)):
+                if bdist[i]:
+                    lattice1[ix1[i], iy1[i]].append( C[i] )
+                else:
+                    lattice2[ix2[i], iy2[i]].append( C[i] )
+
+            for i in range(nx1):
+                for j in range(ny1):
+                    vals = lattice1[i,j]
+                    if len(vals):
+                        lattice1[i,j] = reduce( reduce_C_function, vals )
+                    else:
+                        lattice1[i,j] = np.nan
+            for i in range(nx2):
+                for j in range(ny2):
+                    vals = lattice2[i,j]
+                    if len(vals):
+                        lattice2[i,j] = reduce( reduce_C_function, vals )
+                    else:
+                        lattice2[i,j] = np.nan
+
+            accum = np.hstack(( lattice1.astype(float).ravel(), lattice2.astype(float).ravel() ))
+            good_idxs = ~np.isnan(accum)
+
         px = xmin + sx * np.array([ 0.5, 0.5, 0.0, -0.5, -0.5,  0.0])
         py = ymin + sy * np.array([-0.5, 0.5, 1.0,  0.5, -0.5, -1.0]) / 3.0
 
@@ -5112,6 +5160,11 @@
         polygons[:,nx1*ny1:,0] = np.repeat(np.arange(nx2) + 0.5, ny2)
         polygons[:,nx1*ny1:,1] = np.tile(np.arange(ny2), nx2) + 0.5
 
+        if C is not None:
+            # remove accumulation bins with no data
+            polygons = polygons[:,good_idxs,:]
+            accum = accum[good_idxs]
+
         polygons = np.transpose(polygons, axes=[1,0,2])
         polygons[:,:,0] *= sx
         polygons[:,:,1] *= sy
@@ -5150,20 +5203,20 @@
                         transOffset = self.transData,
                         )
 
-        # Transform the counts if needed
+        # Transform accum if needed
         if bins=='log':
-            counts = np.log10(counts+1)
+            accum = np.log10(accum+1)
         elif bins!=None:
             if not iterable(bins):
-                minimum, maximum = min(counts), max(counts)
+                minimum, maximum = min(accum), max(accum)
                 bins-=1 # one less edge than bins
                 bins = minimum + (maximum-minimum)*np.arange(bins)/bins
             bins = np.sort(bins)
-            counts = bins.searchsorted(counts)
+            accum = bins.searchsorted(accum)
 
         if norm is not None: assert(isinstance(norm, mcolors.Normalize))
         if cmap is not None: assert(isinstance(cmap, mcolors.Colormap))
-        collection.set_array(counts)
+        collection.set_array(accum)
         collection.set_cmap(cmap)
         collection.set_norm(norm)
         collection.set_alpha(alpha)
Index: examples/pylab_examples/hexbin_demo2.py
===================================================================
--- examples/pylab_examples/hexbin_demo2.py	(revision 0)
+++ examples/pylab_examples/hexbin_demo2.py	(revision 0)
@@ -0,0 +1,54 @@
+"""
+hexbin is an axes method or pyplot function that is essentially
+a pcolor of a 2-D histogram with hexagonal cells.  It can be
+much more informative than a scatter plot; in the first subplot
+below, try substituting 'scatter' for 'hexbin'.
+"""
+
+import numpy as np
+import  matplotlib.pyplot as plt
+import matplotlib.mlab as mlab
+
+delta = 0.025
+x = y = np.arange(-3.0, 3.0, delta)
+X, Y = np.meshgrid(x, y)
+Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
+Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
+Z = Z2-Z1  # difference of Gaussians
+
+x = X.ravel()
+y = Y.ravel()
+z = Z.ravel()
+
+if 1:
+    # make some points 20 times more common than others, but same mean
+    xcond = (-1 < x) & (x < 1)
+    ycond = (-2 < y) & (y < 0)
+    cond = xcond & ycond
+    xnew = x[cond]
+    ynew = y[cond]
+    znew = z[cond]
+    for i in range(20):
+        x = np.hstack((x,xnew))
+        y = np.hstack((y,ynew))
+        z = np.hstack((z,znew))
+
+xmin = x.min()
+xmax = x.max()
+ymin = y.min()
+ymax = y.max()
+
+plt.subplot(211)
+plt.hexbin(x,y, C=z )
+plt.axis([xmin, xmax, ymin, ymax])
+cb = plt.colorbar()
+cb.set_label('mean value')
+
+plt.subplot(212)
+plt.hexbin(x,y)
+plt.axis([xmin, xmax, ymin, ymax])
+cb = plt.colorbar()
+cb.set_label('N observations')
+
+plt.show()
+
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

Reply via email to