@@ -5212,7 +5212,7 @@ def hexbin(self, x, y, C = None, gridsize = 100, bins = None,
52125212 xscale = 'linear' , yscale = 'linear' ,
52135213 cmap = None , norm = None , vmin = None , vmax = None ,
52145214 alpha = 1.0 , linewidths = None , edgecolors = 'none' ,
5215- reduce_C_function = np .mean , mincnt = None ,
5215+ reduce_C_function = np .mean , mincnt = None , marginals = True ,
52165216 ** kwargs ):
52175217 """
52185218 call signature::
@@ -5221,7 +5221,7 @@ def hexbin(self, x, y, C = None, gridsize = 100, bins = None,
52215221 xscale = 'linear', yscale = 'linear',
52225222 cmap=None, norm=None, vmin=None, vmax=None,
52235223 alpha=1.0, linewidths=None, edgecolors='none'
5224- reduce_C_function = np.mean, mincnt=None,
5224+ reduce_C_function = np.mean, mincnt=None, marginals=True
52255225 **kwargs)
52265226
52275227 Make a hexagonal binning plot of *x* versus *y*, where *x*,
@@ -5273,6 +5273,11 @@ def hexbin(self, x, y, C = None, gridsize = 100, bins = None,
52735273 If not None, only display cells with more than *mincnt*
52745274 number of points in the cell
52755275
5276+ *marginals*: True|False
5277+ if marginals is True, plot the marginal density as
5278+ colormapped rectagles along the bottom of the x-axis and
5279+ left of the y-axis
5280+
52765281 Other keyword arguments controlling color mapping and normalization
52775282 arguments:
52785283
@@ -5320,7 +5325,10 @@ def hexbin(self, x, y, C = None, gridsize = 100, bins = None,
53205325 :class:`~matplotlib.collections.PolyCollection` instance; use
53215326 :meth:`~matplotlib.collection.PolyCollection.get_array` on
53225327 this :class:`~matplotlib.collections.PolyCollection` to get
5323- the counts in each hexagon.
5328+ the counts in each hexagon.. If marginals is True, horizontal
5329+ bar and vertical bar (both PolyCollections) will be attached
5330+ to the return collection as attributes *hbar* and *vbar*
5331+
53245332
53255333 **Example:**
53265334
@@ -5331,8 +5339,10 @@ def hexbin(self, x, y, C = None, gridsize = 100, bins = None,
53315339
53325340 self ._process_unit_info (xdata = x , ydata = y , kwargs = kwargs )
53335341
5342+
53345343 x , y , C = cbook .delete_masked_points (x , y , C )
53355344
5345+
53365346 # Set the size of the hexagon grid
53375347 if iterable (gridsize ):
53385348 nx , ny = gridsize
@@ -5357,6 +5367,11 @@ def hexbin(self, x, y, C = None, gridsize = 100, bins = None,
53575367 xmax += padding
53585368 sx = (xmax - xmin ) / nx
53595369 sy = (ymax - ymin ) / ny
5370+
5371+ if marginals :
5372+ xorig = x .copy ()
5373+ yorig = y .copy ()
5374+
53605375 x = (x - xmin )/ sx
53615376 y = (y - ymin )/ sy
53625377 ix1 = np .round (x ).astype (int )
@@ -5496,6 +5511,93 @@ def hexbin(self, x, y, C = None, gridsize = 100, bins = None,
54965511
54975512 # add the collection last
54985513 self .add_collection (collection )
5514+ if not marginals :
5515+ return collection
5516+
5517+
5518+ if C is None :
5519+ C = np .ones (len (x ))
5520+
5521+ def coarse_bin (x , y , coarse ):
5522+ ind = coarse .searchsorted (x ).clip (0 , len (coarse )- 1 )
5523+ mus = np .zeros (len (coarse ))
5524+ for i in range (len (coarse )):
5525+ mu = reduce_C_function (y [ind == i ])
5526+ mus [i ] = mu
5527+ return mus
5528+
5529+ coarse = np .linspace (xmin , xmax , gridsize )
5530+
5531+ xcoarse = coarse_bin (xorig , C , coarse )
5532+ valid = ~ np .isnan (xcoarse )
5533+ verts , values = [], []
5534+ for i ,val in enumerate (xcoarse ):
5535+ thismin = coarse [i ]
5536+ if i < len (coarse )- 1 :
5537+ thismax = coarse [i + 1 ]
5538+ else :
5539+ thismax = thismin + np .diff (coarse )[- 1 ]
5540+
5541+ if not valid [i ]: continue
5542+
5543+ verts .append ([(thismin , 0 ), (thismin , 0.05 ), (thismax , 0.05 ), (thismax , 0 )])
5544+ values .append (val )
5545+
5546+ values = np .array (values )
5547+ trans = mtransforms .blended_transform_factory (
5548+ self .transData , self .transAxes )
5549+
5550+
5551+ hbar = mcoll .PolyCollection (verts , transform = trans , edgecolors = 'face' )
5552+
5553+ hbar .set_array (values )
5554+ hbar .set_cmap (cmap )
5555+ hbar .set_norm (norm )
5556+ hbar .set_alpha (alpha )
5557+ hbar .update (kwargs )
5558+ self .add_collection (hbar )
5559+
5560+ coarse = np .linspace (ymin , ymax , gridsize )
5561+ ycoarse = coarse_bin (yorig , C , coarse )
5562+ valid = ~ np .isnan (ycoarse )
5563+ verts , values = [], []
5564+ for i ,val in enumerate (ycoarse ):
5565+ thismin = coarse [i ]
5566+ if i < len (coarse )- 1 :
5567+ thismax = coarse [i + 1 ]
5568+ else :
5569+ thismax = thismin + np .diff (coarse )[- 1 ]
5570+ if not valid [i ]: continue
5571+ verts .append ([(0 , thismin ), (0.0 , thismax ), (0.05 , thismax ), (0.05 , thismin )])
5572+ values .append (val )
5573+
5574+ values = np .array (values )
5575+
5576+
5577+ trans = mtransforms .blended_transform_factory (
5578+ self .transAxes , self .transData )
5579+
5580+ vbar = mcoll .PolyCollection (verts , transform = trans , edgecolors = 'face' )
5581+ vbar .set_array (values )
5582+ vbar .set_cmap (cmap )
5583+ vbar .set_norm (norm )
5584+ vbar .set_alpha (alpha )
5585+ vbar .update (kwargs )
5586+ self .add_collection (vbar )
5587+
5588+
5589+
5590+ collection .hbar = hbar
5591+ collection .vbar = vbar
5592+
5593+ def on_changed (collection ):
5594+ hbar .set_cmap (collection .get_cmap ())
5595+ hbar .set_clim (collection .get_clim ())
5596+ vbar .set_cmap (collection .get_cmap ())
5597+ vbar .set_clim (collection .get_clim ())
5598+
5599+ collection .callbacksSM .connect ('changed' , on_changed )
5600+
54995601 return collection
55005602
55015603 hexbin .__doc__ = cbook .dedent (hexbin .__doc__ ) % martist .kwdocd
0 commit comments