You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

子图日期与月份格式化问题:多年份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()
问题原因
  1. 仅绘制SST数值数组,未传入对应年份的日期序列,matplotlib默认用数组索引作为X轴坐标,后续用日期格式化器时,会基于设置的全局epoch(2016)计算年份,导致所有子图年份统一为2016。
  2. 全局设置mdates.set_epoch(new_epoch)完全没必要,反而干扰了日期的正确显示。
解决方法
  1. 为每个年份生成对应的每日日期序列,确保X轴坐标是真实的日期值。
  2. 绘制时将日期序列与SST数据配对传入plot函数,让matplotlib识别真实日期。
  3. 移除全局epoch设置,每个子图基于自身的日期序列显示正确年份。
  4. 优化数据读取逻辑,减少重复代码。
修改后的代码
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 12:25:17