You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于共享时间戳的三个分组DataFrame绘制堆叠柱状图?

问题

我有三个分组DataFrame,都包含TIMESTAMP、类别列和count列,且共享相同时间戳。单个DataFrame可以用以下代码成功绘制堆叠柱状图:

df.pivot_table(index='timestamp', columns='category1', values='count', aggfunc='mean').plot(kind='bar', stacked=True)

但我想在同一画布的三个子轴上分别绘制这三个DataFrame的堆叠柱状图,尝试下面的代码却无法运行:

fig, (ax1, ax2, ax3) = plt.subplots(1, 3)
ax1.bar(x=df.index, y='category1', data=df1, stacked=True) 
ax2.bar(x=df.index, y='category2', data=df2, stacked=True)
ax3.bar(x=df.index, y='category3', data=df3, stacked=True)

不能使用Seaborn库,看到过循环解决方案但没明确对应列,求可行建议。

数据示例:

TIMESTAMP        CATEGORY_1  count
0   2023-03-31        correct     30
1   2023-03-31    not correct     11
2   2023-03-31        no info      2
3   2023-04-30        correct     15
4   2023-04-30    not correct      8

  TIMESTAMP             CATEGORY_2  count
0   2023-03-31                okay     29
1   2023-03-31             no info     17
2   2023-03-31             too high     4

  TIMESTAMP       CATEGORY_3  count
0   2023-03-31                 okay      4
1   2023-03-31              no info      2
2   2023-03-31             positive      3
3   2023-03-31             negative      2
解决方案

你之前的代码跑不通,是因为原生matplotlib的ax.bar方法里的stacked参数根本不是用来实现堆叠的(这个参数是控制水平柱状图的对齐方式,和堆叠逻辑无关)。其实不用折腾原生bar,直接沿用你熟悉的pandas透视+绘图逻辑,指定每个图的子轴就行,简单高效。

方法1:逐个处理每个DataFrame

直接对每个DataFrame做透视,然后把图画到对应的子轴上:

import matplotlib.pyplot as plt

# 创建1行3列的画布和子轴,设置合适的尺寸
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(15, 6))

# 第一个子轴:处理df1并绘图
df1_pivot = df1.pivot_table(index='TIMESTAMP', columns='CATEGORY_1', values='count', aggfunc='mean')
df1_pivot.plot(kind='bar', stacked=True, ax=ax1)
ax1.set_title('CATEGORY_1 堆叠柱状图')
ax1.tick_params(axis='x', rotation=45)  # 旋转x轴标签避免重叠

# 第二个子轴:处理df2并绘图
df2_pivot = df2.pivot_table(index='TIMESTAMP', columns='CATEGORY_2', values='count', aggfunc='mean')
df2_pivot.plot(kind='bar', stacked=True, ax=ax2)
ax2.set_title('CATEGORY_2 堆叠柱状图')
ax2.tick_params(axis='x', rotation=45)

# 第三个子轴:处理df3并绘图
df3_pivot = df3.pivot_table(index='TIMESTAMP', columns='CATEGORY_3', values='count', aggfunc='mean')
df3_pivot.plot(kind='bar', stacked=True, ax=ax3)
ax3.set_title('CATEGORY_3 堆叠柱状图')
ax3.tick_params(axis='x', rotation=45)

# 自动调整子轴间距,避免标签重叠
plt.tight_layout()
plt.show()

方法2:用循环简化代码(减少重复)

如果三个DataFrame的处理逻辑完全一致,可以把相关参数打包成列表,用循环批量处理,避免重复写代码:

import matplotlib.pyplot as plt

# 打包需要处理的参数:(DataFrame对象, 类别列名称, 目标子轴, 图表标题)
plot_configs = [
    (df1, 'CATEGORY_1', ax1, 'CATEGORY_1 堆叠柱状图'),
    (df2, 'CATEGORY_2', ax2, 'CATEGORY_2 堆叠柱状图'),
    (df3, 'CATEGORY_3', ax3, 'CATEGORY_3 堆叠柱状图')
]

# 创建画布和子轴
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(15, 6))

# 循环处理每个配置
for df, cat_col, ax, title in plot_configs:
    # 透视表转换
    pivot_df = df.pivot_table(index='TIMESTAMP', columns=cat_col, values='count', aggfunc='mean')
    # 绘制堆叠柱状图到指定子轴
    pivot_df.plot(kind='bar', stacked=True, ax=ax)
    # 设置标题和x轴标签旋转
    ax.set_title(title)
    ax.tick_params(axis='x', rotation=45)

plt.tight_layout()
plt.show()

补充说明

原生ax.bar要实现堆叠,需要手动计算每个类别的底部位置(比如第一个类别底部是0,第二个类别底部是第一个类别的数值总和,以此类推),逻辑繁琐容易出错。而pandas的plot接口已经封装了堆叠的计算逻辑,只需要通过ax参数指定子轴,就能轻松把图画到对应位置,完全满足你的需求。

内容的提问来源于stack exchange,提问作者gulniza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 23:55:33