Matplotlib绘制全y轴范围垂直线时y轴范围异常问题排查
Matplotlib绘制跨y轴垂直线导致子图y轴范围异常
我需要绘制覆盖整个y轴范围的垂直线,不需要关注y轴具体数值。参考Matplotlib官方的vline_hline_demo示例实现,但编写的代码出现异常:执行以下代码后,期望左右两个子图的y轴范围一致,实际右侧子图y轴范围错误。
from matplotlib import pyplot as plt import numpy as np np.random.seed(19680801) y = np.random.normal(scale=0.01, size=200).cumsum() fig, ax = plt.subplots(1, 2, figsize=(12, 6)) ax[0].plot(y) ax[0].vlines([25, 50, 100], [0], [0.1, 0.2, 0.3], color='C1') ax[1].plot(y) ax[1].vlines([25, 50, 100], [0], [0.1, 0.2, 0.3], color='C1') ax[1].vlines([0], 0, 1, color='k', linestyle='dashed', transform=ax[1].get_xaxis_transform())
使用环境:matplotlib 3.7.1,Python 3.11.3
问题原因
你用的ax[1].get_xaxis_transform()是**数据坐标(x轴)+ 轴域归一化坐标(y轴)**的混合变换,但调用vlines时传入的ymin=0和ymax=1被Matplotlib误判为数据坐标的y值,导致它自动调整右侧子图的y轴范围来适配0-1这个区间,和左侧子图的实际数据范围(y的累积和)脱节。
解决方案
要绘制覆盖整个y轴的垂直线,有两种简单的正确做法:
方案一:用axvline(最简洁)
axvline默认会覆盖当前子图的整个y轴范围,不需要额外处理坐标变换:
from matplotlib import pyplot as plt import numpy as np np.random.seed(19680801) y = np.random.normal(scale=0.01, size=200).cumsum() fig, ax = plt.subplots(1, 2, figsize=(12, 6)) ax[0].plot(y) ax[0].vlines([25, 50, 100], [0], [0.1, 0.2, 0.3], color='C1') ax[1].plot(y) ax[1].vlines([25, 50, 100], [0], [0.1, 0.2, 0.3], color='C1') # 直接用axvline画x=0处的垂直线,自动覆盖整个y轴 ax[1].axvline(x=0, color='k', linestyle='dashed')
方案二:用正确的混合变换配合vlines
如果一定要用vlines,需要明确指定x用数据坐标、y用轴域归一化坐标,通过blended_transform_factory创建对应的变换:
from matplotlib import pyplot as plt from matplotlib.transforms import blended_transform_factory import numpy as np np.random.seed(19680801) y = np.random.normal(scale=0.01, size=200).cumsum() fig, ax = plt.subplots(1, 2, figsize=(12, 6)) ax[0].plot(y) ax[0].vlines([25, 50, 100], [0], [0.1, 0.2, 0.3], color='C1') ax[1].plot(y) ax[1].vlines([25, 50, 100], [0], [0.1, 0.2, 0.3], color='C1') # 创建混合变换:x轴用数据坐标,y轴用轴域归一化坐标 trans = blended_transform_factory(ax[1].transData, ax[1].transAxes) ax[1].vlines(x=0, ymin=0, ymax=1, color='k', linestyle='dashed', transform=trans)
内容的提问来源于stack exchange,提问作者Ilya
相关产品推荐
相关产品推荐

