双Y轴图需先创建主轴ax1并绘图,再调用ax1.twinx()生成ax2,所有右轴操作须作用于ax2;注意柱状图宽度、刻度对齐、图例合并及中文标签显示优化。

用 plt.twinx() 创建双Y轴,但必须注意坐标轴顺序
双Y轴图的核心是让两个不同量纲的数据共用X轴,左Y轴画折线、右Y轴画柱状图(或反过来)。关键在于:plt.twinx() 必须在第一个绘图对象创建之后调用,否则右轴会覆盖左轴刻度甚至丢失标签。
常见错误现象:ax2.set_ylabel() 不显示、右轴刻度挤成一团、折线和柱子完全错位——基本都是因为 twinx() 调用太早,或者后续又对 ax1 做了 set_ylim() 却没同步调整 ax2。
- 先调用
ax1 = plt.gca()或fig, ax1 = plt.subplots()创建主轴 - 在
ax1.plot(...)之后,立刻执行ax2 = ax1.twinx() - 所有针对右轴的操作(
plot、bar、set_ylabel)都必须作用于ax2 - 若手动设了
ax1.set_ylim(),记得按比例估算并设置ax2.set_ylim(),否则柱状图可能被截断
柱状图用 ax2.bar() 而不是 ax2.plot(),且需注意宽度与对齐
双Y轴里混用折线和柱状图时,最容易忽略的是柱子的视觉对齐。直接用 ax2.bar(x, y) 默认以 x 坐标为中心绘制,但如果 x 是日期或字符串,容易出现偏移;若 x 是数值型但间隔不均,柱宽不设也会导致挤压或空隙过大。
使用场景:比如分析月度销售额(柱状图,万元)和用户增长率(折线图,%),二者时间点一致但量级差3个数量级。
立即学习“Python免费学习笔记(深入)”;
- 显式传入
width参数,例如width=0.6(默认是0.8,太宽易重叠) - 若
x是pd.Timestamp或str,先用ax1.set_xticks()固定位置,再让ax2.bar()的x与之严格对应 - 避免对
ax2调用ax2.grid(True)—— 它会覆盖左轴网格;如需右轴辅助线,改用ax2.axhline(y=...)
图例合并显示要用 ax1.get_legend_handles_labels() 手动拼接
双Y轴下,ax1.legend() 和 ax2.legend() 会互相覆盖,直接调用任一者都只能显示部分图例。必须把两个轴的句柄和标签取出来,合并后统一交给一个轴管理。
性能影响:该操作本身无开销,但若在循环中反复调用 get_legend_handles_labels() 而未清空旧图例,会导致内存缓慢增长(尤其在动态刷新图表时)。
- 执行
h1, l1 = ax1.get_legend_handles_labels()和h2, l2 = ax2.get_legend_handles_labels() - 合并为
handles = h1 + h2、labels = l1 + l2 - 只调一次
ax1.legend(handles, labels),不要对ax2再调用legend() - 如果某条线没加
label参数(如ax1.plot(..., label='_nolegend_')),它不会出现在l1中,无需额外过滤
中文标签乱码和负数坐标轴刻度重叠是高频兼容性问题
Matplotlib 默认字体不支持中文,且当右轴数据含负值、左轴为正时,两套Y轴刻度标签容易上下重叠,尤其在导出为PDF或保存为高DPI图片时更明显。
解决方式不是换全局字体配置,而是就图论图:
- 在绘图前加
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans'],确保中文字体 fallback 链有效 - 对
ax2单独调用ax2.tick_params(axis='y', pad=15)增大右侧标签与轴线距离 - 若左轴最大值远大于右轴,考虑对右轴数据做缩放(如除以1000),并在
set_ylabel()中注明单位(如 “销量(千件)”) - 避免用
plt.tight_layout()—— 它常把右轴标签切掉;改用plt.subplots_adjust(right=0.85)留足右侧空间


















