天气数据绘图x轴时间戳格式化异常及定制需求求助
解决Matplotlib天气数据绘图的X轴格式化问题(附完整修复代码)
哇,我太懂这种调时间轴调得头大的感觉了!你遇到的ValueError: year is out of range十有八九是Unix时间戳单位不匹配导致的——很多时候我们拿到的天气数据时间戳是毫秒级的,但matplotlib的mdates默认认秒级的epoch时间,直接喂毫秒的话会被解析成几十万年以后的时间,自然报错。
结合你的需求(30分钟刻度、每小时虚线网格、UTC时区00:00显示日期),我整理了一套亲测有效的解决方案:
核心问题定位
你的时间戳是Unix epoch格式,但如果是毫秒级(比如1690000000000),直接传给mdates会触发年份溢出错误。第一步必须把时间戳转换成UTC时区的datetime对象。
完整修复代码示例
假设你的样本数据是包含timestamp(Unix时间戳)和temperature(温度)的列表/数组,代码如下:
import matplotlib.pyplot as plt import matplotlib.dates as mdates from datetime import datetime, timezone import numpy as np # ---------------------- 模拟你的样本数据 ---------------------- # 注意:这里用毫秒级时间戳模拟常见的天气数据格式 timestamps_ms = np.arange(1690000000000, 1690100000000, 1800000) # 每30分钟一个数据点 temperatures = np.random.randn(len(timestamps_ms)) * 5 + 25 # ---------------------- 关键:时间戳转换为UTC datetime ---------------------- # 先判断时间戳单位:如果是毫秒就除以1000,秒级就直接用 # 可以通过打印第一个时间戳的长度判断:13位是毫秒,10位是秒 if len(str(timestamps_ms[0])) == 13: timestamps_s = timestamps_ms / 1000 else: timestamps_s = timestamps_ms # 转换为UTC时区的datetime对象 utc_dates = [datetime.fromtimestamp(ts, timezone.utc) for ts in timestamps_s] # ---------------------- 绘图与X轴格式化 ---------------------- fig, ax = plt.subplots(figsize=(12, 6)) ax.plot(utc_dates, temperatures, label="Temperature (°C)") # 1. 设置X轴刻度:每30分钟一个标记 ax.xaxis.set_major_locator(mdates.MinuteLocator(interval=30)) # 2. 设置X轴标签:自定义格式化——00:00显示日期,其他显示HH:MM def custom_date_formatter(x, pos): date = mdates.num2date(x, tz=timezone.utc) if date.hour == 0 and date.minute == 0: # 00:00位置显示日期(UTC) return date.strftime("%Y-%m-%d") else: # 其他时间显示HH:MM return date.strftime("%H:%M") ax.xaxis.set_major_formatter(plt.FuncFormatter(custom_date_formatter)) # 3. 设置每小时的垂直虚线网格 ax.xaxis.set_minor_locator(mdates.HourLocator(interval=1)) ax.grid(True, which='minor', axis='x', linestyle='--', color='gray', alpha=0.5) ax.grid(True, which='major', axis='y', linestyle='-', color='lightgray') # 4. 旋转X轴标签避免重叠 plt.xticks(rotation=45, ha='right') ax.set_ylabel("Temperature (°C)") ax.set_title("Weather Data (UTC Time)") ax.legend() plt.tight_layout() plt.show()
关键细节说明
- 时间戳转换:一定要确认是秒级还是毫秒级,这是解决
year is out of range的核心! - 自定义格式化器:通过
FuncFormatter判断当前时间是否为00:00,分别显示日期或时间,完美匹配你的需求。 - 网格设置:用
HourLocator作为次要定位器,设置虚线网格,既满足每小时的分隔,又不干扰30分钟的主刻度。 - UTC时区:全程用
timezone.utc确保时间显示正确,避免本地时区干扰。
排查小技巧
如果还是报错,你可以先打印几个转换后的utc_dates对象,确认年份是正常的(比如2023/2024),如果年份是几千甚至几万,那肯定是时间戳单位没转对!
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

