Matplotlib 3D 条形图:轴问题

3

我在获取x,y,z轴上的数据时遇到了问题。以下是我的代码。我定义range(dx,dy.dz)的方式是否有问题?

result=[['122', '109', '2343', '220', '19'],
 ['15', '407', '37', '10', '102'],
 ['100', '100', '100', '100', '100'],
 ['113', '25', '19', '31', '112'],
 ['43', '219', '35', '33', '14'],
 ['132', '108', '256', '119', '14'],
 ['22', '48', '352', '51', '438']]

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.dates as dates

def format_date(x, pos=None):
     return dates.num2date(x).strftime('%m/%d/%Y')

fig=plt.figure()
ax1=fig.add_subplot(111,projection='3d')

xpos=[10/11/2013,10/12/2013,10/13/2013,10/14/2013,10/15/2013]
ypos=['A1','C1','G1','M1','M2','M3','P1']
zpos=result

dx=[5]
dy=[7]
dz=[7]
ax1.w_xaxis.set_major_formatter(ticker.FuncFormatter(format_date))
ax1.bar3d(xpos,ypos,zpos,dx,dy,dz,color='#00ceaa')
plt.show()

我收到了以下错误信息:
TypeError                                 Traceback (most recent call last)
<ipython-input-45-02cd8e7ee228> in <module>()
     18 dz=[17]
     19 ax1.w_xaxis.set_major_formatter(ticker.FuncFormatter(format_date))
---> 20 ax1.bar3d(xpos,ypos,zpos,dx,dy,dz,color='#00ceaa')
     21 plt.show()

C:\Users\Andalib\Anaconda\lib\site-packages\mpl_toolkits\mplot3d\axes3d.py in bar3d(self, x, y, z, dx, dy, dz, color, zsort, *args, **kwargs)
   2316             maxx = max(xi + dxi, maxx)
   2317             miny = min(yi, miny)
-> 2318             maxy = max(yi + dyi, maxy)
   2319             minz = min(zi, minz)
   2320             maxz = max(zi + dzi, maxz)

TypeError: cannot concatenate 'str' and 'int' objects

你的 xpos 应该是一个字符串列表 ["10/11/2013", "10/12/2013", "10/13/2013", "10/14/2013", "10/15/2013"] - Saullo G. P. Castro
我已经这样做了...但仍然得到与上述相同的错误。 - user3632319
2个回答

6
您的代码存在以下问题:
  • xposypos通常是一个扁平化的网格,包含3D条形图基部的位置。
  • zpos给出了沿着z轴的基准位置,通常为零,除非您希望条形图看起来像在飞行。
  • xposyposzpos必须具有相同的扁平化形状,并且都必须是1-D数组。
由于您已经知道每个值的位置,因此可以使用np.arange()创建位置xposypos,然后设置刻度标签。
示例代码如下:
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm

result=[['122', '109', '2343', '220', '19'],
 ['15', '407', '37', '10', '102'],
 ['100', '100', '100', '100', '100'],
 ['113', '25', '19', '31', '112'],
 ['43', '219', '35', '33', '14'],
 ['132', '108', '256', '119', '14'],
 ['22', '48', '352', '51', '438']]

result = np.array(result, dtype=np.int)

fig=plt.figure(figsize=(5, 5), dpi=150)
ax1=fig.add_subplot(111, projection='3d')

xlabels = np.array(['10/11/2013', '10/12/2013', '10/13/2013',
                    '10/14/2013', '10/15/2013'])
xpos = np.arange(xlabels.shape[0])
ylabels = np.array(['A1','C1','G1','M1','M2','M3','P1'])
ypos = np.arange(ylabels.shape[0])

xposM, yposM = np.meshgrid(xpos, ypos, copy=False)

zpos=result
zpos = zpos.ravel()

dx=0.5
dy=0.5
dz=zpos

ax1.w_xaxis.set_ticks(xpos + dx/2.)
ax1.w_xaxis.set_ticklabels(xlabels)

ax1.w_yaxis.set_ticks(ypos + dy/2.)
ax1.w_yaxis.set_ticklabels(ylabels)

values = np.linspace(0.2, 1., xposM.ravel().shape[0])
colors = cm.rainbow(values)
ax1.bar3d(xposM.ravel(), yposM.ravel(), dz*0, dx, dy, dz, color=colors)
plt.show()

这将给出:

输入图片描述

您还可以使用与dz成比例的values数组:

values = (dz-dz.min())/np.float_(dz.max()-dz.min())

enter image description here


每行或每条线都随机分配颜色,这是否可行? - user3632319
我已经更新了答案,为每个条形图添加了颜色。请注意,您可以使用matplotlib.cm中包含的任何颜色比例尺,我使用了rainbow,但您也应该检查其他颜色比例尺... - Saullo G. P. Castro
@user3632319 如果你只想改变一行或一列,你需要操作values数组... - Saullo G. P. Castro
@user3632319 别忘了你可以点赞这个答案 ;) - Saullo G. P. Castro
@SaulloG.P.Castro 很好,我运行了完全相同的代码,但是每个条形图周围都没有黑色描边,出了什么问题? - Mehdi

0

正如错误提示所示,您的result列表必须包含整数而不是字符串。您可以使用列表推导式将其转换为整数:

result = [[int(i) for i in sublist] for sublist in result]

或者更好的是,您可以使用np.array

import numpy as np
result = np.array(result, dtype=np.int)

更新:

根据文档(和示例)中的建议,ipos数组应该包含条形图的位置;di数组应该包含条形之间的距离。而你的 xposypos 列表所包含的是刻度标签,因此你需要对它们进行更改,并将相应轴的刻度标签设置为给定的 xposypos 值。根据提供的示例,你可以按照以下方式实现:

xpos, ypos = np.meshgrid(np.arange(5)+0.5, np.arange(7)+0.5)
xpos = xpos.flatten()
ypos = ypos.flatten()
zpos = np.zeros(5*7)
dx = np.ones_like(zpos)
dy = dx.copy()
dz = result.flatten()
xticks=['','10/11/2013','10/12/2013','10/13/2013','10/14/2013','10/15/2013']
yticks=['','A1','C1','G1','M1','M2','M3','P1']
ax1.set_xticklabels(xticks)
ax1.set_yticklabels(yticks)

我已经按照您上面的代码将我的结果列表进行了转换,但仍然出现相同的错误。 - user3632319
是的,似乎bar3d的工作方式完全不同。我会编辑我的答案。 - Andrey Sobolev

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