Matplotlib中基于np.interp实现的次级X轴范围设置及轴值匹配问题
嗨,我来帮你解决这个双X轴的问题!你的核心问题在于两个X轴数据完全独立,而默认的secondary_xaxis结合np.interp时,matplotlib的自动刻度逻辑会生成超出你数据范围的刻度,同时设置主轴范围后没有同步调整次级轴的范围匹配规则。下面分两步解决你的问题:
一、移除次级轴上多余的0和3e-28刻度
出现这个问题的原因是:matplotlib的自动刻度生成器会尝试覆盖比你的实际数据范围更广的区间,而np.interp在输入超出原始xold范围时,会返回边界值(比如x小于20时返回xnew[0],x大于120时返回xnew[-1]),但这些边界外的刻度并不是你需要的。
解决方案:让转换函数在超出数据范围时返回NaN
修改你的forward和inverse函数,当输入值超出原始数据的范围时返回NaN,这样matplotlib会忽略这些无效值,不会生成多余的刻度:
import matplotlib.pyplot as plt import numpy as np fig, ax = plt.subplots(constrained_layout=True) x_upper = np.array([2.379618e-29,5.895669e-29,1.018725e-28, 1.413803e-28,1.780809e-28,2.080620e-28, 2.287013e-28,2.603605e-28,2.810124e-28]) x_lower = np.array([20,30,40,50,60,70,80,100,120]) y = np.array([-1.333526e-16,-8.841676e-16,-2.803599e-15, -5.300285e-15,-7.723194e-15,-9.906261e-15, -1.124626e-14,-1.238456e-14,-1.193596e-14]) ax.plot(x_lower, y) xold = x_lower xnew = x_upper def forward(x): # 仅在xold的范围内进行插值,超出范围返回NaN mask = (x >= xold.min()) & (x <= xold.max()) result = np.full_like(x, np.nan) result[mask] = np.interp(x[mask], xold, xnew) return result def inverse(x): # 仅在xnew的范围内进行插值,超出范围返回NaN mask = (x >= xnew.min()) & (x <= xnew.max()) result = np.full_like(x, np.nan) result[mask] = np.interp(x[mask], xnew, xold) return result secax = ax.secondary_xaxis('top', functions=(forward,inverse)) plt.autoscale(enable=True, axis='x', tight=True) plt.show()
替代方案:手动设置次级轴刻度
如果你希望次级轴只显示你提供的x_upper数值,可以直接手动设置刻度:
# 在创建secax之后添加这一行 secax.set_xticks(x_upper)
这样次级轴就只会显示你的数据点对应的刻度值,彻底避免多余刻度。
二、解决主轴范围修改后轴值不匹配的问题
当你设置ax.set_xlim(15, 125)时,主轴范围超出了x_lower的原始范围(20-120),但secondary_xaxis不会自动调整转换逻辑的有效范围,导致两个轴的刻度无法对应。
解决方案:同步主副轴的有效范围
你需要确保主轴的范围被限制在x_lower的有效区间内,或者手动将次级轴的范围同步到主轴范围对应的转换值:
方法1:限制主轴范围在数据范围内
# 主轴范围设置为x_lower的最小和最大值,这样次级轴自然匹配x_upper的范围 ax.set_xlim(xold.min(), xold.max())
方法2:手动计算并设置次级轴范围(当主轴必须超出数据范围时)
如果一定要设置主轴范围为(15,125),那么需要手动计算对应的次级轴范围,并确保转换函数在有效区间外返回NaN:
ax.set_xlim(15, 125) # 计算主轴范围对应的次级轴有效范围 secax.set_xlim(forward(xold.min()), forward(xold.max()))
这样次级轴的刻度只会在x_upper的范围内生成,主轴超出部分(15-20)对应的次级轴没有刻度,避免不匹配的问题。
经过这些调整后,你的双X轴就能正确显示,且不会出现多余的刻度和值不匹配的情况啦!
备注:内容来源于stack exchange,提问作者Hyperbolic

