【WRF后处理】提取某要素数据并绘制地图
【WRF后处理】提取某要素数据并绘制地图
- 根据Domain提取文件
- 提取某要素数据并绘制地图
- 参考
根据Domain提取文件
为了满足根据需求提取不同区域(例如 D01、D02、D03)的文件,可以将区域作为函数的一个参数传入,并根据传入的区域自动匹配相应的文件。使用正则表达式来动态生成匹配模式,从而提取不同区域的 wrfout 文件。
Python代码如下:
import os
import re
def get_wrfout_files_by_domain(directory, domain):
"""
从指定目录中提取指定域 (D01, D02, D03) 的 wrfout 文件。
参数:
directory (str): 文件夹路径
domain (str): 需要提取的域 (例如 "d01", "d02", "d03")
返回:
list: 包含所有符合条件的 wrfout 文件的绝对路径
"""
# 检查 domain 参数是否正确
if domain.lower() not in ["d01", "d02", "d03"]:
raise ValueError("域必须是 'd01'、'd02' 或 'd03'")
# 用于存储符合条件的文件
wrfout_files = []
# 定义 wrfout 文件的正则表达式模式,动态匹配域
pattern = re.compile(fr"^wrfout_{domain}_\d{{4}}-\d{{2}}-\d{{2}}_\d{{2}}_\d{{2}}_\d{{2}}$")
# 遍历目录中的所有文件
for filename in os.listdir(directory):
# 检查文件名是否匹配 wrfout_{domain} 的格式
if pattern.match(filename):
# 将符合条件的文件的绝对路径添加到列表中
wrfout_files.append(os.path.join(directory, filename))
return wrfout_files
# 示例用法
directory = "/path/to/your/wrfout/files" # 替换为实际的文件夹路径
# 提取 D03 区域文件
wrfout_d03_files = get_wrfout_files_by_domain(directory, "d03")
for file in wrfout_d03_files:
print("D03区域文件:", file)
# 提取 D01 区域文件
wrfout_d01_files = get_wrfout_files_by_domain(directory, "d01")
for file in wrfout_d01_files:
print("D01区域文件:", file)
# 提取 D02 区域文件
wrfout_d02_files = get_wrfout_files_by_domain(directory, "d02")
for file in wrfout_d02_files:
print("D02区域文件:", file)
提取某要素数据并绘制地图
Python代码如下:
import os
import re
from netCDF4 import Dataset
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from wrf import getvar, to_np, get_cartopy, latlon_coords
import geopandas as gpd
from shapely.geometry import Polygon
# 设置字体为 Times New Roman
plt.rcParams['font.family'] = 'Times New Roman'
def get_wrfout_files_by_domain(directory, domain):
"""
从指定目录中提取指定域 (D01, D02, D03) 的 wrfout 文件。
参数:
directory (str): 文件夹路径
domain (str): 需要提取的域 (例如 "d01", "d02", "d03")
返回:
list: 包含所有符合条件的 wrfout 文件的绝对路径
"""
# 检查 domain 参数是否正确
if domain.lower() not in ["d01", "d02", "d03"]:
raise ValueError("域必须是 'd01'、'd02' 或 'd03'")
# 用于存储符合条件的文件
wrfout_files = []
# 定义 wrfout 文件的正则表达式模式,动态匹配域
pattern = re.compile(fr"^wrfout_{domain}_\d{{4}}-\d{{2}}-\d{{2}}_\d{{2}}_\d{{2}}_\d{{2}}$")
# 遍历目录中的所有文件
for filename in os.listdir(directory):
# 检查文件名是否匹配 wrfout_{domain} 的格式
if pattern.match(filename):
# 将符合条件的文件的绝对路径添加到列表中
wrfout_files.append(os.path.join(directory, filename))
return wrfout_files
def list_variables_in_wrfout(file_path):
"""
列出给定 wrfout 文件中的所有 WRF 变量。
参数:
file_path (str): wrfout 文件的路径
"""
# 使用 netCDF4 打开 wrfout 文件
dataset = Dataset(file_path)
print(f"\n文件: {file_path}")
print("包含的变量:")
# 使用 wrf-python 的 getvar 函数获取所有可用变量
for varname in dataset.variables:
print(varname)
# 关闭 NetCDF 文件
dataset.close()
def add_shapefile_to_ax(ax, shapefile_path):
"""
将 shapefile 添加到指定的 cartopy 绘图轴上。
参数:
ax (geoaxes.GeoAxesSubplot): cartopy 投影的绘图轴
shapefile_path (str): shapefile 的路径
"""
# 使用 geopandas 读取 shapefile
gdf = gpd.read_file(shapefile_path)
# 检查 shapefile 是否有坐标系
if gdf.crs is not None:
print(f"Shapefile {shapefile_path} 的原始坐标系: {gdf.crs}")
else:
raise ValueError(f"Shapefile {shapefile_path} 没有坐标系!")
# 将 shapefile 转换为 PlateCarree 投影,这是 cartopy 常用的地理坐标系
gdf = gdf.to_crs(ccrs.PlateCarree().proj4_init)
# 将 GeoDataFrame 中的几何体逐一添加到 ax 中
for geom in gdf.geometry:
ax.add_geometries([geom], crs=ccrs.PlateCarree(), edgecolor='black', facecolor='none', linewidth=1)
def extract_and_plot_t2(file_path, output_dir):
"""
从 wrfout 文件中提取 2米温度 (T2) 并绘制地图。
参数:
file_path (str): wrfout 文件的路径
output_dir (str): 保存地图的目录路径
"""
# 打开 wrfout 文件
dataset = Dataset(file_path)
# 使用 wrf-python 提取 2米温度 (T2)
t2 = getvar(dataset, "T2")
# 将温度从开尔文转换为摄氏度
t2_celsius = t2 - 273.15
# 提取经纬度坐标
lats, lons = latlon_coords(t2)
# 获取 cartopy 投影
cart_proj = get_cartopy(t2)
# 创建绘图
fig = plt.figure(figsize=(12, 10))
ax = plt.axes(projection=cart_proj)
# 绘制T2的值(即2米温度,单位为摄氏度)
t2_contour = ax.contourf(to_np(lons), to_np(lats), to_np(t2_celsius), 10, transform=ccrs.PlateCarree(), cmap="coolwarm")
# 添加海岸线和州界
# ax.coastlines('50m', linewidth=0.8)
# ax.add_feature(cfeature.BORDERS, linewidth=0.5)
# 加载并绘制 SHP 文件(大湾区和中国边界)
GBAshp_file_path = "C:/PycharmProjects/GBA_Data_Process/shpFile/GBA/GBA.shp"
Chinashp_file_path = "C:/PycharmProjects/GBA_Data_Process/shpFile/China/中国.shp"
# 使用转换后的绘制方法
add_shapefile_to_ax(ax, GBAshp_file_path)
add_shapefile_to_ax(ax, Chinashp_file_path)
# 添加经纬度网格和标签
gl = ax.gridlines(draw_labels=True, linewidth=0.5, color='gray', alpha=0.5, linestyle='--')
gl.top_labels = False # 关闭顶部标签
gl.right_labels = False # 关闭右侧标签
gl.bottom_labels = False # 关闭底部标签(稍后手动添加)
# 设置经纬度刻度的字体大小
gl.xlabel_style = {'size': 14, 'color': 'black'}
gl.ylabel_style = {'size': 14, 'color': 'black'}
# 手动添加经度标签,确保它们显示在底部外侧
lon_labels = np.arange(-180, 181, 1) # 经度范围 [-180, 180],间隔 1 度
for lon in lon_labels:
ax.text(lon, -89.5, f"{lon}°", va='top', ha='center', fontsize=12,
transform=ccrs.PlateCarree()) # 这里使用 -89.5 代替 -90
# 添加自定义的 X 和 Y 轴标签(经度和纬度的名称)
ax.text(0.5, -0.02, "Longitude (°E)", va='top', ha='center', fontsize=16, transform=ax.transAxes)
ax.text(-0.10, 0.5, "Latitude (°N)", va='center', ha='right', fontsize=16, rotation='vertical', transform=ax.transAxes)
# 设置经度和纬度的刻度在外侧显示
ax.xaxis.set_ticks_position('bottom') # 经度刻度放在下侧
ax.xaxis.set_label_position('bottom') # 经度标签放在下侧
ax.yaxis.set_ticks_position('left') # 纬度刻度放在左侧
ax.yaxis.set_label_position('left') # 纬度标签放在左侧
# 将刻度设置为指向图形外部
ax.tick_params(axis='both', which='both', direction='out')
# 添加颜色栏(竖直放置,放置在图形右侧)
cbar = plt.colorbar(t2_contour, ax=ax, orientation="vertical", pad=0.05, aspect=20, shrink=0.96)
cbar.set_label("Temperature (°C)", fontsize=14)
# 修改 colorbar 刻度的字体大小
cbar.ax.tick_params(labelsize=12) # 将字体大小设为 12
# 设置标题
plt.title(f"2-meter Temperature (T2) in Celsius from {os.path.basename(file_path)}", fontsize=14)
# 保存图像
output_file = os.path.join(output_dir, f"T2_map_{os.path.basename(file_path)}.png")
plt.savefig(output_file, dpi=600)
plt.close()
print(f"保存地图: {output_file}")
# 关闭 NetCDF 文件
dataset.close()
def extract_and_plot_precipitation(file_path, output_dir):
"""
从 wrfout 文件中提取累计降水 (RAINC + RAINNC) 并绘制地图。
参数:
file_path (str): wrfout 文件的路径
output_dir (str): 保存地图的目录路径
"""
# 打开 wrfout 文件
dataset = Dataset(file_path)
# 使用 wrf-python 提取累计对流降水 (RAINC) 和累计非对流降水 (RAINNC)
rainc = getvar(dataset, "RAINC") # 累计对流降水
rainnc = getvar(dataset, "RAINNC") # 累计非对流降水
# 累计降水量 = RAINC + RAINNC
total_precip = rainc + rainnc
# 提取经纬度坐标
lats, lons = latlon_coords(total_precip)
# 获取 cartopy 投影 - 改为使用 T2 变量或其他原始变量来获取投影信息
t2 = getvar(dataset, "T2") # 使用 T2 提取投影
cart_proj = get_cartopy(t2)
# 创建绘图
fig = plt.figure(figsize=(12, 10))
ax = plt.axes(projection=cart_proj)
# 设置图形范围与 WRF 数据一致
ax.set_extent([np.min(to_np(lons)), np.max(to_np(lons)), np.min(to_np(lats)), np.max(to_np(lats))], crs=ccrs.PlateCarree())
# 绘制累计降水量(单位:毫米)
precip_contour = ax.contourf(to_np(lons), to_np(lats), to_np(total_precip), 10, transform=ccrs.PlateCarree(), cmap="Blues")
# 添加海岸线和州界
# ax.coastlines('50m', linewidth=0.8)
# ax.add_feature(cfeature.BORDERS, linewidth=0.5)
# 加载并绘制 SHP 文件(大湾区和中国边界)
GBAshp_file_path = "C:/PycharmProjects/GBA_Data_Process/shpFile/GBA/GBA.shp"
Chinashp_file_path = "C:/PycharmProjects/GBA_Data_Process/shpFile/China/中国.shp"
# 使用转换后的绘制方法
add_shapefile_to_ax(ax, GBAshp_file_path)
add_shapefile_to_ax(ax, Chinashp_file_path)
# 添加经纬度网格和标签
gl = ax.gridlines(draw_labels=True, linewidth=0.5, color='gray', alpha=0.5, linestyle='--')
gl.top_labels = False # 关闭顶部标签
gl.right_labels = False # 关闭右侧标签
gl.bottom_labels = False # 关闭底部标签(稍后手动添加)
# 设置经纬度刻度的字体大小
gl.xlabel_style = {'size': 14, 'color': 'black'}
gl.ylabel_style = {'size': 14, 'color': 'black'}
# 手动添加经度标签,确保它们显示在底部外侧
lon_labels = np.arange(-180, 181, 1) # 经度范围 [-180, 180],间隔 1 度
for lon in lon_labels:
ax.text(lon, -89.5, f"{lon}°", va='top', ha='center', fontsize=12,
transform=ccrs.PlateCarree()) # 这里使用 -89.5 代替 -90
# 添加自定义的 X 和 Y 轴标签(经度和纬度的名称)
ax.text(0.5, -0.02, "Longitude (°E)", va='top', ha='center', fontsize=16, transform=ax.transAxes)
ax.text(-0.10, 0.5, "Latitude (°N)", va='center', ha='right', fontsize=16, rotation='vertical', transform=ax.transAxes)
# 设置经度和纬度的刻度在外侧显示
ax.xaxis.set_ticks_position('bottom') # 经度刻度放在下侧
ax.xaxis.set_label_position('bottom') # 经度标签放在下侧
ax.yaxis.set_ticks_position('left') # 纬度刻度放在左侧
ax.yaxis.set_label_position('left') # 纬度标签放在左侧
# 将刻度设置为指向图形外部
ax.tick_params(axis='both', which='both', direction='out')
# 添加颜色栏(竖直放置,放置在图形右侧)
cbar = plt.colorbar(precip_contour, ax=ax, orientation="vertical", pad=0.05, aspect=20, shrink=0.96)
cbar.set_label("Cumulative Precipitation (mm)", fontsize=14)
# 修改 colorbar 刻度的字体大小
cbar.ax.tick_params(labelsize=12) # 将字体大小设为 12
# 设置标题
plt.title(f"Cumulative Precipitation from {os.path.basename(file_path)}", fontsize=14)
# 保存图像
output_file = os.path.join(output_dir, f"Precipitation_map_{os.path.basename(file_path)}.png")
plt.savefig(output_file, dpi=600)
plt.close()
print(f"保存降水地图: {output_file}")
# 关闭 NetCDF 文件
dataset.close()
# 示例用法
directory = "C:/Database/wrfout" # 替换为实际的文件夹路径
output_dir = "C:/Database/wrfout-Outputs/Figures" # 替换为保存地图的路径
# 检查输出目录是否存在,如果不存在则创建
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# 提取 D03 区域文件
wrfout_d03_files = get_wrfout_files_by_domain(directory, "d03")
for file in wrfout_d03_files:
print("D03区域文件:", file)
# 遍历 D03 文件,列出每个文件的变量
# list_variables_in_wrfout(file)
# 提取T2并绘制地图
# extract_and_plot_t2(file, output_dir)
# 提取降水并绘制地图
extract_and_plot_precipitation(file, output_dir)