Matplotlib 双轴:twinx 与 secondary_yaxis 的正确用法
Updated on
一个图需要两套刻度(美元 vs 数量、摄氏 vs 华氏)时,如果双轴处理不当,很容易误导读者:刻度错位、图例混乱、标签被裁剪。关键是选对工具,并提供清晰的转换函数,让两套刻度都可信。
快速决策表
| 方案 | 适用场景 | 优点 | 注意事项 |
|---|---|---|---|
twinx / twiny | 只是共享 x(或 y)位置的两条独立系列 | 代码少、上手快 | 刻度格式需手动;不自动同步比例 |
secondary_yaxis / secondary_xaxis | 两条系列可互相转换(如 °C ↔ °F) | 通过正/反函数保证刻度对齐 | 需要精确且单调的转换 |
| 两个共享轴的子图 | 希望并排比较而不叠加 | 更清晰 | 占空间,图例分别处理 |
示例:twinx 叠加两个 y 轴
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(1, 13)
sales = np.array([12, 18, 25, 30, 28, 35, 40, 38, 32, 28, 22, 18])
customers = np.array([120, 155, 180, 210, 205, 230, 245, 240, 225, 200, 175, 150])
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(x, sales, color="tab:blue", label="Sales (k$)")
ax.set_xlabel("Month")
ax.set_ylabel("Sales (k$)", color="tab:blue")
ax.tick_params(axis="y", labelcolor="tab:blue")
ax2 = ax.twinx()
ax2.plot(x, customers, color="tab:orange", label="Customers")
ax2.set_ylabel("Customers", color="tab:orange")
ax2.tick_params(axis="y", labelcolor="tab:orange")
lines = ax.get_lines() + ax2.get_lines()
labels = [line.get_label() for line in lines]
ax.legend(lines, labels, loc="upper left")
plt.tight_layout()
plt.show()提示:
- 为每个轴使用不同颜色,图例更清晰。
- 先合并两组线再调用
legend,避免重复。 tight_layout()或constrained_layout=True可防止标签被裁剪。
示例:secondary_yaxis 的安全转换
import matplotlib.pyplot as plt
import numpy as np
temps_c = np.linspace(-20, 40, 200)
fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(temps_c, np.sin(temps_c / 10), color="tab:blue", label="Signal vs °C")
ax.set_xlabel("Temperature (°C)")
ax.set_ylabel("Signal")
def c_to_f(c):
return c * 9/5 + 32
def f_to_c(f):
return (f - 32) * 5/9
ax_f = ax.secondary_xaxis("top", functions=(c_to_f, f_to_c))
ax_f.set_xlabel("Temperature (°F)")
ax.legend(loc="lower right")
plt.tight_layout()
plt.show()提示:
- 一定要提供正向与反向函数,刻度才能对齐。
- 仅用单调、可逆的转换。
- 格式化刻度(如
ax_f.xaxis.set_major_formatter("{x:.0f}°F"))能让单位更清晰。
让双轴保持可信
- 系列毫不相关时别用双轴;两个子图通常更易读。
- 如果某条曲线量级太大,先归一化再对比。
- 只在主轴上画网格,减少视觉噪声。
排查清单
- 图例重复?合并两轴的线后再
legend。 - 标签被裁剪?开启
constrained_layout=True或调用plt.tight_layout()。 - 刻度颜色不一致?分别对两个轴用
tick_params(labelcolor=...)。