子图日期与月份格式化问题:多年份SST时序图X轴年份不更新
问题描述
尝试绘制2014-2019年连续6年的海表温度(SST)全年时间序列子图,要求X轴刻度标记为月份。使用matplotlib.dates模块后,所有子图的X轴年份均为设置的epoch年份(2016),未随对应数据年份变化,需修改为显示2014-2019各自的年份。
原代码
import numpy as np import sys import matplotlib.pyplot as plt import matplotlib.dates as mdates from matplotlib.dates import set_epoch arrays14 = [np.asarray(list(map(str, line.split()))) for line in open('/home/swadhin/project/sst/daily/sst15n90e_dy_2014.ascii')] #loading the data arrays15 = [np.asarray(list(map(str, line.split()))) for line in open('/home/swadhin/project/sst/daily/sst15n90e_dy_2015.ascii')] arrays16 = [np.asarray(list(map(str, line.split()))) for line in open('/home/swadhin/project/sst/daily/sst15n90e_dy_2016.ascii')] arrays17 = [np.asarray(list(map(str, line.split()))) for line in open('/home/swadhin/project/sst/daily/sst15n90e_dy_2017.ascii')] arrays18 = [np.asarray(list(map(str, line.split()))) for line in open('/home/swadhin/project/sst/daily/sst15n90e_dy_2018.ascii')] arrays19 = [np.asarray(list(map(str, line.split()))) for line in open('/home/swadhin/project/sst/daily/sst15n90e_dy_2019.ascii')] arrays14 = np.delete(arrays14,[0,1,2,3,4],0) #deleting the headers arrays15 = np.delete(arrays15,[0,1,2,3,4],0) arrays16 = np.delete(arrays16,[0,1,2,3,4],0) arrays17 = np.delete(arrays17,[0,1,2,3,4],0) arrays18 = np.delete(arrays18,[0,1,2,3,4],0) arrays19 = np.delete(arrays19,[0,1,2,3,4,215,216,217],0) sst14 = [] for i in arrays14: d1 = i[0] d2 = i[2] sst1 = i[2] sst14.append(sst1) datetime1.append(d1) datetime2.append(d2) sst14 = np.array(sst14,dtype = np.float64) sst_14_m = np.ma.masked_equal(sst14,-9.99) #masking the fillvalues sst15 = [] for i in arrays15: sst2 = i[2] sst15.append(sst2) sst15 = np.array(sst15,dtype = np.float64) sst_15_m = np.ma.masked_equal(sst15,-9.99) sst16 = [] for i in arrays16: sst3 = i[2] sst16.append(sst3) sst16 = np.array(sst16,dtype = np.float64) sst_16_m = np.ma.masked_equal(sst16,-9.99) sst17 = [] for i in arrays17: sst4 = i[2] sst17.append(sst4) sst17 = np.array(sst17,dtype = np.float64) sst_17_m = np.ma.masked_equal(sst17,-9.99) sst18 = [] for i in arrays18: sst5 = i[2] sst18.append(sst5) sst18 = np.array(sst18,dtype = np.float64) sst_18_m = np.ma.masked_equal(sst18,-9.99) np.shape(sst18) sst19 = [] for i in arrays19: sst6 = i[2] sst19.append(sst6) sst19 = np.array(sst19,dtype = np.float64) sst19_u = np.zeros(len(sst14), dtype = np.float64) sst19_fill = np.full([118],-9.99,dtype=np.float64) sst19_u[0:211] = sst19[0:211] sst19_u[211:329] = sst19_fill sst19_u[329:365] = sst19[211:247] sst_19_m = np.ma.masked_equal(sst19_u,-9.99) ##########Plotting new_epoch = '2016-01-01T00:00:00' mdates.set_epoch(new_epoch) fig, axs=plt.subplots(3, 2, figsize=(12, 8),constrained_layout=True) axs = axs.ravel() axs[0].plot(sst_14_m) axs[1].plot(sst_15_m) axs[2].plot(sst_16_m) axs[3].plot(sst_17_m) axs[4].plot(sst_18_m) axs[5].plot(sst_19_m) for i in range(6): axs[i].xaxis.set_major_locator(mdates.MonthLocator()) axs[i].xaxis.set_minor_locator(mdates.MonthLocator()) axs[i].xaxis.set_major_formatter(mdates.ConciseDateFormatter(axs[i].xaxis.get_major_locator())) #axs[i].grid(True) axs[i].set_ylim(bottom=25, top=32) axs[i].set_ylabel('SST') plt.show()
问题原因
- 仅绘制SST数值数组,未传入对应年份的日期序列,matplotlib默认用数组索引作为X轴坐标,后续用日期格式化器时,会基于设置的全局epoch(2016)计算年份,导致所有子图年份统一为2016。
- 全局设置
mdates.set_epoch(new_epoch)完全没必要,反而干扰了日期的正确显示。
解决方法
- 为每个年份生成对应的每日日期序列,确保X轴坐标是真实的日期值。
- 绘制时将日期序列与SST数据配对传入
plot函数,让matplotlib识别真实日期。 - 移除全局epoch设置,每个子图基于自身的日期序列显示正确年份。
- 优化数据读取逻辑,减少重复代码。
修改后的代码
import numpy as np import matplotlib.pyplot as plt import matplotlib.dates as mdates from datetime import datetime, timedelta # 定义数据路径和年份列表 data_dir = '/home/swadhin/project/sst/daily/' years = [2014, 2015, 2016, 2017, 2018, 2019] sst_data = [] date_series = [] for year in years: # 读取数据文件 file_path = f'{data_dir}sst15n90e_dy_{year}.ascii' arrays = [np.asarray(list(map(str, line.split()))) for line in open(file_path)] # 删除表头 if year == 2019: arrays = np.delete(arrays, [0,1,2,3,4,215,216,217], 0) else: arrays = np.delete(arrays, [0,1,2,3,4], 0) # 提取SST数据并处理缺失值 sst = np.array([float(row[2]) for row in arrays], dtype=np.float64) sst_masked = np.ma.masked_equal(sst, -9.99) # 处理2019年的数据填充,确保长度为对应年份的天数 if year == 2019: full_length = 366 if year %4 ==0 else 365 sst_full = np.full(full_length, -9.99, dtype=np.float64) sst_full[0:211] = sst[0:211] sst_full[329:365] = sst[211:247] sst_masked = np.ma.masked_equal(sst_full, -9.99) sst_data.append(sst_masked) # 生成对应年份的日期序列 start_date = datetime(year, 1, 1) full_length = 366 if year %4 ==0 else 365 dates = [start_date + timedelta(days=i) for i in range(full_length)] date_series.append(dates) # 绘图部分 fig, axs = plt.subplots(3, 2, figsize=(12, 8), constrained_layout=True) axs = axs.ravel() for idx, (year, dates, sst) in enumerate(zip(years, date_series, sst_data)): axs[idx].plot(dates, sst) axs[idx].xaxis.set_major_locator(mdates.MonthLocator()) axs[idx].xaxis.set_major_formatter(mdates.ConciseDateFormatter(axs[idx].xaxis.get_major_locator())) axs[idx].set_ylim(bottom=25, top=32) axs[idx].set_ylabel('SST') axs[idx].set_title(f'{year}年SST时间序列') plt.show()
说明
- 新增日期序列生成逻辑,每个年份的X轴使用真实日期,确保年份显示正确。
- 用循环统一处理6年的数据读取和预处理,减少重复代码,提升可维护性。
- 移除全局epoch设置,让matplotlib自动基于传入的日期显示正确的年份和月份。
- 为每个子图添加年份标题,更直观区分不同年份的数据。
内容的提问来源于stack exchange,提问作者The Emerging Star
相关产品推荐
相关产品推荐

