You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Matplotlib等高线图添加刻度对齐的次级X/Y轴?

问题描述

我一直尝试使用matplotlib为填充等高线图设置次级y轴和x轴,目标是让次级轴的数值为主轴数值经过自定义函数转换后的结果。我试过secondary_yaxis和secondary_xaxis函数,但对其工作原理感到困惑。以下是测试代码:

import matplotlib.pyplot as plt
import numpy as np

# the function that I'm going to plot
def z_func(x, y):
    return (1 - (x ** 2 + y ** 3)) * np.exp(-(x ** 2 + y ** 2) / 2)

yMax = 2.5
yMin = 1
xMax = yMax
xMin = yMin

x = np.arange(yMin, yMax, 0.01)
y = np.arange(xMin, xMax, 0.01)
X, Y = np.meshgrid(x, y)  # grid of point
Z = z_func(X, Y)  # evaluation of the function on the grid

fig,ax = plt.subplots()

ctr = ax.contourf( X,Y, Z)

xticks=np.linspace(xMin,xMax,9)
xtickLabels = [fr'{i:.1f}' for i in xticks]
ax.set_xticks(ticks=xticks, labels=xtickLabels)
ax.set_xlabel('x')

yticks = np.linspace( yMin,yMax, 9)
ytickLabels = [fr'{i:.1f}' for i in yticks]
ax.set_yticks(ticks=yticks, labels=ytickLabels)
ax.set_ylabel('y')

cbar = fig.colorbar(ctr, ax=ax, location='right')
cbar.ax.set_ylabel(r'$z=f(x,y)$')

Y = yticks**2

fig.subplots_adjust(left=0.20)
def y_forward(y):
    return  1/y
# def forward(y):
#     return 1/y
# def inverse(y):
#     return y

secay=ax.secondary_yaxis('left', functions=(y_forward,y_forward))
secay.spines['left'].set_position(('outward', 40))
secay.set_ylabel(r'Y=1/y')
secay.yaxis.set_inverted(True)

fig.subplots_adjust(bottom=0.27)
def x_forward(x):
    return 3*x
secax=ax.secondary_xaxis('bottom', functions=(x_forward,x_forward))
secax.spines['bottom'].set_position(('outward', 30))
secax.set_xlabel(r'X=3$\times$ x')

ax.grid(visible=False)

ax.set_title(r'$z=(1-x^2+y^3) e^{-(x^2+y^2)/2}$')
fig.tight_layout()
plt.show()

我原本以为secondary_yaxis和secondary_xaxis会根据转换函数自动生成刻度,但我希望次级轴的刻度是与主刻度严格对齐的——比如主y轴有9个刻度,次级y轴也应有9个由主刻度经自定义函数计算得到的刻度,且两者位置完全对应。请问能否通过secondary_yaxis和secondary_xaxis实现该需求?还是用twinx和twiny更合适?


解决方案

方法一:正确使用secondary_yaxis/secondary_xaxis

secondary_yaxis的functions参数需要传入两个函数:第一个是主轴转次轴的正向转换函数,第二个是次轴转主轴的逆向转换函数,这样matplotlib才能正确处理轴的映射逻辑。如果要让次级轴和主轴线严格对齐,直接基于主刻度计算次级刻度标签即可,无需依赖自动生成。

修改后的完整代码:

import matplotlib.pyplot as plt
import numpy as np

# 定义绘图函数
def z_func(x, y):
    return (1 - (x ** 2 + y ** 3)) * np.exp(-(x ** 2 + y ** 2) / 2)

yMax = 2.5
yMin = 1
xMax = yMax
xMin = yMin

x = np.arange(yMin, yMax, 0.01)
y = np.arange(xMin, xMax, 0.01)
X, Y = np.meshgrid(x, y)
Z = z_func(X, Y)

fig, ax = plt.subplots()
ctr = ax.contourf(X, Y, Z)

# 主X轴设置
xticks = np.linspace(xMin, xMax, 9)
ax.set_xticks(ticks=xticks)
ax.set_xticklabels([f'{i:.1f}' for i in xticks])
ax.set_xlabel('x')

# 主Y轴设置
yticks = np.linspace(yMin, yMax, 9)
ax.set_yticks(ticks=yticks)
ax.set_yticklabels([f'{i:.1f}' for i in yticks])
ax.set_ylabel('y')

# 颜色条设置
cbar = fig.colorbar(ctr, ax=ax, location='right')
cbar.ax.set_ylabel(r'$z=f(x,y)$')

# 次级Y轴:Y=1/y
fig.subplots_adjust(left=0.20)
# 定义正向和逆向转换函数
def y_forward(y):
    return 1/y
def y_inverse(y_sec):
    return 1/y_sec

secay = ax.secondary_yaxis('left', functions=(y_forward, y_inverse))
secay.spines['left'].set_position(('outward', 40))
secay.set_ylabel(r'Y=1/y')
# 手动设置次级Y轴刻度与主Y轴对齐
secay.set_yticks(yticks)
secay.set_yticklabels([f'{y_forward(tick):.2f}' for tick in yticks])
secay.yaxis.set_inverted(True)

# 次级X轴:X=3*x
fig.subplots_adjust(bottom=0.27)
def x_forward(x):
    return 3*x
def x_inverse(x_sec):
    return x_sec/3

secax = ax.secondary_xaxis('bottom', functions=(x_forward, x_inverse))
secax.spines['bottom'].set_position(('outward', 30))
secax.set_xlabel(r'X=3$\times$x')
# 手动设置次级X轴刻度与主X轴对齐
secax.set_xticks(xticks)
secax.set_xticklabels([f'{x_forward(tick):.1f}' for tick in xticks])

ax.grid(visible=False)
ax.set_title(r'$z=(1-x^2+y^3) e^{-(x^2+y^2)/2}$')
fig.tight_layout()
plt.show()

关键修改点:

  • 给secondary_yaxis/secondary_xaxis传入完整的正向+逆向转换函数,确保轴的映射逻辑正确
  • 手动设置次级轴的ticks为主轴的ticks,再通过自定义函数计算对应的标签,实现严格对齐

方法二:使用twinx/twiny

如果需要更灵活的控制,twinx/twiny也是可行方案,本质是创建共享轴的孪生轴,手动设置刻度和标签:

示例代码片段(仅展示Y轴部分,X轴同理):

# 孪生Y轴
ax2 = ax.twinx()
# 设置孪生轴的位置(向外偏移)
ax2.spines['left'].set_position(('outward', 40))
ax2.set_ylabel(r'Y=1/y')
# 让孪生轴的刻度位置与主Y轴完全一致
ax2.set_yticks(yticks)
# 计算并设置标签
ax2.set_yticklabels([f'{1/tick:.2f}' for tick in yticks])
# 反转轴方向
ax2.invert_yaxis()

两种方法对比

  • secondary_yaxis/secondary_xaxis:专门为刻度转换场景设计,代码更简洁,自动处理轴的映射关系,适合仅需刻度转换的需求
  • twinx/twiny:自由度更高,适合需要对次级轴做更多自定义操作(比如绘制额外曲线)的场景

内容的提问来源于stack exchange,提问作者ishan_ae

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 16:12:29