Python matplotlib 堆叠条形图 -- 奇怪的结果

Python matplotlib stacked bar chart -- strange results

我正在尝试使用 Python 的 matplotlib 库在同一图上绘制四个堆叠条形图。

对于每个观察值(obs1、obs2、obs3、obs4),我想使用堆积条形图查看每个成分(c1、c2、c3、c4、c5、c6)的数量。这是我写的代码:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

data = np.array([[-904., 97., 59., 5., 252., 138.], [-603., 65., 0., 29., 0., 0.], [-571., -27., 0., -28., 0., 0.], [-80., 40., 0., -9., 0., 0.]])

data2 = pd.DataFrame(data=data)
data2.index = ['obs1', 'obs2', 'obs3', 'obs4']
data2.columns = ['c1', 'c2', 'c3', 'c4', 'c5', 'c6']

ind = np.arange(4)
width = 0.4

p1 = plt.bar(ind, data2['c1'], width)
p2 = plt.bar(ind, data2['c2'], width)
p3 = plt.bar(ind, data2['c3'], width)
p4 = plt.bar(ind, data2['c4'], width)
p5 = plt.bar(ind, data2['c5'], width)
p6 = plt.bar(ind, data2['c6'], width)

plt.legend((p1[0], p2[0], p3[0], p4[0], p5[0], p6[0]), tuple(data2.columns), bbox_to_anchor = (1.05, 1), loc = 'upper left', borderaxespad = 0.)

为清楚起见,这是 DataFrame(用于生成绘图):

print(data2)
         c1    c2    c3    c4     c5     c6
obs1 -904.0  97.0  59.0   5.0  252.0  138.0
obs2 -603.0  65.0   0.0  29.0    0.0    0.0
obs3 -571.0 -27.0   0.0 -28.0    0.0    0.0
obs4  -80.0  40.0   0.0  -9.0    0.0    0.0

剧情是这样的:

请注意图中,obs1 的条形位于 x=0,obs2 的条形位于 x=1,依此类推。

但是,有两个问题:

  1. obs1 对于组件 5 的值为 252,但组件 5 的高度(紫色)大大低于 252。我该如何解决这个问题?

  2. obs3 的分量 2 的值为 -27,但这根本没有显示在图上。我该如何解决?

谢谢。

这是因为当您绘图时,y 值参考取自 y=0,因此 obs1 分量 5 的紫色条实际上跨越 y=0y=252,并且由于顺序性质,它被组件 6 的条形图(稍后绘制)阻塞了 matplotlib 绘制了条形图块。

同理,obs3 component 2 因同样原因未显示

要获得您想要的堆叠条形图,您可以简单地使用 pandas 绘图界面进行绘图:

fig, ax = plt.subplots(1,1,figsize=(6,4))

data2.plot(kind='bar', stacked=True, ax=ax)

ax.set_xticklabels(ax.get_xticklabels(), rotation=0)

plt.show()

这正是您想要的:

附带说明一下,我建议为每个组件绘制一个单独的条形图,因为它们的比例非常不同,这将使观察之间的组件级别比较更加清晰:

fig, ax = plt.subplots(1, 6, figsize=(20,4))

for index, col in enumerate(data2.columns):
    data2[col].plot(kind='bar', ax=ax[index], color=f'C{index}', title=f'{col}')
    ax[index].grid(True)
    ax[index].set_xticklabels(ax[index].get_xticklabels(), rotation=0)

plt.show()

这给你: