绘制一个三维条形直方图。

6
我有一些x和y的数据,想要生成一个带有颜色渐变(bwr或其他)的3D直方图。
我编写了一个脚本,绘制了在x和y的绝对值范围在-2到2之间的有趣数值:
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()

并返回正确的结果:

enter image description here

现在,我想将它转换成一个3D直方图。不幸的是,我无法通过bar3d正确地绘制它,因为它默认采用x和y的长度作为横坐标。

我相信用imshow很容易以3D形式绘制这个图像。就像一个未知选项一样...


1
除非您使用mplot3d,否则matplotlib不支持3D绘图。 - Pierre de Buyl
2
你有查看官方文档(https://matplotlib.org/examples/mplot3d/hist3d_demo.html)吗?那里有一个简单的例子。 - norok2
1
我不明白这个x,y数据是用来做什么的。我猜你有一个等间距的网格,在每个方格上应该有一些随机值。 - kanayamalakar
给norok2:是的,我已经看过了,但是这些例子(包括你的)并不符合我所寻找的内容... - Agape Gal'lo
给kanayamalakar:我正在进行数据处理,有带有x和y坐标的点。然后,我想重新创建一个直方图来查看哪些事件更加频繁发生。首先,我要对它们进行过滤,只保留在区间内的点。 - Agape Gal'lo
1
这个链接提供的示例似乎可以直接应用。如果那不是“我要找的”,你需要告诉别人它有多大程度上不适用,否则别人就无法知道问题出在哪里。(如果你想通知某人,请使用@用户名,否则他们将看不到它) - ImportanceOfBeingErnest
3个回答

13

我终于成功了。我几乎确定有更好的方法可以做到,但至少它现在有效:

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()
我使用了这个示例,但是我修改了它,因为它引入了一个偏移量。结果就是这个:

enter image description here


1
干得好!我在应用配色方案方面遇到了麻烦。感谢分享。 - kanayamalakar
@kanayamalakar 但是颜色的归一化存在问题... 如果在这行代码 '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' 后,你用另一个7X7矩阵替换hist,那么颜色就不再被正确地缩放。我不明白为什么!应该有更好的方法来获得这种颜色渐变。 - Agape Gal'lo
1
也许你可以添加 "import matplotlib.cm as cm" - Daniel González Cortés

5
您可以使用以下简单的方法生成相同的结果:
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()

以下是结果: 输入图像描述 曲面图

抱歉,但最好使用相同的 x、y 和 heatmap.T 数据。你改变了 exep。 - Agape Gal'lo
谢谢!但是很抱歉,如果您使用相同的x、y和heatmap.T数据会更好。您可以稍微修改一下示例。此外,我们能否使用一些平面级别而不是倾斜表面? - Agape Gal'lo
@AgapeGal'lo,你能给我展示一下你想要的3D图形吗?也许只需要一个代表性的图形?因为我似乎不明白你所说的“平面方块水平线”在3D中是什么意思。 - kanayamalakar
1
2D和3D图的区别在于:在2D中,数据点位于每个框的中心。而在3D中,数据点位于框的角落。线段连接相邻的数据点并形成网格。因此,对于7x7个数据点,您将获得(7-1)x(7-1)大小的网格。 - kanayamalakar
是的,我理解了,但这不是你在三个直方图中期望的结果... - Agape Gal'lo
显示剩余2条评论

0
这篇帖子中的被接受的答案很好,但是它有一个bug。需要进行以下修复之一,否则数据看起来是镜像的。
dz = np.transpose(hist).flatten() 或者 ypos, xpos = np.meshgrid(yedges[:-1] + yedges[1:], xedges[:-1] + xedges[1:])
当你展平np.histogram2d的输出时,你会得到每个x后面堆叠的完整一行y值。 然后展平meshgrid的输出时,你会得到递增的x和固定的y沿着数组堆叠。因此,两者不再匹配。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接