如何制作带百分比标注的堆叠柱状图(Matplotlib实现)
堆叠柱状图实现方案
1. 数据格式转换
原DataFrame是长格式,需先转成宽格式(日期为索引、设备为列),才能直接绘制堆叠柱状图:
pivot_df = df.pivot(index='date', columns='device', values='count')
2. 自定义设备颜色
按需求定义每个设备对应的颜色:
color_map = {'tv': 'red', 'laptop': 'steelblue', 'cellphone': 'limegreen'}
3. 绘制堆叠柱状图
基于透视后的DataFrame绘制,同时配置轴标签、标题和图例:
fig, ax = plt.subplots(figsize=(10, 6)) pivot_df.plot(kind='bar', stacked=True, color=[color_map[col] for col in pivot_df.columns], ax=ax) # 配置图表样式 ax.set_xlabel('Date', fontsize=14) ax.set_ylabel('Count', fontsize=14) ax.set_title('Count of Viewing Type Over Time', fontsize=20) ax.legend(title='Device', bbox_to_anchor=(1.05, 1), loc='upper left') ax.tick_params(axis='x', rotation=45)
4. 添加堆叠区域百分比标注
遍历每个柱子的堆叠部分,计算当前部分占该柱子总计数的百分比,并标注在对应位置:
# 遍历每个日期对应的柱子 for i, date in enumerate(pivot_df.index): total = pivot_df.loc[date].sum() current_height = 0 # 遍历每个设备的计数 for device in pivot_df.columns: count = pivot_df.loc[date, device] if count == 0: continue # 计算百分比 percentage = f'{(count/total)*100:.1f}%' # 标注位置:x为柱子中心,y为当前堆叠高度的中间位置 ax.text(i, current_height + count/2, percentage, ha='center', va='center', fontsize=10) current_height += count
完整代码
import pandas as pd import matplotlib.pyplot as plt # 原始数据 df = pd.DataFrame(data = {'id' : ['hbo', 'hbo', 'hbo', 'fox','fox','fox', 'NBC', 'NBC', 'NBC'], 'device': ['laptop', 'tv', 'cellphone','laptop', 'tv', 'cellphone','laptop', 'tv', 'cellphone'], 'count': [100,200,300, 400, 300, 200, 900, 1000, 100], 'date': ['2022-04-30', '2022-05-30','2022-06-30', '2022-07-30', '2022-08-30','2022-09-30', '2022-10-30', '2022-11-30','2022-12-30']}) # 数据透视转换 pivot_df = df.pivot(index='date', columns='device', values='count') # 自定义颜色映射 color_map = {'tv': 'red', 'laptop': 'steelblue', 'cellphone': 'limegreen'} # 绘制堆叠柱状图 fig, ax = plt.subplots(figsize=(10, 6)) pivot_df.plot(kind='bar', stacked=True, color=[color_map[col] for col in pivot_df.columns], ax=ax) # 配置图表样式 ax.set_xlabel('Date', fontsize=14) ax.set_ylabel('Count', fontsize=14) ax.set_title('Count of Viewing Type Over Time', fontsize=20) ax.legend(title='Device', bbox_to_anchor=(1.05, 1), loc='upper left') ax.tick_params(axis='x', rotation=45) # 添加百分比标注 for i, date in enumerate(pivot_df.index): total = pivot_df.loc[date].sum() current_height = 0 for device in pivot_df.columns: count = pivot_df.loc[date, device] if count == 0: continue percentage = f'{(count/total)*100:.1f}%' ax.text(i, current_height + count/2, percentage, ha='center', va='center', fontsize=10) current_height += count plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者Beans On Toast
相关产品推荐
相关产品推荐

