如何在 Matplotlib 中精准添加多组垂直参考线(含合并图表场景)

老丽吖_8666

老丽吖_8666

2026-03-25

1004人浏览

原创

如何在 Matplotlib 中精准添加多组垂直参考线(含合并图表场景)

本文详解如何在合并的双类别柱状图中,为不同数据子集(如 call/put)分别绘制对应分位数的垂直参考线,核心在于统一 x 轴索引映射,避免因 dataframe 索引错位导致线条位置错误。

本文详解如何在合并的双类别柱状图中,为不同数据子集(如 call/put)分别绘制对应分位数的垂直参考线,核心在于统一 x 轴索引映射,避免因 dataframe 索引错位导致线条位置错误。

在使用 seaborn.barplot 或 matplotlib.pyplot.bar 绘制合并后的分类柱状图(例如 CALL 与 PUT 的 CDF 对比)时,一个常见却易被忽视的问题是:直接使用原始 DataFrame 的 .idxmin() 返回的索引值调用 plt.axvline(x=...) 会导致垂直线位置严重偏移。这是因为 barplot 默认将 x 轴按 data['STRIKE'] 的唯一值自动排序并分配整数位置(0, 1, 2, …),而原始索引(如 CALL.index)与绘图坐标系中的视觉位置完全不一致。

✅ 正确解法的核心逻辑是:

  1. 统一构建有序的 x 轴刻度序列:提取合并后所有唯一 STRIKE 值并排序;
  2. 映射分位数对应的实际绘图位置:遍历该序列,找到目标 STRIKE 值所在的位置索引(即 0-based integer position);
  3. 基于该位置索引绘制 axvline,并可叠加文本标注增强可读性。

以下是完整、可复现的专业实践代码(已优化结构与健壮性):

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np

# ✅ 步骤 1:预计算各子集的分位数对应 STIKE 值(注意:使用 'STRIKE' 列,非索引)
nearest_40_call = CALL.loc[(CALL['Percentile'] - 0.4).abs().idxmin(), 'STRIKE']
nearest_80_call = CALL.loc[(CALL['Percentile'] - 0.8).abs().idxmin(), 'STRIKE']
nearest_40_put  = PUT.loc[(PUT['Percentile'] - 0.4).abs().idxmin(), 'STRIKE']
nearest_80_put  = PUT.loc[(PUT['Percentile'] - 0.8).abs().idxmin(), 'STRIKE']

# ✅ 步骤 2:构建全局有序 STRIKE 序列(barplot 实际使用的 x 轴位置基础)
all_strikes = sorted(pd.concat([CALL, PUT])['STRIKE'].unique())

# ✅ 步骤 3:映射每个目标 STIKE 到 barplot 的整数位置(关键!)
def strike_to_position(strike_val, strike_list):
    try:
        return strike_list.index(strike_val)
    except ValueError:
        # 若精确匹配失败,取最接近的值位置(增强鲁棒性)
        idx = np.argmin(np.abs(np.array(strike_list) - strike_val))
        return idx

pos_40_call = strike_to_position(nearest_40_call, all_strikes)
pos_80_call = strike_to_position(nearest_80_call, all_strikes)
pos_40_put  = strike_to_position(nearest_40_put,  all_strikes)
pos_80_put  = strike_to_position(nearest_80_put,  all_strikes)

# ✅ 步骤 4:绘制合并柱状图 + 精准垂直线
plt.figure(figsize=(16, 6))
sns.barplot(x='STRIKE', y='CDF', hue='hue', data=pd.concat([CALL, PUT]), 
            palette={'CALL': 'lightgreen', 'PUT': 'orange'}, 
            dodge=True,  # 明确启用分组柱状图(若 hue 存在)
            order=all_strikes)  # 强制按统一顺序排列 x 轴

# 添加垂直线(使用映射后的位置索引)
for pos, label, color in [
    (pos_40_call, f'40% CALL ({nearest_40_call})', 'red'),
    (pos_80_call, f'80% CALL ({nearest_80_call})', 'darkred'),
    (pos_40_put,  f'40% PUT ({nearest_40_put})',  'steelblue'),
    (pos_80_put,  f'80% PUT ({nearest_80_put})',  'darkblue')
]:
    plt.axvline(x=pos, color=color, linestyle='--', linewidth=1.2, alpha=0.9)

# ✅ 可选:添加顶部标注提升信息密度
y_max = plt.ylim()[1] * 0.95
for pos, label, color in [
    (pos_40_call, f'40% CALL', 'red'),
    (pos_80_call, f'80% CALL', 'darkred'),
    (pos_40_put,  f'40% PUT',  'steelblue'),
    (pos_80_put,  f'80% PUT',  'darkblue')
]:
    plt.text(pos, y_max, label, ha='center', va='bottom', 
             fontsize=9, fontweight='bold', color=color)

# 设置标签与图例
plt.xlabel('Strike Price', fontsize=11)
plt.ylabel('Cumulative Distribution Function (CDF)', fontsize=11)
plt.title('CDF Comparison: CALL vs PUT with 40% & 80% Percentile Lines', fontsize=13, pad=15)
plt.xticks(rotation=45, ha='right')
plt.grid(axis='y', alpha=0.3)

# 自定义图例(避免 axvline 干扰)
from matplotlib.patches import Patch
legend_elements = [
    Patch(facecolor='lightgreen', edgecolor='k', label='CALL'),
    Patch(facecolor='orange', edgecolor='k', label='PUT')
]
plt.legend(handles=legend_elements, loc='upper left', frameon=True, fancybox=True, shadow=False)

plt.tight_layout()
plt.show()

⚠️ 关键注意事项:

  • ❌ 切勿直接使用 df.idxmin() 结果作为 axvline(x=...) 参数——它返回的是原始 DataFrame 行号,而非 barplot 的视觉坐标;
  • ✅ 务必通过 order=all_strikes 显式控制 barplot 的 x 轴顺序,并基于该列表做位置映射;
  • ? 若 STRIKE 为浮点数,建议在 strike_to_position 中加入容差匹配(如 np.isclose),避免因精度问题找不到精确值;
  • ? axvline 的 x 值始终是整数位置索引(0, 1, 2…),而非原始 STRIKE 数值本身;
  • ? 如需区分更多类别或分位数,只需扩展映射逻辑与循环即可,架构高度可复用。

掌握这一“索引映射”范式,你不仅能准确绘制多组垂直参考线,更能举一反三地解决各类混合图表中坐标对齐难题——这是数据可视化从“能画”迈向“精准表达”的关键一步。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1851

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

4964

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1789

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

29817

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

3547

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

3567

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1223

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

616

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2763

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 134.1万人学习