如何在Matplotlib中调整多Y轴spine与图例的左侧布局
多独立Y轴Matplotlib布局解决方案
核心思路
通过创建多个共享X轴的独立Axes对象,手动调整每个轴的脊柱(spine)位置和图例偏移,实现你需要的【温度+湿度(左)---绘图区---气压+紫外线(右)】布局,完全适配独立数据。
完整实现代码
import matplotlib.pyplot as plt import pandas as pd import numpy as np # 构造示例数据(替换成你的真实数据) dates = pd.date_range(start='2024-01-01', periods=20, freq='D') temp = np.random.randint(10, 30, size=20) humidity = np.random.randint(40, 80, size=20) pressure = np.random.randint(1000, 1030, size=20) uv = np.random.randint(0, 10, size=20) # 创建画布和主X轴(用于共享日期轴) fig, ax_main = plt.subplots(figsize=(12, 6)) # ---------------------- 左侧第一个Y轴:温度 ---------------------- ax_temp = ax_main.twinx() # 将脊柱向左偏移15%绘图区宽度 ax_temp.spines['left'].set_position(('axes', -0.15)) ax_temp.spines['left'].set_visible(True) ax_temp.spines['right'].set_visible(False) # 刻度显示在左侧 ax_temp.yaxis.set_ticks_position('left') # 绘制曲线并保存句柄用于图例 line_temp, = ax_temp.plot(dates, temp, color='#ff4444', label='温度(℃)') # 把图例定位到脊柱左侧 ax_temp.legend(handles=[line_temp], loc='upper left', bbox_to_anchor=(-0.14, 1)) # ---------------------- 左侧第二个Y轴:湿度 ---------------------- ax_humidity = ax_main.twinx() # 脊柱再向左偏移13%(累计偏移28%) ax_humidity.spines['left'].set_position(('axes', -0.28)) ax_humidity.spines['left'].set_visible(True) ax_humidity.spines['right'].set_visible(False) ax_humidity.yaxis.set_ticks_position('left') line_humidity, = ax_humidity.plot(dates, humidity, color='#33b5e5', label='湿度(%)') ax_humidity.legend(handles=[line_humidity], loc='upper left', bbox_to_anchor=(-0.27, 0.9)) # ---------------------- 右侧第一个Y轴:气压 ---------------------- ax_pressure = ax_main.twinx() # 脊柱向右偏移10%绘图区宽度 ax_pressure.spines['right'].set_position(('axes', 1.1)) ax_pressure.spines['right'].set_visible(True) ax_pressure.spines['left'].set_visible(False) ax_pressure.yaxis.set_ticks_position('right') line_pressure, = ax_pressure.plot(dates, pressure, color='#99cc00', label='气压(hPa)') ax_pressure.legend(handles=[line_pressure], loc='upper right', bbox_to_anchor=(1.09, 1)) # ---------------------- 右侧第二个Y轴:紫外线 ---------------------- ax_uv = ax_main.twinx() # 脊柱再向右偏移13%(累计偏移23%) ax_uv.spines['right'].set_position(('axes', 1.23)) ax_uv.spines['right'].set_visible(True) ax_uv.spines['left'].set_visible(False) ax_uv.yaxis.set_ticks_position('right') line_uv, = ax_uv.plot(dates, uv, color='#ffbb33', label='紫外线指数') ax_uv.legend(handles=[line_uv], loc='upper right', bbox_to_anchor=(1.22, 0.9)) # ---------------------- 整体布局调整 ---------------------- ax_main.set_xlabel('日期') # 调整X轴刻度密度,避免重叠 ax_main.set_xticks(dates[::2]) ax_main.set_xticklabels(dates.strftime('%m-%d')[::2], rotation=45) # 隐藏主轴的Y轴元素,消除干扰 ax_main.spines[['left', 'right']].set_visible(False) ax_main.yaxis.set_visible(False) # 调整画布左右边距,防止左侧轴/图例被截断 plt.subplots_adjust(left=0.2, right=0.8) plt.tight_layout() plt.show()
关键问题解决说明
脊柱位置调整失败:
- 必须隐藏每个轴不需要的脊柱(比如温度轴隐藏右侧脊柱),否则偏移后会出现双重脊柱
set_position(('axes', offset))的offset是相对绘图区的比例,负数向左偏移,正数向右偏移
图例移到脊柱左侧/右侧:
- 不能仅靠
loc参数,需要配合bbox_to_anchor手动定位,数值和脊柱偏移量对应,保证图例和脊柱对齐
- 不能仅靠
独立数据适配:
- 每个指标用单独的
twinx()创建轴,完全独立处理数据,避免secondary_yaxis只能基于主轴数据转换的限制
- 每个指标用单独的
内容的提问来源于stack exchange,提问作者Ben Nguyen
相关产品推荐
相关产品推荐

