我搜索过高低,但找不到这个问题的另一个答案。
我正在尝试将Met Office在南极半岛的统一模型的输出可视化。此刻,我有一个纵向横截面,潜在温度绘制为填充轮廓。我想在此基础上绘制风矢量,因此它们看起来更像:
我试图调整中给出的lat / lon坐标的例子 matplotlib的例子(例如quiver_demo),但没有运气(可能是因为我做错了,这是非常明显的)。
我有风的u,v和w分量(虽然我不需要v因为我在一条纬度线上切了一条)。
我目前正在使用一个名为iris(v1.7)的模块,它允许我处理我拥有的文件(例如,从旋转的杆投影转换并将纬度/经度转换为合理的坐标),所以请原谅我的代码中不熟悉的行。
我的代码如下:
import iris
import iris.plot as iplt
import matplotlib.pyplot as plt
import numpy as np
# Load variables from file
fname = ['/pathname/filename.pp']
theta= iris.load_cube(fname,'air_potential_temperature') #all data are 3D 'cubes' of dimensions [x,y,z] = [40,800,800]
U = iris.load_cube(fname, 'eastward_wind')
W = iris.load_cube(fname, 'upward_air_velocity')
lev_ht = theta.coord('level_height').points # for extracting z coordinate only - shape = (40,)
##SPATIAL COORDINATES
## rotate projection to account for rotated pole
var_name = theta
pole_lon = 298.5
pole_lat = 22.99
rotated_lat = var_name.coord('grid_latitude').points
rotated_lon = var_name.coord('grid_longitude').points
real_lon, real_lat = iris.analysis.cartography.unrotate_pole(rotated_lon,rotated_lat, pole_lon, pole_lat)
#define function to find index of gridbox in question
def find_gridbox(x,y):
global lon_index, lat_index
lat_index = np.argmin((real_lat-x)**2) #take whole array and subtract lat you want from each point, then find the smallest difference
lon_index = np.argmin((real_lon-y)**2)
return lon_index, lat_index
lon_index, lat_index = find_gridbox(-66.58333, -63.166667) # coordinates of Cabinet Inlet
#add unrotated lats/lons into variables
lat = var_name.coord('grid_latitude')
lon = var_name.coord('grid_longitude')
New_lat = iris.coords.DimCoord(real_lat, standard_name='latitude',long_name="grid_latitude",var_name="lat",units=lat.units)
New_lon= iris.coords.DimCoord(real_lon, standard_name='longitude',long_name="grid_longitude",var_name="lon",units=lon.units)
var_names = [theta, U, W]
for var in var_names:
var.remove_coord('grid_latitude')
var.add_dim_coord(New_lat, data_dim=1)
var.remove_coord('grid_longitude')
var.add_dim_coord(New_lon, data_dim=2)
# Create 2D subsets of data for plotting (longitudinal transects)
theta_slice = theta[:,lat_index,:]
U_slice = U[:,lat_index,:]
W_slice = W[:,lat_index,:]
# Create 2d arrays of lon/alt for gridding
x, y = np.meshgrid(lon.points, lev_ht)
u = U_slice
w = W_slice
# plot
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.set_axis_bgcolor('k') #set orography to be black
ax3 = iplt.contourf(theta_slice, cmap=plt.cm.bwr)
ax1.set_ylim(0,5500)
barbs = plt.quiver(x, y, u, w)
ax3.set_clim(vmin=250, vmax=320)
ax1.set_title('25 May 00:00 UTC', fontsize=28)
ax1.set_ylabel('Height (m)', fontsize=22)
ax1.set_xlabel('Longitude', fontsize=22)
ax1.tick_params(axis='both', which='major', labelsize=18)
plt.colorbar(ax3)
plt.show()
然而,当绘制矢量时,它们显示为线条:
我不确定这是不是因为它们太融合在一起(当我改变线宽和比例等线属性时,向量变得相当疯狂)或因为我的输入不正确。 u和w变量分别是包含风的西风和向上分量的二维阵列(长子/高度),因此应该包含这些方向上的移动幅度。
我不能发布实际文件的道歉:它们是特定的Met Office .pp格式(当然),但与netCDF具有相似的品质。我试图在代码注释中描述数据维度。
答案 0 :(得分:0)
希望您一切顺利,并能够快速解决问题。
以下是一些代码以及生成的图像:
import numpy as np
from matplotlib import pyplot
import matplotlib.pyplot as plt
from matplotlib.cm import get_cmap
from matplotlib.colors import from_levels_and_colors
from cartopy import crs
from cartopy.feature import NaturalEarthFeature, COLORS
from netCDF4 import Dataset
from wrf import (getvar, to_np, get_cartopy, latlon_coords, vertcross,
cartopy_xlim, cartopy_ylim, interpline, CoordPair)
wrf_file = Dataset("C:/Users/meteorologia.gmmc/Documents/WRF - Rodada Exemplo/wrfout_exemplo.nc")
# Define the cross section start and end points
cross_start = CoordPair(lat=-8.5, lon=-42)
cross_end = CoordPair(lat=-8.5, lon=-30)
# Get the WRF variables
ht = getvar(wrf_file, "z", timeidx=8)
ht = ht[0:20,:,:]
ter = getvar(wrf_file, "ter", timeidx=8)
w = getvar(wrf_file, "wa", timeidx=8)
w = w[0:20,:,:]
u = getvar(wrf_file, "ua", timeidx=8)
u = u[0:20,:,:]
max_dbz = getvar(wrf_file, "mdbz", timeidx=8)
W = 10**(w/10.) # Use linear Z for interpolation
w_cross = vertcross(W, ht, wrfin=wrf_file,
start_point=cross_start,
end_point=cross_end,
latlon=True, meta=True)
U = 10**(u/10.) # Use linear Z for interpolation
u_cross = vertcross(U, ht, wrfin=wrf_file,
start_point=cross_start,
end_point=cross_end,
latlon=True, meta=True)
# Convert back to dBz after interpolation
w_cross = 10.0 * np.log10(w_cross)
u_cross = 10.0 * np.log10(u_cross)
# Add back the attributes that xarray dropped from the operations above
w_cross.attrs.update(w_cross.attrs)
w_cross.attrs["description"] = "destaggered w-wind component"
w_cross.attrs["units"] = "m s-1"
# Add back the attributes that xarray dropped from the operations above
u_cross.attrs.update(u_cross.attrs)
u_cross.attrs["description"] = "destaggered u-wind component"
u_cross.attrs["units"] = "m s-1"
# To remove the slight gap between the dbz contours and terrain due to the
# contouring of gridded data, a new vertical grid spacing, and model grid
# staggering, fill in the lower grid cells with the first non-missing value
# for each column.
# Make a copy of the z cross data. Let's use regular numpy arrays for this.
w_cross_filled = np.ma.copy(to_np(w_cross))
u_cross_filled = np.ma.copy(to_np(u_cross))
# For each cross section column, find the first index with non-missing
# values and copy these to the missing elements below.
for i in range(w_cross_filled.shape[-1]):
column_vals = w_cross_filled[:,i]
# Let's find the lowest index that isn't filled. The nonzero function
# finds all unmasked values greater than 0. Since 0 is a valid value
# for dBZ, let's change that threshold to be -200 dBZ instead.
first_idx = int(np.transpose((column_vals > -200).nonzero())[0])
w_cross_filled[0:first_idx, i] = w_cross_filled[first_idx, i]
# For each cross section column, find the first index with non-missing
# values and copy these to the missing elements below.
for i in range(u_cross_filled.shape[-1]):
column_vals = u_cross_filled[:,i]
# Let's find the lowest index that isn't filled. The nonzero function
# finds all unmasked values greater than 0. Since 0 is a valid value
# for dBZ, let's change that threshold to be -200 dBZ instead.
first_idx = int(np.transpose((column_vals > -200).nonzero())[0])
u_cross_filled[0:first_idx, i] = u_cross_filled[first_idx, i]
# Get the terrain heights along the cross section line
ter_line = interpline(ter, wrfin=wrf_file, start_point=cross_start,
end_point=cross_end)
# Get the lat/lon points
lats, lons = latlon_coords(w)
# Get the cartopy projection object
cart_proj = get_cartopy(w)
# Create the figure
fig = pyplot.figure(figsize=(8,6))
ax_cross = pyplot.axes()
# Make the cross section plot for dbz
w_levels = np.arange(-4E-1, +4E-1, 5E-2)
xs = np.arange(0, w_cross.shape[-1], 1)
ys = to_np(w_cross.coords["vertical"])
w_contours = ax_cross.contourf(xs,
ys,
to_np(w_cross_filled),
levels=w_levels,
cmap='seismic',
extend="both")
# Add the color bar
cbar = fig.colorbar(w_contours, ax=ax_cross)
cbar.ax.tick_params(labelsize=12)
cbar.set_label('Vertical Velocity (m.s)', rotation=-270, fontsize=12)
# Fill in the mountain area
ht_fill = ax_cross.fill_between(xs, 0, to_np(ter_line),
facecolor="black")
# Tentativa do quiver
ax_cross.quiver(xs[::5], ys[::5],
to_np(u_cross_filled[::5, ::5]), to_np(w_cross_filled[::5, ::5]*100))
# Set the x-ticks to use latitude and longitude labels
coord_pairs = to_np(u_cross.coords["xy_loc"])
x_ticks = np.arange(coord_pairs.shape[0])
x_labels = [pair.latlon_str() for pair in to_np(coord_pairs)]
# Set the desired number of x ticks below
num_ticks = 5
thin = int((len(x_ticks) / num_ticks) + .5)
ax_cross.set_xticks(x_ticks[::thin])
ax_cross.set_xticklabels(x_labels[::thin], rotation=90, fontsize=8)
# Set the x-axis and y-axis labels
ax_cross.set_xlabel("Latitude, Longitude", fontsize=12)
ax_cross.set_ylabel("Altura (m)", fontsize=12)
# Add a title
ax_cross.set_title("Ilha com vetores zonais", {"fontsize" : 14})
pyplot.show()
fig.savefig('WV.png', dpi=None, facecolor='w', edgecolor='w',
orientation='portrait', papertype=None, format=None,
transparent=False, bbox_inches=None, pad_inches=0.1,
frameon=None, metadata=None)