如何在python/matplotlib中自定义3D直方图的轴
我正在尝试用3D柱状图来绘制这个数据集。
B A freq
1 2003 2
1 2003 2
2 2008 1
2 2007 2
2 2007 2
3 2004 1
1 2004 3
1 2004 3
1 2004 3
我在这里写了代码。
data = pandas.DataFrame({'A':[2003,2003,2008,2007,2007,2004,2004,2004,2004] , 'B': [1,1,2,2,2,3,1,1,1] ,'C': [2,2,1,2,2,1,3,3,3] })
fig = plt.figure()
ax = plt.axes(projection='3d')
# put 0s on the y-axis, and put the y axis on the z-axis
#ax.plot(data.A.values, data.B.values,data.freq.values, marker='o', linestyle='--', color="blue", label='ys=0, zdir=z')
xpos= range(len( data.A.values))
ypos= range(len( data.B.values))
zpos= range(len( data.freq.values))
ax.bar3d(xpos, ypos, zpos, data.A.values, data.B.values,data.freq.values, color='b', alpha=0.5)
x_formatter = matplotlib.ticker.ScalarFormatter(useOffset=False)
ax.xaxis.set_major_formatter(x_formatter)
ax.set_xticks(data.A.values)
ax.set_yticks(data.B.values)
ax.set_zticks(data.freq.values)
plt.savefig("test.png", dpi=300)
plt.show()
但是这似乎不是正确的方法?有没有人能帮我,教我怎么自定义坐标轴?
当我使用 plot 时,它是可以工作的。
ax.plot(data.A.values, data.B.values,data.freq.values,marker='o', linestyle='--', color='r')
而不是 bar3D。
ax.bar3d(xpos, ypos, zpos, data.A.values, data.B.values,data.freq.values, color='b', alpha=0.5)
但我想用3D直方图,这样更容易理解。
2 个回答
2
你在很多地方都搞错了,所以我就直接发一下正确的样子:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
data = pd.DataFrame({'A': [1,1,2,2,2,3,1,1,1], 'B': [2003,2003,2008,2007,2007,2004,2004,2004,2004] ,'freq': [2,2,1,2,2,1,3,3,3] })
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# put 0s on the y-axis, and put the y axis on the z-axis
#ax.plot(data.A.values, data.B.values,data.freq.values, marker='o', linestyle='--', color="blue", label='ys=0, zdir=z')
PV = pd.pivot_table(data, values='freq',rows='A',cols='B')
xpos=np.arange(PV.shape[0])
ypos=np.arange(PV.shape[1])
xpos, ypos = np.meshgrid(xpos+0.25, ypos+0.25)
xpos = xpos.flatten()
ypos = ypos.flatten()
zpos=np.zeros(PV.shape).flatten()
dx=0.5 * np.ones_like(zpos)
dy=0.5 * np.ones_like(zpos)
dz=PV.values.ravel()
dz[np.isnan(dz)]=0.
ax.bar3d(xpos,ypos,zpos,dx,dy,dz,color='b', alpha=0.5)
ax.set_xticks([.5,1.5,2.5])
ax.set_yticks([.5,1.5,2.5,3.5])
ax.w_yaxis.set_ticklabels(PV.columns)
ax.w_xaxis.set_ticklabels(PV.index)
ax.set_xlabel('A')
ax.set_ylabel('B')
ax.set_zlabel('Occurrence')
plt.savefig("test.png", dpi=300)
plt.show()
6
看起来你对bar3d函数的参数有些误解:
bar3d(x, y, z, dx, dy, dz)
- 参数x、y和z分别是柱子在x、y和z轴上的坐标。
- 参数dx、dy和dz分别是柱子在x、y和z轴上的大小。
举个例子,如果你想绘制以下数据集:
{'A': [1, 2], 'B': [2003, 2008] ,'freq': [2, 3] }
你需要这样定义这些参数:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
xpos = [1, 2]
ypos = [2003, 2008]
zpos = [0, 0]
dx = 1
dy = 1
dz = [2, 3]
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.bar3d(xpos, ypos, zpos, dx, dy, dz)
plt.show()
这意味着:
- 你在(1, 2003, 0)这个位置绘制一根柱子(x, y, z),高度为2。
- 你在(2, 2008, 0)这个位置绘制另一根柱子(x, y, z),高度为3。
- 这两根柱子在x和y轴上的大小都是1,不过可以小一点,这只是美观问题。
上面的代码会生成以下图表:
如果你看看这个图,你会发现一些小的格式问题:
- 年份用的是科学计数法。
- 柱子没有正好在它们的(x, y)坐标中心。
其实我们可以通过一些小调整来解决这些问题:
import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
xpos = [1, 2]
ypos = [2003, 2008]
zpos = [0, 0]
dx = 1
dy = 1
dz = [2, 3]
# Move each (x, y) coordinate to center it on the tick
xpos = map(lambda x: x - 0.5, xpos)
ypos = map(lambda y: y - 0.5, ypos)
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.bar3d(xpos, ypos, zpos, dx, dy, dz)
# Do not print years in exponential notation
y_formatter = matplotlib.ticker.ScalarFormatter(useOffset=False)
ax.yaxis.set_major_formatter(y_formatter)
plt.show()
最后,我们会得到这样的结果: