如何创建符合需求的Matplotlib瀑布图?解决标注与布局问题
问题
使用Matplotlib创建瀑布图时遇到以下问题:
- 数值标注位置错误
- 末尾文本缺失
- 缺少瀑布连接线
当前代码:
import pandas as pd import matplotlib.pyplot as plt data = { 'Market': ['EU', 'EU', 'US', 'US', 'CN'], 'Vehicle ID': ['001-1234', '001-1254', '003-7485', '001-1232', '001-2138'], 'Status': ['Rec.', 'Rec.', 'Development', 'Stopped', 'Development'] } df = pd.DataFrame(data) filtered_df = df[df['Vehicle ID'].str.startswith('001')] status_order = [ 'Wachting', 'Stopped', 'Development', 'Rec.', ] status_counts = filtered_df['Status'].value_counts().reindex(status_order, fill_value=0) total_count = df.shape[0] status_counts = status_counts.append(pd.Series({'Total': total_count})).reindex(['Total'] + status_order) plt.bar(status_counts.index, status_counts) plt.xlabel('Status') plt.ylabel('Number of Vehicles') plt.title('Distribution of Vehicle Status for vehicles starting with "001"') for index, value in enumerate(status_counts): plt.text(index, -0.1, str(value), ha='center') plt.gca().axes.get_yaxis().set_visible(False) plt.tight_layout() plt.show()
当前图表效果:
预期效果参考:
解决方案
核心调整点
- 重构瀑布图数据逻辑:瀑布图需要展示累计变化,将
Total作为起始值,后续状态用负数表示扣除量,而非直接显示原始计数 - 修正数值标注位置:将标注移至柱子内部/顶端,根据数值正负调整显示位置和颜色
- 添加瀑布连接线:通过绘制灰色虚线连接相邻柱子的顶端与底端
- 补全末尾文本:确保
Total及所有状态的标注正常显示
完整代码
import pandas as pd import matplotlib.pyplot as plt data = { 'Market': ['EU', 'EU', 'US', 'US', 'CN'], 'Vehicle ID': ['001-1234', '001-1254', '003-7485', '001-1232', '001-2138'], 'Status': ['Rec.', 'Rec.', 'Development', 'Stopped', 'Development'] } df = pd.DataFrame(data) filtered_df = df[df['Vehicle ID'].str.startswith('001')] status_order = ['Wachting', 'Stopped', 'Development', 'Rec.'] status_counts = filtered_df['Status'].value_counts().reindex(status_order, fill_value=0) total_count = df.shape[0] # 构建瀑布图数据:Total为初始值,后续状态是扣除量(负数) waterfall_data = pd.Series([total_count] + list(-status_counts.values), index=['Total'] + status_order) # 计算累计值,确定每个柱子的底部位置 cumulative = waterfall_data.cumsum() bottoms = [0] + list(cumulative[:-1].values) plt.figure(figsize=(8, 5)) # 绘制瀑布柱,Total用蓝色,其余用橙色 bars = plt.bar(waterfall_data.index, waterfall_data.values, bottom=bottoms, color=['#1f77b4'] + ['#ff7f0e']*len(status_order)) # 添加数值标注 for bar, val in zip(bars, waterfall_data.values): height = bar.get_height() y_pos = bar.get_y() + height / 2 # 负数柱子用白色标注,正数用黑色 text_color = 'white' if height < 0 else 'black' plt.text(bar.get_x() + bar.get_width()/2, y_pos, f'{abs(val)}', ha='center', va='center', color=text_color) # 绘制瀑布连接线 for i in range(1, len(cumulative)): # 连接上一柱顶端到当前柱底端 plt.plot([i-0.5, i-0.5, i+0.5], [cumulative[i-1], cumulative[i], cumulative[i]], color='gray', linestyle='--') plt.xlabel('状态') plt.ylabel('车辆数量') plt.title('以"001"开头的车辆状态分布(瀑布图)') plt.gca().axes.get_yaxis().set_visible(False) plt.tight_layout() plt.show()
效果说明
- 瀑布图清晰展示从总车辆数到各状态的扣除过程
- 数值标注位于柱子中央,可读性更强
- 灰色虚线明确连接各阶段的数值变化
- 配色区分起始值和扣除项,更符合预期视觉效果
内容的提问来源于stack exchange,提问作者Test
相关产品推荐
相关产品推荐

