简介
GRIB(General Regularly distributed Information in Binary form)是世界气象组织(WMO)标准化的二进制格式,专门用于存储和传输气象、海洋等领域的网格化物理量数据,以其高效压缩和灵活的元数据结构,成为全球气象业务与科研的通用标准。然而,面对这种专业格式,许多人在第一步“读取数据”时就可能陷入困境——复杂的二进制结构、令人眼花缭乱的参数编码、多层次的海量数据……本文介绍如何使用 pygrib 轻松读取 GRIB 文件,提取你需要的气象要素,并经过简单处理进行绘图!
代码
import pygribimport numpy as npimport matplotlib.pyplot as pltimport cartopy.crs as ccrsimport cartopy.feature as cfeaturefrom datetime import datetimedef plot_t2m_fixed(grib_file, target_date='1979-01-01'):""" 2m 温度 """ grbs = pygrib.open(grib_file) found_data = [] target_dt = datetime.strptime(target_date, '%Y-%m-%d').date()for grb in grbs:if (grb.parameterName == '2 metre temperature' and grb.typeOfLevel == 'surface' and grb.level == 0): data_time = grb.validDate# 检查日期是否匹配if data_time.date() == target_dt:print(f"✓ 找到匹配数据: 时间 {data_time}") found_data.append({'grb': grb,'time': data_time })if not found_data:print(f"未找到 {target_date} 的数据") grbs.close()return None, None, None grb = found_data[0]['grb'] data_time = found_data[0]['time']print(f"使用数据时间: {data_time}")# 获取数据 t2m_data = grb.values lats, lons = grb.latlons()print(f"数据形状: {t2m_data.shape}")print(f"纬度范围: {lats.min():.2f} 到 {lats.max():.2f}")print(f"经度范围: {lons.min():.2f} 到 {lons.max():.2f}")print(f"温度范围: {t2m_data.min():.2f}K 到 {t2m_data.max():.2f}K")# 转换为摄氏度 t2m_data_celsius = t2m_data - 273.15 unit = "°C"# 区域裁剪 lat_range = (20, 50) lon_range = (100, 130) lat_mask = (lats >= lat_range[0]) & (lats <= lat_range[1]) lon_mask = (lons >= lon_range[0]) & (lons <= lon_range[1]) region_mask = lat_mask & lon_mask region_lats = lats[region_mask] region_lons = lons[region_mask] region_t2m = t2m_data_celsius[region_mask]# 计算统计 region_mean = np.mean(region_t2m) region_max = np.max(region_t2m) region_min = np.min(region_t2m)print(f"\n区域统计 ({target_date}):")print(f"平均温度: {region_mean:.2f}{unit}")print(f"最高温度: {region_max:.2f}{unit}")print(f"最低温度: {region_min:.2f}{unit}")# 绘图 plot_temperature_map(region_lons, region_lats, region_t2m, data_time, unit, lat_range, lon_range) grbs.close()return region_t2m, region_lats, region_lonsdef plot_temperature_map(lons, lats, data, data_time, unit, lat_range, lon_range):""" 绘制温度分布图 """ fig = plt.figure(figsize=(12, 8)) ax = plt.axes(projection=ccrs.PlateCarree())# 设置地图范围 ax.set_extent([lon_range[0], lon_range[1], lat_range[0], lat_range[1]], crs=ccrs.PlateCarree())# 添加地图要素 ax.add_feature(cfeature.COASTLINE, linewidth=0.8) ax.add_feature(cfeature.BORDERS, linewidth=0.5) ax.add_feature(cfeature.OCEAN, color='lightblue', alpha=0.3) ax.add_feature(cfeature.LAND, color='lightgray', alpha=0.1)# 添加网格线 gl = ax.gridlines(draw_labels=True, alpha=0.5, linestyle='--') gl.top_labels = False gl.right_labels = False gl.xlabel_style = {'size': 10} gl.ylabel_style = {'size': 10}# 创建散点图 scatter = ax.scatter(lons, lats, c=data, cmap='RdBu_r', s=15, alpha=0.8, vmin=np.floor(np.min(data)), vmax=np.ceil(np.max(data)), transform=ccrs.PlateCarree())# 添加颜色条 cbar = plt.colorbar(scatter, ax=ax, orientation='vertical', shrink=0.8, pad=0.05) cbar.set_label(f'2m Temperature ({unit})', fontsize=12)# 设置标题 title_date = data_time.strftime('%Y-%m-%d %H:%M UTC') plt.title(f'2m Temperature - {title_date}\n' f'Region Mean: {np.mean(data):.2f}{unit}', fontsize=14, fontweight='bold') plt.tight_layout() plt.savefig('test_GRIB.png', dpi=600, bbox_inches='tight') plt.show()# 执行绘图try: data, lats, lons = plot_t2m_fixed('t2m_1979_hourly.grib', target_date='1979-12-01' )if data is not None:print("绘图完成!")else:print("未找到数据")except Exception as e:print(f"处理文件时出错: {e}") import traceback traceback.print_exc()
结果