如何基于多级透视表创建堆叠柱状图
解决方案:实现每月分年份的堆叠柱状图
要实现你需要的「每个月对应3个年份柱子,每个柱子内堆叠casual和member数据」的效果,我们可以通过调整透视表结构或使用Seaborn手动绘制堆叠柱两种方式实现,以下是具体步骤:
方法一:调整透视表结构,用Pandas直接绘图
你的原始透视表列层级是(year, usertype),我们可以通过重塑数据,将year移到索引层级,让usertype作为列,这样就能直接绘制出符合需求的堆叠柱状图:
# 重塑透视表:将year从列层级移到索引层级,usertype作为列 pivot_reshaped = pivotCust.stack(level='year').unstack(level='usertype') # 绘制堆叠柱状图 ax = pivot_reshaped.plot(kind='bar', stacked=True, figsize=(17,10)) # 优化图表样式 ax.set_xlabel('月份') ax.set_ylabel('出行次数') ax.set_title('各年份不同用户类型的月度出行次数(堆叠柱状图)') # 将图例移到图表外侧,避免遮挡 ax.legend(title='用户类型', bbox_to_anchor=(1.05, 1), loc='upper left')
效果说明
- X轴会显示
(月份, 年份)的组合,同一个月份的3个年份柱子会并排显示 - 每个柱子内部会堆叠
casual和member的数据,直观展示单年份内不同用户类型的占比
方法二:使用Melt转换长格式,结合Seaborn手动绘制
如果更偏好Seaborn的风格,可以先将透视表转换为长格式,再手动实现堆叠效果:
import seaborn as sns import matplotlib.pyplot as plt # 将透视表转换为长格式 df_melted = pivotCust.reset_index().melt( id_vars='month', var_name=['year', 'usertype'], value_name='count' ) # 设置绘图风格 sns.set_style("whitegrid") fig, ax = plt.subplots(figsize=(17,10)) # 定义柱子宽度和年份列表 width = 0.25 years = df_melted['year'].unique() months = df_melted['month'].unique() # 遍历每个年份,绘制堆叠柱 for idx, year in enumerate(years): # 筛选当前年份的两类用户数据 casual_data = df_melted[(df_melted['year'] == year) & (df_melted['usertype'] == 'casual')].set_index('month')['count'] member_data = df_melted[(df_melted['year'] == year) & (df_melted['usertype'] == 'member')].set_index('month')['count'] # 绘制casual柱子(底层) ax.bar( [x + idx*width for x in range(len(months))], casual_data, width=width, label=f'{year} casual' ) # 绘制member柱子(堆叠在casual上方) ax.bar( [x + idx*width for x in range(len(months))], member_data, bottom=casual_data, width=width, label=f'{year} member' ) # 调整X轴标签和刻度 ax.set_xticks([x + width for x in range(len(months))]) ax.set_xticklabels(months) # 设置图表标签和图例 ax.set_xlabel('月份') ax.set_ylabel('出行次数') ax.set_title('各年份不同用户类型的月度出行次数') ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left') plt.tight_layout() plt.show()
效果说明
- 该方法完全手动控制柱子的位置和堆叠逻辑,灵活性更高
- 同样实现「每月3个年份柱子,每个柱子堆叠两类用户」的需求,且Seaborn的样式更美观
方法三:拆分年份单独绘图(最直观的手动方式)
如果你希望更清晰地控制每个年份的柱子位置,可以直接拆分每个年份的透视表部分,分别绘制:
# 拆分出每个年份的子透视表 df_2019 = pivotCust['2019'] df_2020 = pivotCust['2020'] df_2021 = pivotCust['2021'] # 创建画布 fig, ax = plt.subplots(figsize=(17,10)) # 分别绘制三个年份的堆叠柱,设置不同的位置偏移实现并排 df_2019.plot(kind='bar', stacked=True, width=0.25, position=0, ax=ax, label=['2019 casual', '2019 member']) df_2020.plot(kind='bar', stacked=True, width=0.25, position=1, ax=ax, label=['2020 casual', '2020 member']) df_2021.plot(kind='bar', stacked=True, width=0.25, position=2, ax=ax, label=['2021 casual', '2021 member']) # 优化图表 ax.set_xlabel('月份') ax.set_ylabel('出行次数') ax.set_title('各年份不同用户类型的月度出行次数') ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left') plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者Feikname
相关产品推荐
相关产品推荐

