如何用Pandas实现按星期分组的年度堆叠柱状图并列展示?
需求与问题描述
- 需绘制两组堆叠柱状图:每组内为对应年份各月数据堆叠,两组(2022/2023年)按星期几分组并列展示
- 原始数据:
size_array = ("sun", "mon", "tue", "wed", "thr", "fri",) jan_2022 = [11,12,11,14,18,24] feb_2022 = [3,3,3,5,7,11] mar_2022 = [2,2,7,32,103,242] apr_2022 = [13,13,13,13,13,13] jan_2023 = [10,11,12,15,16,27] feb_2023 = [4,3,4,6,8,13] mar_2023 = [3,4,7,41,145,351] apr_2023 = [10,9,9,10,9,9]
- 尝试代码未得到期望效果:
df1 = pd.DataFrame({"Jan (2022)":jan_2022, "Feb (2022)":feb_2022, "March (2022)":mar_2022, "April (2022)":apr_2022}, index=size_array) df1.plot.bar(stacked=True, rot=0, width=0.5, color=plt.cm.Pastel1(np.linspace(0,1,8))) df2 = pd.DataFrame({"Jan (2023)":jan_2023, "Feb (2023)":feb_2023, "March (2023)":mar_2023, "April (2023)":apr_2023}, index=size_array) df2.plot.bar(stacked=True, rot=0, width=0.5, color=plt.cm.Pastel1(np.linspace(0,1,8))) df4 = pd.concat([df1, df2], axis=0, ignore_index=False) ax = df4.plot.bar(rot=0, width=0.5, color=plt.cm.Pastel1(np.linspace(0,1,8)))
- 期望效果:
- 2022年各月数据堆叠为单个柱,2023年各月数据同理堆叠
- 同一星期的2022/2023堆叠柱并列展示
解决方案
要实现堆叠+并列的组合柱状图,需调整数据结构并手动控制柱子位置,完整代码如下:
import pandas as pd import matplotlib.pyplot as plt import numpy as np # 原始数据 size_array = ("sun", "mon", "tue", "wed", "thr", "fri",) jan_2022 = [11,12,11,14,18,24] feb_2022 = [3,3,3,5,7,11] mar_2022 = [2,2,7,32,103,242] apr_2022 = [13,13,13,13,13,13] jan_2023 = [10,11,12,15,16,27] feb_2023 = [4,3,4,6,8,13] mar_2023 = [3,4,7,41,145,351] apr_2023 = [10,9,9,10,9,9] # 整理为多层列索引DataFrame,方便按年份/月份提取数据 data_2022 = pd.DataFrame([jan_2022, feb_2022, mar_2022, apr_2022], index=["Jan", "Feb", "Mar", "Apr"], columns=size_array).T data_2023 = pd.DataFrame([jan_2023, feb_2023, mar_2023, apr_2023], index=["Jan", "Feb", "Mar", "Apr"], columns=size_array).T df = pd.concat([data_2022, data_2023], axis=1, keys=["2022", "2023"]) # 设置柱子宽度与x轴位置 width = 0.35 x = np.arange(len(size_array)) # 创建画布与轴对象 fig, ax = plt.subplots(figsize=(10,6)) # 绘制2022年堆叠柱 bottom_2022 = np.zeros(len(size_array)) for month in df["2022"].columns: ax.bar(x - width/2, df["2022"][month], width, bottom=bottom_2022, label=f"2022 - {month}") bottom_2022 += df["2022"][month] # 绘制2023年堆叠柱 bottom_2023 = np.zeros(len(size_array)) for month in df["2023"].columns: ax.bar(x + width/2, df["2023"][month], width, bottom=bottom_2023, label=f"2023 - {month}") bottom_2023 += df["2023"][month] # 美化图表 ax.set_xticks(x) ax.set_xticklabels(size_array) ax.set_xlabel("星期几") ax.set_ylabel("数值") ax.set_title("2022与2023年各月数据按星期堆叠对比") ax.legend(bbox_to_anchor=(1.05, 1), loc="upper left") plt.tight_layout() plt.show()
代码说明
- 用多层列索引整合两年数据,便于批量提取年份/月份维度的数据
- 通过
x - width/2和x + width/2分别定位2022/2023年的柱子,实现并列效果 - 利用
bottom参数累计各月数据,完成堆叠效果 - 调整图例位置避免遮挡图表,优化整体布局
内容的提问来源于stack exchange,提问作者yolo_ML
相关产品推荐
相关产品推荐

