如何在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
相关产品推荐
相关产品推荐

