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...
A bar 3D chart represents quantitative information. The chart consists of horizontally aligned rectangular bars of equal width with lengths proportional to the values they represent, something that aids in instant comparison of data. One axis of the chart plots categories and the other axis represents the value scale.
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:
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()
The results are given below:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With