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

Matplotlib:绘制长度不同的第二Y轴及相关格式问题

双Y轴Matplotlib图表格式优化方案

问题描述

我正在尝试使用Matplotlib绘制带有第二个Y轴的图表,目前已实现双Y轴功能,但想了解是否可以缩短第二个Y轴的长度。此外还存在以下格式设置难题:

  • a) 希望在第二个Y轴上绘制箭头,样式与第一个Y轴的箭头一致;
  • b) 将第二个Y轴对齐在-1位置,使其与X轴的交点为(…; -1);
  • c) 当前X轴在原点处穿过X轴和Y轴刻度,需要避免该情况;
  • d) 如何为两个Y轴设置统一的图例?

当前代码片段:

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots()
bx = ax.twinx() # 2nd y-axis

ax.spines['bottom'].set_position(('data',0))
ax.spines['left'].set_position(('data',0)) 
ax.xaxis.set_ticks_position('bottom')

bx.spines['left'].set_position(('data',-1)) 
bx.spines['bottom'].set_position(('data',-1))

ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
bx.spines["top"].set_visible(False)
bx.spines["bottom"].set_visible(False)
bx.spines["left"].set_visible(False)

## Graphs
x_val = np.arange(0,10)
y_val = 0.1*x_val
ax.plot(x_val, y_val, 'k--')
bx.plot(x_val, -y_val+1, color = 'purple')

## Arrows
ms=2
#ax.plot(1, 0, ">k", ms=ms, transform=ax.get_yaxis_transform(), clip_on=False)
ax.plot(0, 1, "^k", ms=ms, transform=ax.get_xaxis_transform(), clip_on=False)
bx.plot(1, 1, "^k", ms=ms, transform=bx.get_xaxis_transform(), clip_on=False)

plt.ylim((-1, 1.2))
bx.set_yticks([-1, -0.75, -0.5, -0.25, 0, 0.25, 0.5])

## Legend
ax.legend([r'$A_{hull}$'], frameon=False, 
      loc='upper left', bbox_to_anchor=(0.2, .75))

plt.show()

解决方案

1. 缩短第二个Y轴长度

直接通过bx.set_ylim()限制第二个Y轴的显示范围即可,轴的长度会自动适配设定的刻度区间。例如要让Y轴仅显示-1到0.5的范围,添加bx.set_ylim(-1, 0.5)即可。

2. 格式设置难题逐个解决

a) 为第二个Y轴添加一致样式的箭头

第一个Y轴的箭头是基于轴坐标绘制的,第二个Y轴需要对应调整变换方式:

  • 第二个Y轴是twinx()生成的右侧轴,用bx.get_yaxis_transform()确保坐标相对Y轴,在轴顶端绘制^k箭头即可和左侧轴样式统一。

b) 对齐第二个Y轴到-1位置

当前代码错误设置了左侧脊柱的位置,第二个Y轴的显示脊柱是右侧,修改为:

bx.spines['right'].set_position(('data', -1))

这样右侧Y轴会在X=-1的位置与X轴相交。

c) 避免X轴在原点穿过刻度

可以通过调整刻度内边距避免轴遮挡刻度,同时保留X轴在Y=0的位置:

ax.tick_params(axis='both', pad=10)
bx.tick_params(axis='y', pad=10)

如果不需要X轴在Y=0位置,也可以将X轴脊柱设为轴底部:ax.spines['bottom'].set_position('axes')。

d) 统一两个Y轴的图例

先保存两个轴的线条对象,再基于整个画布创建统一图例:

# 保存线条对象
line1, = ax.plot(x_val, y_val, 'k--', label=r'$A_{hull}$')
line2, = bx.plot(x_val, -y_val+1, color='purple', label='Second Series')
# 统一生成图例
fig.legend([line1, line2], [line1.get_label(), line2.get_label()], frameon=False, loc='upper left', bbox_to_anchor=(0.2, .75))

修改后的完整代码

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots()
bx = ax.twinx() # 2nd y-axis

# 调整第一个Y轴和X轴的脊柱位置
ax.spines['bottom'].set_position(('data', 0))
ax.spines['left'].set_position(('data', 0)) 
ax.xaxis.set_ticks_position('bottom')
# 调整第二个Y轴的脊柱位置到X=-1处
bx.spines['right'].set_position(('data', -1))

# 隐藏不需要的脊柱
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
bx.spines["top"].set_visible(False)
bx.spines["bottom"].set_visible(False)
bx.spines["left"].set_visible(False)

# 绘制曲线并保存线条对象
x_val = np.arange(0,10)
y_val = 0.1*x_val
line1, = ax.plot(x_val, y_val, 'k--', label=r'$A_{hull}$')
line2, = bx.plot(x_val, -y_val+1, color='purple', label='Second Series')

# 添加轴箭头
ms = 5
# 第一个Y轴箭头(左侧Y轴顶端)
ax.plot(0, 1, "^k", ms=ms, transform=ax.get_yaxis_transform(), clip_on=False)
# 第一个X轴箭头(底部X轴右端)
ax.plot(1, 0, ">k", ms=ms, transform=ax.get_xaxis_transform(), clip_on=False)
# 第二个Y轴箭头(右侧Y轴顶端)
bx.plot(1, 1, "^k", ms=ms, transform=bx.get_yaxis_transform(), clip_on=False)

# 设置轴范围和刻度
ax.set_ylim((-1, 1.2))
bx.set_ylim(-1, 0.5)  # 缩短第二个Y轴长度
bx.set_yticks([-1, -0.75, -0.5, -0.25, 0, 0.25, 0.5])
# 调整刻度内边距避免被轴遮挡
ax.tick_params(axis='both', pad=10)
bx.tick_params(axis='y', pad=10)

# 统一图例
fig.legend([line1, line2], [line1.get_label(), line2.get_label()], frameon=False, loc='upper left', bbox_to_anchor=(0.2, .75))

plt.show()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 19:25:26