如何在matplotlib stackplot中正常显示负资产权重数值
问题根因
Matplotlib原生stackplot的默认堆叠逻辑为严格按照传入的序列顺序,从固定基线开始逐次向上累加所有传入值,不会自动区分数值的正负方向:当传入序列中混有正、负权重时,负权重对应的数值会被前置的正向高值累积层覆盖在画布下层,视觉上就表现为负权重没有正常渲染,并非函数本身不支持绘制负数值。
可落地方案
核心思路是拆分正、负权重序列,分别沿着0轴做双向堆叠,绕开原生stackplot的全正向累加限制,同时完全保留stackplot对时间序列X轴的原生适配能力,不需要手动调整日期轴格式:
- 第一步:按权重正负拆分资产组
遍历DataFrame的所有资产列,将平均权重为正的列归为正向资产组,平均权重为负的列归为负向资产组,分别计算两组的累积堆叠基线:- 正向组:以0值为起点,逐列向上累加每一行的权重值,作为每个面积层的下边界
- 负向组:以0值为起点,逐列向下累加每一行的负权重值,作为每个面积层的上边界
- 第二步:用手动计算的边界逐次绘制面积层,和
stackplot的视觉表现完全一致
适配Python 3.8.3 + Matplotlib 3.3.2环境的可直接运行代码如下:
# 按资产平均权重拆分正负序列组 pos_cols = [col for col in w_minvar1nc.columns if w_minvar1nc[col].mean() > 0] neg_cols = [col for col in w_minvar1nc.columns if w_minvar1nc[col].mean() < 0] fig, ax = plt.subplots(nrows=1, ncols=1, facecolor="#F0F0F0") # 绘制正向堆叠层:从0轴开始向上累加 pos_baseline = pd.Series(0, index=w_minvar1nc.index) for col in pos_cols: upper_edge = pos_baseline + w_minvar1nc[col] ax.fill_between(w_minvar1nc.index, pos_baseline, upper_edge, label=col) pos_baseline = upper_edge # 绘制负向堆叠层:从0轴开始向下累加 neg_baseline = pd.Series(0, index=w_minvar1nc.index) for col in neg_cols: lower_edge = neg_baseline + w_minvar1nc[col] ax.fill_between(w_minvar1nc.index, lower_edge, neg_baseline, label=col) neg_baseline = lower_edge # 格式设置和原有逻辑完全兼容 ax.set_xlabel("Time") ax.set_ylabel("Weight") ax.axhline(y=0, color="black", linewidth=0.8) # 添加0值参考线区分上下堆叠 ax.set_ylim(bottom=-0.5, top=1.5) ax.grid(which="major", color="grey", linestyle="--", linewidth=0.5) ax.legend(loc="upper right") # 保存逻辑和原有代码一致 fig.savefig(fname=(plotpath + "test.png")) plt.clf() plt.close()
效果验证说明
- 该方案完全匹配日频时间序列的X轴自动格式适配,不会出现之前手动堆叠绘制柱状图时的日期轴显示错位、标签拥挤问题
- 所有负权重资产(如示例数据中的MOMTUM)会从0轴向下独立成层显示,不会被正向堆叠的资产层覆盖,最终每一层的高度和实际权重值完全对应
- 由于采用逐层计算边界的方式,在Matplotlib 3.3.2版本上不存在baseline参数的兼容问题,不需要升级依赖版本即可运行
内容的提问来源于stack exchange,提问作者dominikmeyer95
相关产品推荐
相关产品推荐

