如何用Pandas分组绘制指定样式的堆叠柱状图?
实现Pandas分组堆叠并列柱状图的解决方案
需求说明
现有数据集包含日期、两类版本用户及对应花费,结构如下:
date_time version_A spend_A version_B spend_B 2022-07-30 User1 39734.582 User1 15354.253 2022-07-30 User2 11720.6742 User2 3486.8551 ... ... ... ... ... 2022-08-12 User5 111739.7095 User5 39797.8841
需要绘制的图表要求:
- X轴为
date_time - 每个日期对应两个并列的堆叠柱状图:分别展示
spend_A和spend_B的总花费 - 每个堆叠柱内按
version_A(与version_B用户一一对应)的不同用户拆分,用颜色区分
问题分析
直接使用Pandas的plot(kind='bar', stacked=True)会将spend_A和spend_B堆叠到同一柱形中,无法实现并列效果;简单分组后的图表可读性差,需要调整数据结构并手动控制绘图逻辑。
解决方案
步骤1:数据整理与聚合
先将宽表转换为适合堆叠绘图的结构,再按日期、类别、用户聚合总花费:
import pandas as pd # 拆分spend_A和spend_B数据并合并为长表 df_a = df[['date_time', 'version_A', 'spend_A']].rename(columns={'version_A': 'user', 'spend_A': 'amount'}) df_a['category'] = 'spend_A' df_b = df[['date_time', 'version_B', 'spend_B']].rename(columns={'version_B': 'user', 'spend_B': 'amount'}) df_b['category'] = 'spend_B' df_long = pd.concat([df_a, df_b], ignore_index=True) # 按日期、类别、用户聚合求和 df_agg = pd.pivot_table(df_long, index='date_time', columns=['category', 'user'], values='amount', aggfunc='sum')
步骤2:绘制并列堆叠柱状图
使用Matplotlib手动控制柱子位置,实现spend_A和spend_B的并列堆叠效果:
import matplotlib.pyplot as plt dates = df_agg.index.values n_dates = len(dates) width = 0.35 # 柱子宽度 fig, ax = plt.subplots(figsize=(12, 6)) # 绘制spend_A的堆叠柱(左列) bottom_a = [0] * n_dates for user in df_agg['spend_A'].columns: ax.bar( [i - width/2 for i in range(n_dates)], df_agg['spend_A'][user], width, bottom=bottom_a, label=f'spend_A - {user}' ) bottom_a = [b + val for b, val in zip(bottom_a, df_agg['spend_A'][user])] # 绘制spend_B的堆叠柱(右列) bottom_b = [0] * n_dates for user in df_agg['spend_B'].columns: ax.bar( [i + width/2 for i in range(n_dates)], df_agg['spend_B'][user], width, bottom=bottom_b, label=f'spend_B - {user}' ) bottom_b = [b + val for b, val in zip(bottom_b, df_agg['spend_B'][user])] # 配置图表样式 ax.set_xticks(range(n_dates)) ax.set_xticklabels(dates, rotation=45) ax.set_xlabel('日期') ax.set_ylabel('总花费') ax.set_title('每日spend_A与spend_B用户堆叠花费对比') # 调整图例位置避免遮挡 ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left') plt.tight_layout() plt.show()
效果说明
执行上述代码后,每个日期下会生成两个并列的堆叠柱:
- 左侧柱为
spend_A的用户花费堆叠 - 右侧柱为
spend_B的用户花费堆叠
不同用户用不同颜色区分,清晰展示各维度的花费分布。
内容的提问来源于stack exchange,提问作者Geosphere
相关产品推荐
相关产品推荐

