Plot a 3D bar histogram with python
Solution 1
I finaly succeded in doing it. I am almost sure there is a better way to do it, but at leat it works:
import numpy as np
import numpy.random
import matplotlib.pyplot as plt
# To generate some test data
x = np.random.randn(500)
y = np.random.randn(500)
XY = np.stack((x,y),axis=-1)
def selection(XY, limitXY=[[-2,+2],[-2,+2]]):
XY_select = []
for elt in XY:
if elt[0] > limitXY[0][0] and elt[0] < limitXY[0][1] and elt[1] > limitXY[1][0] and elt[1] < limitXY[1][1]:
XY_select.append(elt)
return np.array(XY_select)
XY_select = selection(XY, limitXY=[[-2,+2],[-2,+2]])
xAmplitudes = np.array(XY_select)[:,0]#your data here
yAmplitudes = np.array(XY_select)[:,1]#your other data here
fig = plt.figure() #create a canvas, tell matplotlib it's 3d
ax = fig.add_subplot(111, projection='3d')
hist, xedges, yedges = np.histogram2d(x, y, bins=(7,7), range = [[-2,+2],[-2,+2]]) # you can change your bins, and the range on which to take data
# hist is a 7X7 matrix, with the populations for each of the subspace parts.
xpos, ypos = np.meshgrid(xedges[:-1]+xedges[1:], yedges[:-1]+yedges[1:]) -(xedges[1]-xedges[0])
xpos = xpos.flatten()*1./2
ypos = ypos.flatten()*1./2
zpos = np.zeros_like (xpos)
dx = xedges [1] - xedges [0]
dy = yedges [1] - yedges [0]
dz = hist.flatten()
cmap = cm.get_cmap('jet') # Get desired colormap - you can change this!
max_height = np.max(dz) # get range of colorbars so we can normalize
min_height = np.min(dz)
# scale each z to [0,1], and get their rgb values
rgba = [cmap((k-min_height)/max_height) for k in dz]
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color=rgba, zsort='average')
plt.title("X vs. Y Amplitudes for ____ Data")
plt.xlabel("My X data source")
plt.ylabel("My Y data source")
plt.savefig("Your_title_goes_here")
plt.show()
I use this example, but I modified it, because it introduced an offset. The result is this:
Solution 2
You can generate the same result using something as simple as the following:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-2, 2, 7)
y = np.linspace(-2, 2, 7)
xx, yy = np.meshgrid(x, y)
z = xx*0+yy*0+ np.random.random(size=[7,7])
plt.imshow(z, interpolation='nearest', cmap=plt.cm.viridis, extent=[-2,2,2,2])
plt.show()
from mpl_toolkits.mplot3d import Axes3D
ax = Axes3D(plt.figure())
ax.plot_surface(xx, yy, z, cmap=plt.cm.viridis, cstride=1, rstride=1)
plt.show()
![Agape Gal'lo](https://i.stack.imgur.com/BN2wv.jpg?s=256&g=1)
Agape Gal'lo
Updated on June 09, 2022Comments
-
Agape Gal'lo about 2 years
I have some x and y data, with which I would like to generate a 3D histogram, with a color gradient (bwr or whatever).
I have written a script which plot the interesting values, in between -2 and 2 for both x and y abscesses:
import numpy as np import numpy.random import matplotlib.pyplot as plt # To generate some test data x = np.random.randn(500) y = np.random.randn(500) XY = np.stack((x,y),axis=-1) def selection(XY, limitXY=[[-2,+2],[-2,+2]]): XY_select = [] for elt in XY: if elt[0] > limitXY[0][0] and elt[0] < limitXY[0][1] and elt[1] > limitXY[1][0] and elt[1] < limitXY[1][1]: XY_select.append(elt) return np.array(XY_select) XY_select = selection(XY, limitXY=[[-2,+2],[-2,+2]]) heatmap, xedges, yedges = np.histogram2d(XY_select[:,0], XY_select[:,1], bins = 7, range = [[-2,2],[-2,2]]) extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]] plt.figure("Histogram") #plt.clf() plt.imshow(heatmap.T, extent=extent, origin='lower') plt.show()
And give this correct result:
Now, I would like to turn this into a 3D histogram. Unfortunatly I don't success to plot it correctly with
bar3d
because it takes by default the length of x and y for abscisse.I am quite sure that there is a very easy way to plot this in 3D with imshow. Like an unknow option...
-
Agape Gal'lo almost 6 yearsSorry, but it would be better if you use the same x, y and heatmap.T datas. You change the exep
-
Agape Gal'lo almost 6 yearsThanks! But sorry, but it would be better if you use the same x, y and heatmap.T datas. You change the example a bit. Also, could we have some flat levels instead of the tilts surfaces ?
-
Agape Gal'lo almost 6 yearsAnd also, there is a problem I had not notice before: There are 7x7 delimitations for the 2D colored histogram, and 6 for the other one ! Which make it dangerous to observe for data analysis... What would be great is a 7x7 flat square levels, in 3D. @kanayamalakar
-
kanayamalakar almost 6 years@AgapeGal'lo, could you show me a picture of how you want the 3D plot to be - maybe just a representative one ? Because I don't seem to get what you mean by flat square levels in 3D.
-
kanayamalakar almost 6 yearsYou can look at this link matplotlib.org/examples/mplot3d/…
-
kanayamalakar almost 6 yearsThe difference in the 2D and 3D plots are : In 2D, the data point lies at the center of each box. Whereas in 3D the data points lie at the corner of the boxes. The line segments join adjacent data points and form grids. Hence for 7x7 data points you get (7-1)x(7-1) sized grid.
-
Agape Gal'lo almost 6 yearsYes, I had understood, but it's not what you expect in a 3 histogram...
-
kanayamalakar almost 6 yearsWell done ! I was having trouble with applying a color scheme. Thanks for sharing
-
Agape Gal'lo almost 6 years@kanayamalakar but there is a problem in the renormalisation for the colors... If after this line 'hist, xedges, yedges = np.histogram2d(x, y, bins=(7,7), range = [[-2,+2],[-2,+2]]) # you can change your bins, and the range on which to take data' you replace hist by an other 7X7 matrix, the colors are not anymore well scale. I don't understand why ! There should a better way to get this color gradiant.
-
Daniel González Cortés over 3 yearsPerhaps you can add "import matplotlib.cm as cm"