wrf模拟的domain图绘制
wrf模拟的区域绘制,domain图,利用python的cartopy库绘制模拟区域
参考Liang Chen的draw_wrf_domian.py这个代码, 出处python画wrf模式的模拟区域
创新点
区别于Liange代码的地方在于使用cartopy库,替换了basemap库, 方便在最新的python版本下使用。
初学cartopy,使用cartopy根据距离绘制图像是比较难想到的一点, 是在创建投影对象的那里设置的你敢信?
具体代码(使用cartopy)
"""
Author: Forxd
Time: 2021-3-17
Purpose: read in namelist.wps , draw wrf domain and plot some station
"""
import xarray as xr
import numpy as np
import salem
import cartopy.crs as ccrs
import cartopy.feature as cfeat
from cartopy.mpl.ticker import LongitudeFormatter,LatitudeFormatter
from cartopy.io.shapereader import Reader, natural_earth
import cartopy.feature as cf
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import geopandas
import cmaps
from matplotlib.path import Path
import matplotlib.patches as patches
def draw_screen_poly( lats, lons):
'''
lats: 纬度列表
lons: 经度列表
purpose: 画区域直线
'''
x, y = lons, lats
xy = list(zip(x,y))
print(xy)
poly = plt.Polygon( xy, edgecolor="blue",fc="none", lw=0.6, alpha=1)
plt.gca().add_patch(poly)
def create_map(info):
"""创建一个包含青藏高原区域的Lambert投影的底图
Returns:
ax: 坐标图对象
"""
## --创建画图空间
proj = ccrs.PlateCarree() # 创建坐标系
ref_lat = info['ref_lat']
ref_lon = info['ref_lon']
true_lat1 = info['true_lat1']
true_lat2 = info['true_lat2']
false_easting = (info['e_we'][0]-1)/2*info['dx']
false_northing = (info['e_sn'][0]-1)/2*info['dy']
# print(true_lat1)
proj_lambert = ccrs.LambertConformal(
central_longitude=ref_lon,
central_latitude=ref_lat,
standard_parallels=(true_lat1,true_lat2),
cutoff=-30,
false_easting=false_easting,
false_northing=false_northing,
)
## 创建坐标系
fig = plt.figure(figsize=(4, 4), dpi=500) # 创建页面
ax = fig.add_axes([0.1,0.1,0.8,0.8], projection=proj_lambert)
## 读取青藏高原地形文件
Tibet = cfeat.ShapelyFeature(
Reader('/home/fengxiang/Data/shp_tp/Tibet.shp').geometries(),
proj, edgecolor='k',
facecolor='none', alpha=0.9
)
## 将青藏高原地形文件加到地图中区
ax.add_feature(Tibet, linewidth=0.5, zorder=2)
## --设置网格属性, 不画默认的标签
gl=ax.gridlines(draw_labels=True,linestyle=":",linewidth=0.3 ,x_inline=False, y_inline=False,color='k')
## 关闭上面和右边的经纬度显示
gl.top_labels=False #关闭上部经纬标签
# gl.bottom_labels = False
# gl.left_labels = False
gl.right_labels=False
gl.xformatter = LONGITUDE_FORMATTER #使横坐标转化为经纬度格式
gl.yformatter = LATITUDE_FORMATTER
gl.xlocator=mticker.FixedLocator(np.arange(60,120,10))
gl.ylocator=mticker.FixedLocator(np.arange(10,60,10))
gl.xlabel_style={'size':4}#修改经纬度字体大小
gl.ylabel_style={'size':4}
ax.spines['geo'].set_linewidth(0.6)#调节边框粗细
# ax.set_extent([60, 120, 10, 60], crs=proj)
# ax.set_extent([0, 2237500*2, 0, 1987500*2], crs=proj_lambert)
ax.set_extent([0, false_easting*2, 0, false_northing*2], crs=proj_lambert)
print(false_northing)
print(false_easting)
return ax
def get_information(flnm):
"""根据namelist.wps文件,获取地图的基本信息
Args:
flnm ([type]): [description]
Returns:
[type]: [description]
"""
## getting namelist.wps domain information
name_dict={}
with open(flnm) as fr:
for line in fr:
if "=" in line: # 这里没有考虑注释的那些行吧, 不过wps一般也没人注释就是了
line=line.replace("=","").replace(",","")
name_dict.update({line.split()[0]: line.split()[1:]}) # 这个字典直接可以更新
dx = float(name_dict["dx"][0]) # 转换为公里
dy = float(name_dict["dy"][0])
max_dom = int(name_dict["max_dom"][0])
# print(max_dom)
parent_grid_ratio = list(map(int, name_dict["parent_grid_ratio"]))
i_parent_start = list(map(int, name_dict["i_parent_start"]))
j_parent_start = list(map(int, name_dict["j_parent_start"]))
e_sn = list(map(int, name_dict["e_sn"]))
e_we = list(map(int, name_dict["e_we"]))
ref_lat= float(name_dict["ref_lat"][0]) # 模式区域中心位置
ref_lon= float(name_dict["ref_lon"][0])
truelat1 = float(name_dict["truelat1"][0]) # 和投影相关的经纬度
truelat2 = float(name_dict["truelat2"][0])
cenlon= np.arange(max_dom)
cenlat=np.arange(max_dom)
cenlon_model=dx*(e_we[0]-1)/2.0 # 中心点偏离边界的距离
cenlat_model=dy*(e_sn[0]-1)/2.0
dict_return = {
"dx":dx,
"dy":dy,
"max_dom":max_dom,
"parent_grid_ratio":parent_grid_ratio,
"j_parent_start":j_parent_start,
"i_parent_start":i_parent_start,
"e_sn":e_sn,
"e_we":e_we,
'ref_lat':ref_lat,
'ref_lon':ref_lon,
'true_lat1':truelat1,
'true_lat2':truelat2,
'parent_grid_ratio':parent_grid_ratio,
}
return dict_return
def draw_d02(info):
"""绘制domain2
Args:
info ([type]): [description]
"""
max_dom = info['max_dom']
dx = info['dx']
dy = info['dy']
i_parent_start = info['i_parent_start']
j_parent_start = info['j_parent_start']
parent_grid_ratio= info['parent_grid_ratio']
e_we = info['e_we']
e_sn = info['e_sn']
if max_dom >= 2:
### domain 2
# 4 corners 找到四个顶点和距离相关的坐标
ll_lon = dx*(i_parent_start[1]-1)
ll_lat = dy*(j_parent_start[1]-1)
ur_lon = ll_lon + dx/parent_grid_ratio[1] * (e_we[1]-1)
ur_lat = ll_lat + dy/parent_grid_ratio[1] * (e_sn[1]-1)
lon = np.empty(4)
lat = np.empty(4)
lon[0],lat[0] = ll_lon, ll_lat # lower left (ll)
lon[1],lat[1] = ur_lon, ll_lat # lower right (lr)
lon[2],lat[2] = ur_lon, ur_lat # upper right (ur)
lon[3],lat[3] = ll_lon, ur_lat # upper left (ul)
draw_screen_poly(lat, lon) # 画多边型
## 标注d02
plt.text(lon[3]*1, lat[3]*1., "d02")
def draw_station():
station = {'TingRi':{'lat':28.6,'lon':87.0},
'NaQu':{'lat':31.4, 'lon':92.0},
'LaSa':{'lat':29.6, 'lon':91.1},
'TuoTuohe':{'lat':34.2, 'lon':92.4},
'GaiZe':{'lat':32.3, 'lon':84.0},
'ShenZha':{'lat':30.9, 'lon':88.7},
'ShiQuanhe':{'lat':32.4, 'lon':80.1},
'JinChuan':{'lat':31.29, 'lon':102.04},
'JinLong':{'lat':29.00, 'lon':101.50},
}
values = station.values()
station_name = list(station.keys())
print(type(station_name[0]))
# print(station_name[0])
x = []
y = []
for i in values:
y.append(float(i['lat']))
x.append(float(i['lon']))
## 标记出站点
ax.scatter(x,y,color='red',
transform=ccrs.PlateCarree(),
linewidth=0.1,s=10)
## 给站点加注释
for i in range(len(x)):
print(x[i])
plt.text(x[i]-2, y[i]+0.5, station_name[i],
transform=ccrs.PlateCarree(),
fontdict={'size':5,}
)
if __name__ == '__main__':
file_folder="./"
file_name="namelist.wps"
flnm=file_folder+file_name
info = get_information(flnm) # 获取namelist.wps文件信息
ax = create_map(info) # 在domain1区域内,添加地理信息,创建底图
draw_d02(info) # 绘制domain2区域
draw_station() # 将站点位置绘制到图上
plt.title('d01', loc='left')
plt.savefig("domain.png")
具体代码(使用basemap)
'''
File name: draw_wrf_domain.py
Author: Liang Chen
E-mail: chenliang@tea.ac.cn
Date created: 2016-12-22
Date last modified: 2021-3-3
##############################################################
Purpos:
this function reads in namelist.wps and plot the wrf domain
'''
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap, cm
from matplotlib.colors import LinearSegmentedColormap
import shapefile
from matplotlib.collections import LineCollection
import matplotlib.colors
import sys
import numpy as np
def draw_screen_poly( lats, lons):
'''
lats: 纬度列表
lons: 经度列表
purpose: 画区域直线
'''
x, y = lons, lats
xy = list(zip(x,y))
print(xy)
poly = plt.Polygon( xy, edgecolor="blue",fc="none", lw=2, alpha=1)
plt.gca().add_patch(poly)
sShapeFiles="/home/fengxiang/Data/shp_tp/"
shape_line=['Tibet.shp',]
## setting namelist.wps domain information
file_folder="./"
file_name="namelist.wps"
sfile=file_folder+file_name
name_dict={}
with open(sfile) as fr:
for line in fr:
if "=" in line: # 这里没有考虑注释的那些行吧, 不过wps一般也没人注释就是了
line=line.replace("=","").replace(",","")
name_dict.update({line.split()[0]: line.split()[1:]}) # 这个字典直接可以更新
dx = float(name_dict["dx"][0])
dy = float(name_dict["dy"][0])
max_dom = int(name_dict["max_dom"][0])
print(max_dom)
parent_grid_ratio = list(map(int, name_dict["parent_grid_ratio"]))
i_parent_start = list(map(int, name_dict["i_parent_start"]))
j_parent_start = list(map(int, name_dict["j_parent_start"]))
e_sn = list(map(int, name_dict["e_sn"]))
e_we = list(map(int, name_dict["e_we"]))
ref_lat= float(name_dict["ref_lat"][0]) # 模式区域中心位置
ref_lon= float(name_dict["ref_lon"][0])
truelat1 = float(name_dict["truelat1"][0]) # 和投影相关的经纬度
truelat2 = float(name_dict["truelat2"][0])
# # ## draw map
fig = plt.figure(figsize=(7,6)) # 设置画板大小
#Custom adjust of the subplots
plt.subplots_adjust(left=0.05,right=0.97,top=0.9,bottom=0.1) # 调整画布大小
ax = plt.subplot(111)
m = Basemap(resolution="l", projection="lcc", rsphere=(6370000.0, 6370000.0), lat_1=truelat1, lat_2=truelat2, lat_0=ref_lat, lon_0=ref_lon, width=dx*(e_we[0]-1), height=dy*(e_sn[0]-1))
# m.drawcoastlines()
#m.drawcountries(linewidth=2)
#m.drawcountries()
#m.fillcontinents()
#m.fillcontinents(color=(0.8,1,0.8))
#m.drawmapboundary()
#m.fillcontinents(lake_color="aqua")
#m.drawmapboundary(fill_color="aqua")
### 根据地形文件,画底图
ii=0 # 控制变量
for sr in shape_line:
# print(sr)
r = shapefile.Reader(sShapeFiles+sr) # 读地形文件
shapes = r.shapes()
records = r.records()
for record, shape in zip(records,shapes):
lons,lats = zip(*shape.points)
data = np.array(m(lons, lats)).T
if len(shape.parts) == 1:
segs = [data,]
else:
segs = []
for i in range(1,len(shape.parts)):
index = shape.parts[i-1]
index2 = shape.parts[i]
segs.append(data[index:index2])
segs.append(data[index2:])
lines = LineCollection(segs,antialiaseds=(1,))
# lines.set_facecolors(cm.jet(np.random.rand(1)))
if ii==0:
lines.set_edgecolors('black')
lines.set_linewidth(2)
else:
lines.set_edgecolors('k')
lines.set_linewidth(1)
ax.add_collection(lines)
ii=ii+1
## 画标签
m.drawparallels(np.arange(-90, 90, 10), labels = [1,0,0,0], fontsize=16,dashes=[1,1])
# m.drawmeridians(np.arange(-180, 180, 10), labels = [0,0,0,1], fontsize=16,dashes=[1,1])
print(ref_lat, ref_lon)
## plot center position 画中心点
cenlon= np.arange(max_dom); cenlat=np.arange(max_dom)
cenlon_model=dx*(e_we[0]-1)/2.0
cenlat_model=dy*(e_sn[0]-1)/2.0
cenlon[0], cenlat[0]=m(cenlon_model, cenlat_model, inverse=True)
## 画区域1的中点和标注
plt.plot(cenlon_model,cenlat_model, marker="o", color="gray")
plt.text(cenlon_model*0.8, cenlat_model*1.01, "({cenlat}, {cenlon})".format(cenlat=round(cenlat[0],2), cenlon=round(cenlon[0],2)))
#### draw nested domain rectangle
#### 区域2
#### 画多边形
lon=np.arange(4); lat=np.arange(4)
if max_dom >= 2:
### domain 2
# 4 corners
ll_lon = dx*(i_parent_start[1]-1)
ll_lat = dy*(j_parent_start[1]-1)
ur_lon = ll_lon + dx/parent_grid_ratio[1] * (e_we[1]-1)
ur_lat = ll_lat + dy/parent_grid_ratio[1] * (e_sn[1]-1)
## lower left (ll)
lon[0],lat[0] = ll_lon, ll_lat
## lower right (lr)
lon[1],lat[1] = ur_lon, ll_lat
## upper right (ur)
lon[2],lat[2] = ur_lon, ur_lat
## upper left (ul)
lon[3],lat[3] = ll_lon, ur_lat
print(lat)
print(lon)
draw_screen_poly(lat, lon) # 画多边型
## 标注d02
plt.text(lon[3]*1, lat[3]*1., "d02")
### 区域2画多边形中点
cenlon_model = ll_lon + (ur_lon-ll_lon)/2.0
cenlat_model = ll_lat + (ur_lat-ll_lat)/2.0
cenlon[1], cenlat[1]=m(cenlon_model, cenlat_model, inverse=True)
# plt.plot(cenlon_model, cenlat_model,marker="o") # 这个画的是区域2的中点
# plt.text(cenlon_model*0.8, cenlat_model*1.01, "({cenlat}, {cenlon})".format(cenlat=round(cenlat[1],2), cenlon=round(cenlon[1],2)))
if max_dom >= 3:
### domain 3
## 4 corners
ll_lon += dx/parent_grid_ratio[1]*(i_parent_start[2]-1)
ll_lat += dy/parent_grid_ratio[1]*(j_parent_start[2]-1)
ur_lon = ll_lon +dx/parent_grid_ratio[1]/parent_grid_ratio[2]*(e_we[2]-1)
ur_lat =ll_lat+ dy/parent_grid_ratio[1]/parent_grid_ratio[2]*(e_sn[2]-1)
## ll
lon[0],lat[0] = ll_lon, ll_lat
## lr
lon[1],lat[1] = ur_lon, ll_lat
## ur
lon[2],lat[2] = ur_lon, ur_lat
## ul
lon[3],lat[3] = ll_lon, ur_lat
draw_screen_poly(lat, lon)
plt.text(lon[0]-lon[0]/10,lat[0]-lat[0]/10,"({i}, {j})".format(i=i_parent_start[2], j=j_parent_start[2]))
#plt.plot(lon,lat,linestyle="",marker="o",ms=10)
cenlon_model = ll_lon + (ur_lon-ll_lon)/2.0
cenlat_model = ll_lat + (ur_lat-ll_lat)/2.0
# plt.plot(cenlon,cenlat,marker="o",ms=15)
#print m(cenlon, cenlat)cenlon, cenlat, ll_lon, ll_lat, ur_lon, ur_lat
#print m(cenlon, cenlat,inverse=True)
cenlon[2], cenlat[2]=m(cenlon_model, cenlat_model, inverse=True)
if max_dom >= 4:
### domain 3
## 4 corners
ll_lon += dx/parent_grid_ratio[1]/parent_grid_ratio[2]*(i_parent_start[3]-1)
ll_lat += dy/parent_grid_ratio[1]/parent_grid_ratio[2]*(j_parent_start[3]-1)
ur_lon = ll_lon +dx/parent_grid_ratio[1]/parent_grid_ratio[2]/parent_grid_ratio[3]*(e_we[3]-1)
ur_lat =ll_lat+ dy/parent_grid_ratio[1]/parent_grid_ratio[2]/parent_grid_ratio[3]*(e_sn[3]-1)
## ll
lon[0],lat[0] = ll_lon, ll_lat
## lr
lon[1],lat[1] = ur_lon, ll_lat
## ur
lon[2],lat[2] = ur_lon, ur_lat
## ul
lon[3],lat[3] = ll_lon, ur_lat
draw_screen_poly(lat, lon)
#plt.plot(lon,lat,linestyle="",marker="o",ms=10)
cenlon_model = ll_lon + (ur_lon-ll_lon)/2.0
cenlat_model = ll_lat + (ur_lat-ll_lat)/2.0
# plt.plot(cenlon,cenlat,marker="o",ms=15)
#print m(cenlon, cenlat)cenlon, cenlat, ll_lon, ll_lat, ur_lon, ur_lat
#print m(cenlon, cenlat,inverse=True)
cenlon[3], cenlat[3]=m(cenlon_model, cenlat_model, inverse=True)
## 标注站点
plt.plot(cenlon_model, cenlat_model,marker="o") # 这个画的是区域2的中点
print(cenlon_model/25000, cenlat_model/25000)
# plt.text(cenlon_model*0.8, cenlat_model*1.01, "({cenlat}, {cenlon})".format(cenlat=round(cenlat[1],2), cenlon=round(cenlon[1],2)))
cenlon_model=dx*(e_we[0]-1)/2.0
print(dx)
print(dy)
Tingri={'lat':28.6,'lon':87.0,'name':'Tingri'}
plt.plot(Tingri['lon']*25000, Tingri['lat']*25000,marker="o")
# plt.text(Tingri['lon']*0.8, Tingri['lat']*1.01, "({cenlat}, {cenlon})".format(cenlat=round(cenlat[1],2), cenlon=round(cenlon[1],2)))
plt.savefig("tttt.png")
wrf模拟的domain图绘制的更多相关文章
- 矢量图绘制工具Svg-edit调整画布的大小
矢量图绘制工具Svg-edit调整画布的大小 ------------------------------ ------------------------
- Matlab 语谱图(时频图)绘制与分析
Matlab 语谱图(时频图)绘制与分析 语谱图:先将语音信号作傅里叶变换,然后以横轴为时间,纵轴为频率,用颜色表示幅值即可绘制出语谱图.在一幅图中表示信号的频率.幅度随时间的变化,故也称" ...
- Matlab绘图基础——利用axes(坐标系图形对象)绘制重叠图像 及 一图多轴(一幅图绘制多个坐标轴)
描述 axes在当前窗口中创建一个包含默认属性坐标系 axes('PropertyName',propertyvalue,...)创建坐标系时,同时指定它的一些属性,没有指定的使用DefaultAxe ...
- matplotlib点线 坐标刻度 3D图绘制(六)
plot语句中支持除X,Y以外的参数,以字符串形式存在,来控制颜色.线型.点型等要素,语法形式为: plt.plot(X, Y, 'format', ...) 1 点和线的样式 颜色 参数color或 ...
- UML类图绘制
UML图简介 含义:UML-Unified Modeling Language 统一建模语言,又称标准建模语言.是用来对软件密集系统进行可视化建模的一种语言 主要模型: 功能模型:从用户的角度展示系统 ...
- D3力布图绘制--节点自己连自己的实现
案例分析 先看下实现的效果图 实现方法 本篇是在之前写的博文 D3力布图绘制--节点间的多条关系连接线的方法 基础上加修改的,这里放上修改的代码,其他的一样 // DATA var nodes = [ ...
- D3力布图绘制--节点跑掉,单曲线弯曲问题记录
D3力布图绘制中遇到的交互问题,频繁操作数据后,会出现节点跑掉和单曲线弯曲的问题 问题描述 在id指向都正常的情况下出现以下2种状况: 单曲线弯曲 节点跑掉 经排查,是数据重复导致的问题 线条也是一样 ...
- MATLAB之心形图绘制
一.静态心形图绘制 (1)效果展示 (2)静态心形原始代码 clc; clear all; ; % 均布三位坐标 x=-:; y=-:; z=-:; [x,y,z]=meshgrid(x,y,z); ...
- 面向对象的照妖镜——UML类图绘制指南
1.前言 感受 在刚接触软件开发工作的时候,每次接到新需求,在分析需求后的第一件事情,就是火急火燎的打开数据库(DBMS),开始进行数据表的创建工作.然而这种方式,总是会让我在编码过程中出现实体类设计 ...
随机推荐
- pikachu-反射性xss(get)
首先打开漏洞网页,发现输入的长度好像被限制了, 我们便F12查看源代码,发现长度被限制成了20,而且还是前端验证的,我们可以直接修改为100 在我们的输入框中,输入 <script>ale ...
- element-ui UI 组件库剖析
element-ui UI 组件库剖析 /* Automatically generated by './build/bin/build-entry.js' */ https://github.com ...
- es6 curry function
es6 curry function // vuex getters export const getAdsFilterConfig = (state) => (spreader) => ...
- WebIDE All In One
WebIDE All In One web IDE Visual Studio Code vscode Code editing Redefined. Free. Built on open sour ...
- 如何用 js 实现一个 bind 函数
如何用 js 实现一个 bind 函数 原理 实现方式 总结 refs https://developer.mozilla.org/en-US/docs/Web/JavaScript/Referenc ...
- Learn-JavaScript-with-MDN 系列文章: 01. var & let & const 对比
Learn-JavaScript-with-MDN 系列文章: 01. var & let & const 对比 var & let & const 区别 https: ...
- NGK每日快讯2021.1.29日NGK公链第87期官方快讯!
- BGV暴涨千倍,未来或将超越YFI领跑DeFi全场!
毫无疑问,YFI在2020年上半年以一己之力掀翻了DeFi市场的热潮.迄今为止,YFI的新鲜资讯从不缺席,最近也是频频登上各大知名媒体热搜.其币价远远超过比特币价格,也让资本市场注意到DeFi市场原来 ...
- Python算法_斐波那契数列(10)
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项.斐波那契数列的定义如下: F(0) = 0, F(1) = 1F(N) = F(N - 1) + F(N - 2), 其中 ...
- Vue(1)
一:概述 Vue是一套用于构建用户界面的渐进式JavaScript框架,与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用.Vue的核心库只关心视图层,不仅易于上手,还便于与第三方库或既有项目 ...