Python 画水汽通量图 700hPa

本文介绍了如何使用WRF模型数据,进行700hPa高度的水汽比湿和风速插值,通过Lambert Conformal投影展示水汽通量分布,并加入省级行政线、海岸线及箭头指示。最终生成了包含省级边界和详细刻度的水汽通量地图。
摘要由CSDN通过智能技术生成
1. 背景介绍

在这里插入图片描述

2. 导库
import numpy as np
import xarray as xr
import matplotlib.pyplot as plt
from matplotlib.cm import get_cmap
import cartopy.crs as ccrs
import cartopy.feature as cfeat
import cartopy.io.shapereader as shpreader
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
import matplotlib.ticker as mticker
from netCDF4 import Dataset
from wrf import to_np, getvar, interplevel, ALL_TIMES, latlon_coords, get_cartopy
import warnings 
warnings.filterwarnings('ignore')
3. 准备工作: 兰伯特刻度线补丁子程序
from copy import copy
import numpy as np
import shapely.geometry as sgeom
import cartopy.crs as ccrs

def find_side(ls, side):
    """
    Given a shapely LineString which is assumed to be rectangular, return the
    line corresponding to a given side of the rectangle.

    """
    minx, miny, maxx, maxy = ls.bounds
    points = {'left': [(minx, miny), (minx, maxy)],
              'right': [(maxx, miny), (maxx, maxy)],
              'bottom': [(minx, miny), (maxx, miny)],
              'top': [(minx, maxy), (maxx, maxy)],}
    return sgeom.LineString(points[side])

def lambert_xticks(ax, ticks):
    """Draw ticks on the bottom x-axis of a Lambert Conformal projection."""
    te = lambda xy: xy[0]
    lc = lambda t, n, b: np.vstack((np.zeros(n) + t, np.linspace(b[2], b[3], n))).T
    xticks, xticklabels = _lambert_ticks(ax, ticks, 'bottom', lc, te)
    ax.xaxis.tick_bottom()
    ax.set_xticks(xticks)
    ax.set_xticklabels([ax.xaxis.get_major_formatter()(xtick) for xtick in xticklabels])

def lambert_yticks(ax, ticks):
    """Draw ticks on the left y-axis of a Lamber Conformal projection."""
    te = lambda xy: xy[1]
    lc = lambda t, n, b: np.vstack((np.linspace(b[0], b[1], n), np.zeros(n) + t)).T
    yticks, yticklabels = _lambert_ticks(ax, ticks, 'left', lc, te)
    ax.yaxis.tick_left()
    ax.set_yticks(yticks)
    ax.set_yticklabels([ax.yaxis.get_major_formatter()(ytick) for ytick in yticklabels])

def _lambert_ticks(ax, ticks, tick_location, line_constructor, tick_extractor):
    """Get the tick locations and labels for an axis of a Lambert Conformal projection."""
    outline_patch = sgeom.LineString(ax.outline_patch.get_path().vertices.tolist())
    axis = find_side(outline_patch, tick_location)
    n_steps = 30
    extent = ax.get_extent(ccrs.PlateCarree())
    _ticks = []
    for t in ticks:
        xy = line_constructor(t, n_steps, extent)
        proj_xyz = ax.projection.transform_points(ccrs.Geodetic(), xy[:, 0], xy[:, 1])
        xyt = proj_xyz[..., :2]
        ls = sgeom.LineString(xyt.tolist())
        locs = axis.intersection(ls)
        if not locs:
            tick = [None]
        else:
            tick = tick_extractor(locs.xy)
        _ticks.append(tick[0])
    # Remove ticks that aren't visible:    
    ticklabels = copy(ticks)
    while True:
        try:
            index = _ticks.index(None)
        except ValueError:
            break
        _ticks.pop(index)
        ticklabels.pop(index)
    return _ticks, ticklabels
4. 读取变量
wrfout_dir = "./data/wrfout_d02_2017-08-22_12"
wrfout      = Dataset(wrfout_dir, mode="r")
# 读取变量
it = 8
pres   = getvar(wrfout, "pressure", timeidx=it)
ua     = getvar(wrfout, "ua", units="m/s", timeidx=it)
va     = getvar(wrfout, "va", units="m/s", timeidx=it)
q      = getvar(wrfout, "QVAPOR", timeidx=it)
times  = getvar(wrfout, "times", meta=False, timeidx=ALL_TIMES) 

5. 水平插值与掩膜设置

# 水汽比湿、风速插值到700hPa高度
q_700   = interplevel(q,    pres, 700)
u_700   = interplevel(ua,   pres, 700)
v_700   = interplevel(va,   pres, 700)

# 计算水汽x和y方向的分量qu和qv,水汽通量的大小quv 
qu = q_700*u_700/9.8
qv = q_700*v_700/9.8
quv = np.sqrt(qu**2+qv**2)

#同时构造一个mask数组屏蔽水汽通量过小的地方
quv_masked = np.where(quv<0.02, np.nan, quv)
qu_masked = np.where(quv<0.02, np.nan, qu)
qv_masked = np.where(quv<0.02, np.nan, qv)

6. 经纬度和投影
lats, lons = latlon_coords(q_700)
wrf_proj = get_cartopy(q_700)
7. 画水汽通量图
# 4 基础图片
fig = plt.figure(figsize=(12,10))

ax  = plt.axes(projection=wrf_proj )


#增加省级行政线和海岸线
province  = shpreader.Reader('./data/china_shp/province.shp').geometries()
ax.add_geometries(province, ccrs.PlateCarree(), facecolor='none', edgecolor='black', zorder=10)
ax.coastlines('50m', linewidth=2.0, edgecolor="black",zorder=10)

# 5 水汽填色图
levels = np.arange(0.02, 0.07, 0.01)
cts = plt.contourf(lons, 
                   lats, 
                    # quv,
                    quv_masked,
                   levels=levels,
                   transform=ccrs.PlateCarree(),
                   cmap=get_cmap("BuGn"), # rianbow, BuGn
                   zorder=1, #图层顺序
                   extend='both')  # extend 色带两端是否带箭头
plt.colorbar(cts, ax=ax, orientation="horizontal", pad=.05, fraction=0.05)
plt.title('Flux Q: ' + str(times[it])[:13])

# 6 箭头绘制水汽通量
sk = 3 # skip grids
vc = ax.quiver(
    to_np(lons[::sk,::sk]), 
    to_np(lats[::sk,::sk]),
    # to_np(qu[::sk,::sk]), 
    # to_np(qv[::sk,::sk]), 
    to_np(qu_masked[::sk,::sk]), 
    to_np(qv_masked[::sk,::sk]), 
    width = 0.003, # #箭杆箭身宽度
    scale = 1.0, #  # 箭杆长度,参数scale越小箭头越长
    color = 'black',
    transform=ccrs.PlateCarree(), 
   # zorder=3
              )

# 箭头的标尺
ax.quiverkey(vc, 
             X=0.7, Y=0.9, #位置 
             U=0.04,  #参考箭头的长度对应的水汽通量大小
             label = r'0.04 kg m-2 s-1', 
             labelpos = 'E', # 参考箭头指向的方向
             color = 'b', #箭头颜色
             labelcolor = 'k', #label颜色
             coordinates='figure',#
             fontproperties={'size': 15}
            )

# 7 网格刻度线
# must call draw in order to get the axis boundary used to add ticks:
fig.canvas.draw()
#网格线和经纬度
lon_max = int(np.max(lons))
lon_min = int(np.min(lons))
lat_max = int(np.max(lats))
lat_min = int(np.min(lats))

# Define gridline locations and draw the lines using cartopy's built-in gridliner:
xticks = list(np.arange(lon_min-2, lon_max+2, 4.)) #后续函数需要列表
yticks = list(np.arange(lat_min-2, lat_max+2, 3.))
ax.gridlines(xlocs=xticks, ylocs=yticks)

# Label the end-points of the gridlines using the custom tick makers:
ax.xaxis.set_major_formatter(LONGITUDE_FORMATTER) 
ax.yaxis.set_major_formatter(LATITUDE_FORMATTER)
# xticks and yticks only is list
lambert_xticks(ax, xticks)  
lambert_yticks(ax, yticks)

plt.savefig('wrf_flux_q_700hPa.png')

在这里插入图片描述

  • 5
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
绘制500hPa夏季水汽场气候平均需要用到Python中的气象科学可视化库,比如MetPy、Basemap或Cartopy。下面以使用MetPy库为例: 首先,需要安装MetPy库,可以通过以下命令进行安装: ```python !pip install metpy ``` 然后,导入需要的库和数据: ```python import numpy as np import pandas as pd import xarray as xr import metpy.calc as mpcalc from metpy.units import units import cartopy.crs as ccrs import cartopy.feature as cfeature import matplotlib.pyplot as plt # 读取数据文件 data = xr.open_dataset('data.nc') ``` 接下来,选择夏季时间范围和500hPa层数据,并计算水汽场的气候平均值: ```python # 选择夏季时间范围 summer_data = data.sel(time=data['time.season'] == 'JJA') # 选择500hPa层数据 h500_data = summer_data['h500'] # 计算水汽场的气候平均值 q_avg = np.mean(h500_data['q'], axis=0) ``` 最后,使用Cartopy库绘制地,并使用MetPy库绘制等值线: ```python # 创建地投影 proj = ccrs.PlateCarree() # 创建形和轴对象 fig, ax = plt.subplots(figsize=(10, 6), subplot_kw=dict(projection=proj)) # 添加地特征 ax.add_feature(cfeature.COASTLINE) ax.add_feature(cfeature.BORDERS) ax.add_feature(cfeature.STATES) # 绘制等值线 levels = np.arange(0, 25, 2) contour = ax.contourf(q_avg.lon, q_avg.lat, q_avg, levels=levels, cmap='rainbow') # 添加色标 cbar = plt.colorbar(contour, orientation='horizontal', pad=0.05, shrink=0.8) cbar.set_label('500hPa夏季水汽场气候平均值') # 设置标题 ax.set_title('500hPa夏季水汽场气候平均') # 显示形 plt.show() ``` 这样就可以绘制出500hPa夏季水汽场气候平均了。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值