如何用Matplotlib快速绘制带日期的Hovmöller图或热力图?
生成带时间/经度分箱的Hovmöller图(日期轴热力图)
针对你需要的时间-经度分箱热力图(Hovmöller图),这里提供三种无需手动写复杂分箱逻辑的简便方案,适配大量日期(如5500+)的场景:
方案一:Pandas + Seaborn(最易上手)
利用Pandas的分组/分箱函数快速统计频次,再用Seaborn绘制热力图,自动处理日期轴:
import pandas as pd import seaborn as sns import matplotlib.pyplot as plt from matplotlib.dates import DateFormatter # 1. 构造数据框:替换成你的dates和lons列表 df = pd.DataFrame({ 'date': pd.to_datetime(dates), # 自动解析日期字符串 'lon': lons }) # 2. 经度分箱:按1度间隔划分(范围可根据你的数据调整) lon_bins = pd.interval_range(start=-180, end=180, freq=1) df['lon_center'] = pd.cut(df['lon'], bins=lon_bins).apply(lambda x: x.mid) # 用分箱中心值做标签 # 3. 时间分箱:按需求设置频率,比如每周('W')、每月('M')、10天('10D') time_freq = 'W' # 可根据可视化清晰度调整 heatmap_data = df.pivot_table( index=pd.Grouper(key='date', freq=time_freq), columns='lon_center', values='lon', aggfunc='count', # 统计每个分箱的样本数,可换成mean等其他统计量 fill_value=0 ) # 4. 绘制热力图 plt.figure(figsize=(12, 8)) sns.heatmap(heatmap_data.T, cmap='viridis', cbar_kws={'label': '样本数量'}) # 格式化日期轴,避免重叠 plt.gca().xaxis.set_major_formatter(DateFormatter('%Y-%m')) plt.xlabel('时间') plt.ylabel('经度 (°)') plt.title('时间-经度Hovmöller图') plt.xticks(rotation=45) plt.tight_layout() plt.show()
关键说明:
- 时间分箱的
freq参数完全自定义,5500个日期按周分箱会得到约780个时间区间,显示足够清晰且可扩展到更多日期。 - 若需要自定义时间分箱范围,可替换为
pd.date_range生成固定间隔的时间箱,再用pd.cut分组。
方案二:Matplotlib hist2d(直接解决日期轴报错问题)
核心思路是把日期转成数值型(自起始日的天数)分箱,再转回日期格式显示,解决hist2d的日期兼容问题:
import numpy as np import matplotlib.pyplot as plt from matplotlib.dates import DateFormatter, num2date import pandas as pd # 1. 预处理数据 df = pd.DataFrame({'date': pd.to_datetime(dates), 'lon': lons}) # 日期转数值:将datetime转为自1970-01-01的天数 date_nums = df['date'].view('int64') // (10**9 * 86400) # 2. 设置分箱参数 time_bin_width = 7 # 时间分箱宽度(天),比如7天=1周 lon_bin_width = 1 # 经度分箱宽度(度) time_bins = np.arange(date_nums.min(), date_nums.max() + time_bin_width, time_bin_width) lon_bins = np.arange(-180, 181, lon_bin_width) # 3. 绘制hist2d plt.figure(figsize=(12, 8)) counts, xedges, yedges, im = plt.hist2d( date_nums, df['lon'], bins=[time_bins, lon_bins], cmap='viridis' ) # 4. 把数值型x轴转回日期格式 plt.gca().set_xticks((xedges[:-1] + xedges[1:]) / 2) plt.gca().set_xticklabels(num2date((xedges[:-1] + xedges[1:]) / 2 * 86400 * 10**9)) plt.gca().xaxis.set_major_formatter(DateFormatter('%Y-%m')) plt.xlabel('时间') plt.ylabel('经度 (°)') plt.colorbar(im, label='样本数量') plt.xticks(rotation=45) plt.tight_layout() plt.show()
关键说明:
- 这种方法绕过了
hist2d对日期类型的不兼容,直接用数值分箱,再通过num2date转回日期格式化,适合习惯用Matplotlib原生绘图的场景。
进阶方案:Xarray(专业气象/时序数据工具)
如果你的数据是时序类,Xarray的plot.hovmoller是专门为这类图设计的,代码更简洁:
import xarray as xr import pandas as pd import matplotlib.pyplot as plt from matplotlib.dates import DateFormatter # 1. 分箱统计 df = pd.DataFrame({'date': pd.to_datetime(dates), 'lon': lons}) df['time_bin'] = pd.Grouper(key='date', freq='W') df['lon_bin'] = pd.cut(df['lon'], bins=np.arange(-180, 181, 1)) count_df = df.groupby(['time_bin', 'lon_bin']).count().reset_index() # 2. 转成Xarray Dataset并绘图 ds = count_df.set_index(['time_bin', 'lon_bin'])['lon'].to_xarray() ds.plot.hovmoller(x='time_bin', y='lon_bin', cmap='viridis', cbar_label='样本数量') plt.gca().xaxis.set_major_formatter(DateFormatter('%Y-%m')) plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者Outis Nemo
相关产品推荐
相关产品推荐

