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

如何在Matplotlib子图中添加第二个Y轴?附实现代码

在Matplotlib子图中用twinx()添加双Y轴(叠加洪水等级散点图)

问题背景

我了解Matplotlib中的twinx函数,但不清楚如何在子图场景下使用它。现有一段代码生成3张展示降雨数据的子图,我还需添加洪水等级数据(分为1、2、3类,存储于YEAR1['Size']等列),以散点图叠加在折线图上,因此需要为子图添加右侧第二个Y轴。

原降雨子图代码:

import matplotlib.pyplot as plt

fig,ax = plt.subplots(3, figsize=(10,15),sharey=True)
ax[0].plot(YEAR1['pcp_1D_tot'], label='RG')
ax[0].plot(YEAR1['ppt_1D'], label='TRMM')
ax[0].set_title('Year 1',x=0.1,y=0.9)
ax[1].plot(YEAR2['pcp_1D_tot'], label='RG')
ax[1].plot(YEAR2['ppt_1D'], label='TRMM')
ax[1].set_title('Year 2',x=0.1,y=0.9)
ax[1].set_ylabel('Rainfall total (mm/day)')
ax[2].plot(YEAR3['pcp_1D_tot'], label='RG')
ax[2].plot(YEAR3['ppt_1D'], label='TRMM')
ax[2].set_title('Year 3',x=0.1,y=0.9)
ax[2].set_xlabel('Date')
fig.legend(loc=(0.8,0.9))
fig.tight_layout()
plt.show()

解决方案:子图中使用twinx()的核心逻辑

其实在子图场景下用twinx()一点都不复杂——给每个子图对象单独调用twinx()方法,生成对应的右侧Y轴,然后在这个新轴上绘制你的散点图即可。你已经成功实现了需求,这里把关键步骤拆解清楚:

  • 为每个子图创建双轴:比如ax0 = ax[0].twinx(),这个ax0就是第一个子图的右侧Y轴,它和原轴ax[0]共享X轴,完美适配叠加需求。
  • 在双轴上绘制洪水等级散点:用scatter()方法传入日期索引和洪水等级数据,设置醒目的样式(比如红色星型标记),方便和折线图区分。
  • 调整双轴样式:因为洪水等级是0-3,设置ylim([0,3.2])避免刻度贴边,自定义yticklabels让刻度对应等级分类,更直观。

完整实现代码

import matplotlib.pyplot as plt

# 假设x/y/z是对应年份的日期索引数据
x = YEAR1m.index
y = YEAR2m.index
z = YEAR3m.index

fig,ax = plt.subplots(3, figsize=(10,15),sharey=True)

# 第一个子图:降雨折线 + 洪水等级散点
ax[0].plot(YEAR1['pcp_1D_tot'], label='RG')
ax[0].plot(YEAR1['ppt_1D'], label='TRMM')
ax[0].set_title('Year 1',x=0.1,y=0.9)
ax0 = ax[0].twinx()
ax0.scatter(x, YEAR1m['Size'], marker='*', color='r',s=100)
ax0.set_ylim([0,3.2])
ax0.set_yticklabels(['0',' ','1',' ','2',' ','3'])
ax0.set_ylabel('Flood Level')  # 可选:给右侧轴加标签,提升可读性

# 第二个子图
ax[1].plot(YEAR2['pcp_1D_tot'], label='RG')
ax[1].plot(YEAR2['ppt_1D'], label='TRMM')
ax[1].set_title('Year 2',x=0.1,y=0.9)
ax[1].set_ylabel('Rainfall total (mm/day)')
ax1 = ax[1].twinx()
ax1.scatter(y, YEAR2m['Size'], marker='*', color='r',s=100)
ax1.set_ylim([0,3.2])
ax1.set_yticklabels(['0',' ','1',' ','2',' ','3'])
ax1.set_ylabel('Flood Level')

# 第三个子图
ax[2].plot(YEAR3['pcp_1D_tot'], label='RG')
ax[2].plot(YEAR3['ppt_1D'], label='TRMM')
ax[2].set_title('Year 3',x=0.1,y=0.9)
ax[2].set_xlabel('Date')
ax2 = ax[2].twinx()
ax2.scatter(z, YEAR3m['Size'], marker='*', color='r',s=100)
ax2.set_ylim([0,3.2])
ax2.set_yticklabels(['0',' ','1',' ','2',' ','3'])
ax2.set_ylabel('Flood Level')

fig.tight_layout()
plt.show()

小优化建议

如果3个子图的右侧轴逻辑完全一致,你可以用循环简化代码,减少重复:

# 假设年份数据和索引放在列表里
year_data = [YEAR1, YEAR2, YEAR3]
year_index = [x, y, z]
year_labels = ['Year 1', 'Year 2', 'Year 3']

fig, axs = plt.subplots(3, figsize=(10,15), sharey=True)

for idx, (data, idx_data, label) in enumerate(zip(year_data, year_index, year_labels)):
    ax = axs[idx]
    ax.plot(data['pcp_1D_tot'], label='RG')
    ax.plot(data['ppt_1D'], label='TRMM')
    ax.set_title(label, x=0.1, y=0.9)
    
    # 创建双轴并绘制散点
    twin_ax = ax.twinx()
    twin_ax.scatter(idx_data, data['Size'], marker='*', color='r', s=100)
    twin_ax.set_ylim([0,3.2])
    twin_ax.set_yticklabels(['0',' ','1',' ','2',' ','3'])
    twin_ax.set_ylabel('Flood Level')
    
    if idx == 1:
        ax.set_ylabel('Rainfall total (mm/day)')
    if idx == 2:
        ax.set_xlabel('Date')

fig.legend(loc=(0.8,0.9))
fig.tight_layout()
plt.show()

这样代码更简洁,后期维护也更方便~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:00:50