How can I bin 3d points into 3d bins? Is there a multi dimensional version for np.digitize? I can use np.digitize separately for each dimension, like here. Is there a better solution? Thanks!
Asked
Active
Viewed 6,351 times
5
-
An important difference between calling np.digitize separately for each dimension and np.histogramdd is the following property of np.digitize: "If values in x are beyond the bounds of bins, 0 or len(bins) is returned as appropriate". This is not the case in np.histogramdd when specifying a sequence of arrays describing the bin edges along each dimension. – Noam Peled Oct 02 '15 at 03:38
1 Answers
8
You can do this with numpy.histogramdd(sample)
, where the number of bins in each direction and the physical range can be adjusted as with a 1D histogram. More info on the reference page. For more general statistics, like the mean of another variable per point in a bin, you can use the scipy scipy.stats.binned_statistic_dd
function, see docs.
For your case with an array of three dimensional points, you would use this in the following way,
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from scipy import stats
#Setup some dummy data
points = np.random.randn(1000,3)
hist, binedges = np.histogramdd(points, normed=False)
#Setup a 3D figure and plot points as well as a series of slices
fig = plt.figure()
ax1 = fig.add_subplot(111, projection='3d')
ax1.plot(points[:,0],points[:,1],points[:,2],'k.',alpha=0.3)
#Use one less than bin edges to give rough bin location
X, Y = np.meshgrid(binedges[0][:-1],binedges[1][:-1])
#Loop over range of slice locations (default histogram uses 10 bins)
for ct in [0,2,5,7,9]:
cs = ax1.contourf(X,Y,hist[:,:,ct],
zdir='z',
offset=binedges[2][ct],
level=100,
cmap=plt.cm.RdYlBu_r,
alpha=0.5)
ax1.set_xlim(-3, 3)
ax1.set_ylim(-3, 3)
ax1.set_zlim(-3, 3)
plt.colorbar(cs)
plt.show()
which gives a series of histogram slices of occupancy at each location,

Ed Smith
- 12,716
- 2
- 43
- 55
-
Thanks! Exactly what I was searching for. Also, your demonstration is really cool! – Noam Peled Oct 01 '15 at 19:07
-
For Python 3.9.13, the argument `level=100` is no longer supported, so perhaps the answer could be updated to reflect that? – user185160 Jan 24 '23 at 21:31
-
@user185160, I think this will depend on matplotlib version instead of Python version. Which version are you using? It looks like it has been replaced by `levels` from the `matplotlib 3.6.3` documentation (I can't tests without updating, if `levels=100` works for you I'lll update the answer) – Ed Smith Jan 25 '23 at 11:53