Pyplot多Y轴不同刻度绘图问题求助
如何在Matplotlib中创建多Y轴且各轴刻度独立的图表
问题描述
我想要绘制一张多Y轴、各轴刻度不同的可视化图表,在同一张图里用多个独立刻度的Y轴展示多条曲线。我写了一段Python代码,空图时效果符合预期,但加入数据后出现了问题:第i个轴会适配i+1轴的数据刻度,而非仅适配当前轴对应曲线的值,这也导致曲线出现不连续的情况。以下是我的代码:
fig, (ax, ax1, ax2, ax3, ax4, ax5) = plt.subplots(1, 6) chartBox = ax1.get_position() ax1.set_position([chartBox.x0-0.022, chartBox.y0, chartBox.width, chartBox.height]) chartBox = ax2.get_position() ax2.set_position([chartBox.x0-0.044, chartBox.y0, chartBox.width, chartBox.height]) chartBox = ax3.get_position() ax3.set_position([chartBox.x0-0.066, chartBox.y0, chartBox.width, chartBox.height]) chartBox = ax4.get_position() ax4.set_position([chartBox.x0-0.088, chartBox.y0, chartBox.width, chartBox.height]) chartBox = ax5.get_position() ax6=ax5.twinx() ax5.set_position([chartBox.x0-0.112, chartBox.y0, chartBox.width, chartBox.height]) ax.set_xticks([]) ax1.set_xticks([]) ax2.set_xticks([]) ax3.set_xticks([]) ax4.set_xticks([]) ax5.set_xticks([]) ax6.set_xticks([]) Hyper=[0.785,0.890275,6.443702104245254 ] Bayes=[0.789,0.88805,6.325708590132482 ] Ax=[0.817,0.885175,6.133054804498614 ] NG=[0.8,0.884825,6.290438322234702 ] BOHB=[0.785,0.8876999999999999,6.173551552576356 ] Ran=[0.787,0.884175,6.170678868638696 ] Zoo=[0.795,0.884625,6.325670890740688 ] j=0 tmp=ax tmp.plot(Hyper[j:j+2]) tmp.plot(Bayes[j:j+2]) tmp.plot(Ax[j:j+2]) tmp.plot(NG[j:j+2]) tmp.plot(BOHB[j:j+2]) tmp.plot(Ran[j:j+2]) tmp.plot(Zoo[j:j+2]) tmp=ax1 j=1 tmp.plot(Hyper[j:j+2]) tmp.plot(Bayes[j:j+2]) tmp.plot(Ax[j:j+2]) tmp.plot(NG[j:j+2]) tmp.plot(BOHB[j:j+2]) tmp.plot(Ran[j:j+2]) tmp.plot(Zoo[j:j+2]) plt.show()
注:此处仅提供3个轴的数据,我认为适用于3个轴的解决方案同样可推广至7个轴。
解决方案
问题根源分析
你当前用多个独立子图重叠的方式模拟多Y轴,本质上是把多个分离的图表叠在一起。每个子图的x轴默认使用数据的索引(比如第一次plot时x是[0,1],第二次plot时x还是[0,1],但对应的数据实际位置应该是[1,2]),这就导致子图间x轴范围不匹配,进而出现刻度互相干扰、曲线错位的问题。
正确做法:使用孪生轴(twinx())
Matplotlib的标准多Y轴实现是基于同一个主轴创建孪生轴——它们共享x轴,Y轴完全独立,能各自设置刻度、范围和样式,完美解决你的需求。
以下是适配你数据的修正代码:
import matplotlib.pyplot as plt # 准备数据 Hyper = [0.785, 0.890275, 6.443702104245254] Bayes = [0.789, 0.88805, 6.325708590132482] Ax = [0.817, 0.885175, 6.133054804498614] NG = [0.8, 0.884825, 6.290438322234702] BOHB = [0.785, 0.8876999999999999, 6.173551552576356] Ran = [0.787, 0.884175, 6.170678868638696] Zoo = [0.795, 0.884625, 6.325670890740688] x = range(len(Hyper)) # 统一x轴,确保所有曲线对齐 # 创建主图 fig, ax = plt.subplots(figsize=(10, 6)) # 第一组曲线:使用主Y轴 lines = [] lines += ax.plot(x, Hyper, label='Hyper') lines += ax.plot(x, Bayes, label='Bayes') lines += ax.plot(x, Ax, label='Ax') lines += ax.plot(x, NG, label='NG') lines += ax.plot(x, BOHB, label='BOHB') lines += ax.plot(x, Ran, label='Ran') lines += ax.plot(x, Zoo, label='Zoo') ax.set_ylabel('主Y轴刻度') ax.tick_params(axis='y') # 创建第二个孪生Y轴(独立刻度) ax2 = ax.twinx() # 示例:给这个轴单独绘制曲线(如果需要) # ax2.plot(x, [val*10 for val in Hyper], label='Hyper (x10)', color='red') ax2.set_ylabel('第二组Y轴刻度') ax2.tick_params(axis='y') # 创建第三个孪生Y轴,调整位置避免重叠 ax3 = ax.twinx() ax3.spines['right'].set_position(('axes', 1.15)) # 轴位置右移15% # ax3.plot(x, [val/10 for val in Hyper], label='Hyper (/10)', color='green') ax3.set_ylabel('第三组Y轴刻度') ax3.tick_params(axis='y') # 合并所有图例,避免重复 labels = [line.get_label() for line in lines] ax.legend(lines, labels, loc='upper left') plt.tight_layout() plt.show()
核心要点
- 统一x轴:所有曲线使用同一个x轴数据,保证数据点完全对齐,不会出现错位。
- 孪生轴独立性:
twinx()创建的轴和主轴共享x轴,但Y轴完全独立,每个轴的刻度、范围、颜色都可以单独设置,不会互相干扰。 - 多轴位置调整:当创建3个及以上右侧Y轴时,需要通过
spines['right'].set_position调整轴的位置,避免轴标签重叠。参数('axes', 1.15)表示轴位于主图右侧15%的位置,可根据轴的数量调整数值(比如第4个轴用1.3,第5个用1.45等)。 - 手动控制Y轴范围:如果需要固定某个轴的刻度范围,可以用
ax.set_ylim(min_val, max_val),让轴只适配对应曲线的数据。
扩展到7个Y轴
如果需要7个独立Y轴,只需重复创建孪生轴并依次调整位置即可:
# 第4个轴 ax4 = ax.twinx() ax4.spines['right'].set_position(('axes', 1.3)) ax4.set_ylabel('第四组Y轴刻度') # 第5个轴 ax5 = ax.twinx() ax5.spines['right'].set_position(('axes', 1.45)) ax5.set_ylabel('第五组Y轴刻度') # 第6、7个轴以此类推,逐步增加位置参数
这样每个Y轴都会独立适配自己的曲线数据,彻底解决你之前遇到的刻度干扰和曲线不连续问题。
内容的提问来源于stack exchange,提问作者AJSV
相关产品推荐
相关产品推荐

