如何在Python中同图对齐绘制年度叶绿素a与月度MEI.V2数据?
解决Matplotlib绘制不同频率时间序列数据的对齐问题
问题背景
需要在同一张图中展示1998-2021年的年度叶绿素a浓度和月度MEI.V2指数:
- 左y轴对应叶绿素a浓度
- 右y轴对应MEI.V2指数
- 要求月度MEI.V2数据与x轴年份正确对齐
原代码生成的图表存在时间轴对齐异常,x轴年份与数据不匹配。
测试数据代码
import numpy as np import pandas as pd # Generate yearly chlorophyll-a concentration data np.random.seed(0) dates = pd.date_range(start='1998-01-01', end='2021-12-31', freq='Y') chlorophyll_data = np.random.uniform(low=0, high=5, size=len(dates)) chlorophyll_df = pd.DataFrame({'Date': dates, 'Chlorophyll-a': chlorophyll_data}) # Generate monthly MEI.V2 data monthly_dates = pd.date_range(start='1998-01-01', end='2021-12-31', freq='M') mei_data = np.random.uniform(low=-2, high=2, size=len(monthly_dates)) mei_df = pd.DataFrame({'Date': monthly_dates, 'MEI.V2': mei_data})
原尝试代码
import matplotlib.pyplot as plt fig, ax1 = plt.subplots(figsize=(12, 6)) # Primary y-axis (left) ax1.plot(chlorophyll_df.index, chlorophyll_df['Chlorophyll-a'], marker='P', linestyle='-', linewidth=2) ax1.set_ylabel('Chlorophyll-a concentration [mg $m^{-3}$]') ax1.legend(ncol=4, loc='upper center') # Explicitly set the x-axis range plt.xlim(1998, 2021) # Secondary y-axis (right) ax2 = ax1.twinx() ax2.plot(mei_df.index, mei_df['MEI.V2'], color='red', linestyle='-') ax2.set_ylabel('MEI.V2', color='red') ax2.tick_params(axis='y') ax2.legend(loc='upper right') # Plot formatting plt.xticks(rotation=90) plt.tight_layout() plt.show()
问题根源
- 原代码使用DataFrame的默认整数索引绘图,而非实际的时间列
Date,导致Matplotlib无法识别时间序列,无法正确对齐数据 plt.xlim(1998,2021)是针对数值轴的设置,不适用于时间轴,无法正确限制时间范围
修正后的代码
import numpy as np import pandas as pd import matplotlib.pyplot as plt # ---------------------- 数据预处理 ---------------------- np.random.seed(0) # 年度叶绿素a数据:将Date设为时间索引 dates = pd.date_range(start='1998-01-01', end='2021-12-31', freq='Y') chlorophyll_data = np.random.uniform(low=0, high=5, size=len(dates)) chlorophyll_df = pd.DataFrame({'Chlorophyll-a': chlorophyll_data}, index=dates) # 月度MEI.V2数据:将Date设为时间索引 monthly_dates = pd.date_range(start='1998-01-01', end='2021-12-31', freq='M') mei_data = np.random.uniform(low=-2, high=2, size=len(monthly_dates)) mei_df = pd.DataFrame({'MEI.V2': mei_data}, index=monthly_dates) # ---------------------- 绘图实现 ---------------------- fig, ax1 = plt.subplots(figsize=(12, 6)) # 左轴:年度叶绿素a ax1.plot(chlorophyll_df.index, chlorophyll_df['Chlorophyll-a'], marker='P', linestyle='-', linewidth=2, label='Chlorophyll-a') ax1.set_ylabel('Chlorophyll-a concentration [mg $m^{-3}$]') ax1.set_xlabel('Year') ax1.legend(loc='upper center') ax1.tick_params(axis='both', labelsize=10) # 右轴:月度MEI.V2 ax2 = ax1.twinx() ax2.plot(mei_df.index, mei_df['MEI.V2'], color='red', linestyle='-', label='MEI.V2') ax2.set_ylabel('MEI.V2', color='red') ax2.tick_params(axis='y', labelcolor='red', labelsize=10) ax2.legend(loc='upper right') # 优化时间轴显示 fig.autofmt_xdate(rotation=45) # 自动旋转日期标签,避免重叠 plt.tight_layout() plt.show()
关键修正点
- 将
Date列设置为DataFrame的时间索引,让Matplotlib自动识别时间序列,实现数据与年份的正确对齐 - 移除无效的
plt.xlim(1998,2021),时间范围由时间索引自动适配 - 优化图例位置和标签样式,提升图表可读性
- 使用
fig.autofmt_xdate()自动处理x轴日期标签的旋转,解决标签重叠问题
内容的提问来源于stack exchange,提问作者Rony Golder
相关产品推荐
相关产品推荐

