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

基于多级索引分组的Python堆叠柱状图绘制及图例问题求助

问题1:解决多级索引下的堆叠柱状图生成问题

Pandas原生方法

分组后的数据存在多级索引(ID和Cat),直接plot会报错,我们可以用unstack()将多级索引转为宽表格式,再绘制堆叠柱状图:

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame({"Cat":["A", "B","A","B","A","B","A","B","C"], "Time":[0,0,1,1,0,0,1,1,1], "ID":[0,0,0,0,1,1,1,1,1]})

# 分组计数并转换为宽表,缺失类别用0填充
df_grouped = df.groupby(["ID", "Cat"])["Time"].count().unstack(fill_value=0)
# 绘制堆叠柱状图
df_grouped.plot(kind="bar", stacked=True, figsize=(8, 5))

plt.xlabel("ID")
plt.ylabel("Time计数")
plt.title("按ID分组的Cat堆叠计数")
plt.legend(title="Cat")
plt.show()

unstack(fill_value=0)会把Cat的不同类别转为列,确保每个ID对应的所有Cat类别都有数值,Pandas就能正确识别X轴为ID,自动生成堆叠效果。

Seaborn方法

Seaborn没有原生的堆叠柱状图API,我们可以结合Matplotlib的bar函数手动实现堆叠,同时使用Seaborn的配色方案:

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

df = pd.DataFrame({"Cat":["A", "B","A","B","A","B","A","B","C"], "Time":[0,0,1,1,0,0,1,1,1], "ID":[0,0,0,0,1,1,1,1,1]})

# 先计算每个ID和Cat的计数
counts = df.groupby(["ID", "Cat"])["Time"].count().reset_index(name="Count")

ids = counts["ID"].unique()
cats = counts["Cat"].unique()
# 使用Seaborn的配色方案
colors = sns.color_palette("husl", len(cats))

fig, ax = plt.subplots(figsize=(8, 5))
bottom = np.zeros(len(ids))  # 初始堆叠底部位置为0

for cat, color in zip(cats, colors):
    # 筛选当前类别的数据
    cat_data = counts[counts["Cat"] == cat]
    # 绘制柱子,bottom参数控制堆叠的起始位置
    ax.bar(cat_data["ID"], cat_data["Count"], bottom=bottom, label=cat, color=color)
    # 更新下一个类别的底部位置
    bottom += cat_data["Count"].values

ax.set_xlabel("ID")
ax.set_ylabel("Time计数")
ax.set_title("按ID分组的Cat堆叠计数")
ax.legend(title="Cat")
sns.despine()  # 去除多余边框
plt.show()

问题2:解决图例超出绘图窗口的问题

针对你使用seaborn.objects(so)的代码,图例超出窗口通常是因为绘图宽度不足或图例位置不合理,可通过以下几种方式解决:

方法1:将图例移至绘图区域外

通过bbox_to_anchor参数把图例放在图的右侧,同时用tight_layout()调整布局避免内容裁剪:

import pandas as pd
import seaborn.objects as so
import matplotlib.pyplot as plt
import datetime as dt

# 假设df和变量c已定义
p = so.Plot(df.astype({"Time": "category"}), x='Time', color='Cat').add(so.Bar(), so.Count(), so.Stack())
fig, ax = plt.subplots(figsize=(2560/120, 1335/120))
today = dt.datetime.today().strftime("%Y%m%d")
plt.grid()

# 绘制图形
p.on(ax).plot()
# 调整图例位置到图外
ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left', title="Cat")
# 手动调整布局范围,给图例留出空间
plt.tight_layout(rect=[0, 0, 0.85, 1])

# 保存时加上bbox_inches='tight'确保图例被完整保存
plt.savefig(f"{today}_barchart_sources_{c}.png", bbox_inches='tight')
plt.close()

方法2:增大绘图宽度

直接调整figsize的宽度参数,给图例留出足够空间:

# 增大宽度,比如从2560/120改为3000/120
fig, ax = plt.subplots(figsize=(3000/120, 1335/120))

方法3:将图例拆分为多列

如果Cat类别较多,可把图例分成多列,减少横向占用的宽度:

ax.legend(ncol=2, title="Cat")
plt.tight_layout()

注意:代码中color='Category'应为color='Cat'(匹配你的测试数据列名),否则会出现列名不存在的错误。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 14:52:27