Matplotlib绘制叠加柱状图对比新旧时序数据 按差值正负区分颜色
问题原因
直接绘制完整新值柱的逻辑是从y轴0点开始画全高度柱,必然会覆盖下层的旧值蓝色柱。正确的做法是不要绘制完整新值柱,仅单独绘制差值段,通过bottom参数控制差值段的起始位置,就能保留完整的旧值蓝色基底。
实现步骤
- 首先绘制全量旧值的蓝色柱,作为所有月份的基准层
- 差值为正(新值>旧值)时:差值段的起始高度为旧值,柱高等于正差值,填充绿色,叠加在蓝色柱上方展示增长幅度
- 差值为负(新值<旧值)时:差值段的起始高度为新值,柱高等于差值的绝对值,填充红色,叠加在蓝色柱的上部区间展示下降幅度
完整实现代码
import matplotlib.pyplot as plt import pandas as pd # 替换为你自己的数据集加载逻辑即可 data = pd.DataFrame({ "DATE": ["08/22", "09/22", "10/22", "11/22"], "OLD VALUE": [10000, 5000, 8000, 20000], "NEW VALUE": [9500, 5500, 9000, 18000], "DELTA": [-500, 500, 1000, -2000] }) # 绘制旧值蓝色基底 plt.bar(data["DATE"], data["OLD VALUE"], color="#1f77b4", label="旧值") # 绘制增长段(绿色) gain_data = data[data["DELTA"] >= 0] plt.bar( gain_data["DATE"], gain_data["DELTA"], bottom=gain_data["OLD VALUE"], color="green", label="增长值" ) # 绘制下降段(红色) loss_data = data[data["DELTA"] < 0] plt.bar( loss_data["DATE"], -loss_data["DELTA"], bottom=loss_data["NEW VALUE"], color="red", label="减少值" ) # 可选优化:添加图例和差值标签 plt.legend() for _, row in data.iterrows(): label_y = row["NEW VALUE"] if row["DELTA"] < 0 else row["OLD VALUE"] + row["DELTA"] va_align = "top" if row["DELTA"] < 0 else "bottom" plt.text( row["DATE"], label_y, f'{int(row["DELTA"]):+}', ha="center", va=va_align ) plt.show()
最终效果
- 所有月份从0到旧值的柱段始终为蓝色,不会被覆盖
- 增长月份:蓝色柱上方延伸出对应长度的绿色柱,柱顶为新值
- 下降月份:蓝色柱上部覆盖对应长度的红色柱,红色柱顶为新值
内容的提问来源于stack exchange,提问作者stephen1780
相关产品推荐
相关产品推荐

