Matplotlib多子图双Y轴对齐问题求助
解决Matplotlib双Y轴副轴刻度对齐问题
我太懂你这个困扰了——用twinx()搞出来的双Y轴副轴,想让它们在多个子图间对齐刻度,直接用get_shared_y_axes().join()确实经常不管用,因为这些副轴是绑定在主图轴上的独立对象,和subplots()生成的原生子图轴共享机制根本不是一套逻辑。
为什么你的原有方法失效?
get_shared_y_axes().join()本来就是给subplots()创建的原生轴设计的,而twinx()生成的副轴属于“寄生”在主轴上的轴,它们的共享逻辑不会自动触发刻度同步,所以哪怕你调用了join方法,副轴刻度该不对齐还是不对齐。
简洁解决方案:自动同步副轴Y范围
完全不用手动去查数据极值,我们可以先收集所有副轴的初始Y数据范围,算出全局的最小和最大值,再统一设置所有副轴的刻度范围,就能实现完美对齐。修改后的代码如下:
import matplotlib.pyplot as plt import pandas as pd excel_file = 'test_data.xlsx' sims = ['Sim 02', 'Sim 01', 'Sim 03'] if __name__ == '__main__': # 注意:新版pandas里sheetname已改为sheet_name,skipfooter参数保持不变 data = pd.read_excel(excel_file, skiprows=[0,1,2,3], sheet_name=None, header=1, index_col=[0,1], skipfooter=10) plot_cols = len(sims) plot_rows = 2 f, axes = plt.subplots(plot_rows, plot_cols, sharex='col', sharey='row') secondary_ax = [] secondary_ylims = [] # 用来收集所有副轴的Y刻度范围 for i, sim in enumerate(sims): df = data[sim] modern = df.loc['Modern'] # 主Y轴绘制Idle数据 axes[0][i].plot(modern.index, modern['Idle']) # 创建副轴并绘制Work数据 ax2 = axes[0][i].twinx() secondary_ax.append(ax2) ax2.plot(modern.index, modern['Work']) # 记录当前副轴的Y刻度范围 secondary_ylims.append(ax2.get_ylim()) # 第二行绘制Result柱状图 axes[1][i].bar(modern.index, modern['Result']) axes[0][i].set_xlim(12, 6) # 计算所有副轴的公共Y范围:取所有最小值里的最小,最大值里的最大 global_min = min(ylim[0] for ylim in secondary_ylims) global_max = max(ylim[1] for ylim in secondary_ylims) # 统一设置所有副轴的Y范围 for ax in secondary_ax: ax.set_ylim(global_min, global_max) plt.show()
可选:动态同步缩放(交互场景)
如果需要在用户缩放副轴时,其他副轴也自动同步刻度,可以加一个事件回调函数:
# 在plt.show()之前添加以下代码 def sync_secondary_axes(event): # 以第一个副轴为基准,同步所有其他副轴的刻度范围 ref_ylim = secondary_ax[0].get_ylim() for ax in secondary_ax[1:]: ax.set_ylim(ref_ylim) # 绑定鼠标释放事件(缩放/平移操作完成后触发同步) f.canvas.mpl_connect('button_release_event', sync_secondary_axes)
这个方案完全不需要手动干预数据,代码简洁还易维护,完美解决副轴刻度对齐的问题。
内容的提问来源于stack exchange,提问作者M Dillon
相关产品推荐
相关产品推荐

