4次元データ(T,Z,Y,X)の時間と高度を指定し、2次元断面(スカラー)を描画するためのpython (ver1)
version1: anaconda-2020.11 (CENTOS8環境)
お手軽版(colorscaleの調整ができないが、とにかく描画ができる)
main_ver1.py(152)
import sys
import os
import datetime
import inspect
import re
import argparse
import numpy as np
import xarray as xr
import cartopy.crs as ccrs
import matplotlib as mpl
import matplotlib.pyplot as plt
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
import cartopy.feature as cfeature
def main():
parser = argparse.ArgumentParser(description='draw netcdf')
parser.add_argument('arg1',help='input file setting')
parser.add_argument('arg2',help='variable setting')
parser.add_argument('-t','--timenum',help='time slide from initial time')
parser.add_argument('-T','--TIME',help='YYYY-M2-D2_H2:M2:S2(UTC)')
parser.add_argument('-z','--levelnum',help='level number to be drawn')
parser.add_argument('-Z','--LEV',help='level (m) to be drawn')
parser.add_argument('-O','--OUTFIG',help='output file name')
args = parser.parse_args()
#print(args.arg1)
#print(args.arg2)
#print(args.timenum)
#print(args.TIME)
#print(args.levelnum)
#print(args.LEV)
#print(args.OUTFIG)
infile = args.arg1
if not os.path.exists(infile):
print ("infile does not exist \n",infile)
exit(1)
#open NETCDF as XARRAY
data = xr.open_dataset(infile)
# If you need, you can check all CLASS in XARRAY
#for aaa in inspect.getmembers(data):
# print(aaa)
# get variable name
varname = args.arg2
# check if the variable is included in NETCDF
if not varname in data.variables:
print("variable ", varname, " is not found")
exit(1)
# draw region setting
slon = 128.2
elon = 131.8
slat = 30.0
elat = 34.0
#############################################################
# check the dimension name for TIME
#############################################################
dimnameT = "NOTDEFINED"
for ddd in data.dims:
if ddd == "TIME":
dimnameT = "TIME"
elif ddd == "time":
dimnameT = "time"
elif ddd == "Time":
dimnameT = "Time"
if dimnameT == "NOTDEFINED":
print("TIME DIMENSION NAME is not found")
exit(1)
if args.timenum is None and args.TIME is None:
print("chose your time from following list \n")
for i, a in enumerate(data[dimnameT].values):
print(i,a)
print("enter TNUM:")
t = int(input())
TTT = data[dimnameT].values[t]
timesel={dimnameT : t}
V3D = data[varname].isel(timesel)
elif args.timenum is None:
print("YYYY-MM-DD_HH:MN:SC format \n")
ptn = r"\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d"
if not re.match(ptn,args.TIME):
print("TIME INPUT FORMAT WRONG")
print("Y4-M2-D2TH2:M2:S2")
print("ex 2020-07-06T03:00:00")
exit(1)
TTT = args.TIME
timesel={dimnameT : args.TIME}
V3D = data[varname].sel(timesel)
else:
t = int(args.timenum)
timesel={dimnameT : t}
TTT = data[dimnameT].values[t]
V3D = data[varname].isel(timesel)
#############################################################
# check the dimension name for Z
#############################################################
dimnameZ = "NOTDEFINED"
for ddd in data.dims:
if ddd == "LEV":
dimnameZ = "LEV"
elif ddd == "ALT":
dimnameZ = "ALT"
if dimnameZ == "NOTDEFINED":
print("Z DIMENSION NAME is not found")
exit(1)
if args.levelnum is None and args.LEV is None:
print("chose your lev from following list \n")
for k, a in enumerate(data[dimnameZ].values):
print(k,a)
print("enter ZNUM:")
k = int(input())
ZZZ = data[dimnameZ].values[k]
levsel={dimnameZ : k}
V2D = V3D.isel(levsel)
elif args.levelnum is None:
ZZZ = args.LEV
levsel={dimnameZ : ZZZ}
V2D = V3D.sel(levsel)
else:
k = int(args.levelnum)
levsel={dimnameZ : k}
ZZZ = data[dimnameZ].values[k]
V2D = V3D.isel(levsel)
# get max-min in 2dim array maxV = max(list(map(lambda x: max(x), V2D.values))) minV = min(list(map(lambda x: min(x), V2D.values))) diff = (maxV-minV)/5 diff = np.round(diff,1) maxV = maxV*1.01 minV = minV - abs(minV)*0.01 maxV = np.round(maxV,1) minV = np.round(minV,1) print(maxV,minV,diff) clevels =np.arange(minV,maxV,diff)
############################################################# # DRAW by CARTOPY ############################################################# # configure for whole figure domain xFsiz = (elon -slon) / 0.0105 yFsiz = (elat -slat) / 0.009 Fxsiz = 8 Fysiz = Fxsiz * (yFsiz/xFsiz) fig = plt.figure(figsize=(Fxsiz,Fysiz))
# configure for a single figure in the whole figure domain
ax = fig.add_subplot(111,projection=
ccrs.PlateCarree())
# draw two-dimensional distribution
V2D.plot.contourf(ax=ax,transform=ccrs.PlateCarree(),
levels=clevels,cmap='rainbow',add_colorbar=True,
extend='neither')
# set drawing lon.lat
ax.set_extent([slon,elon,slat,elat],crs=ccrs.PlateCarree())
# setting for xlabel and ylabel dlon = int(((elon-slon)/4.0)*10.0)/10.0 dlat = int(((elat-slat)/4.0)*10.0)/10.0 xticks0 = np.arange(slon,elon+0.01,dlon) xticks = np.round(xticks0,1) yticks0 = np.arange(slat,elat+0.01,dlat) yticks = np.round(yticks0,1) ax.set_xticks(xticks,crs=ccrs.PlateCarree()) ax.set_yticks(yticks,crs=ccrs.PlateCarree()) lon_formatter = LongitudeFormatter(zero_direction_label=True) lat_formatter = LatitudeFormatter() ax.xaxis.set_major_formatter(lon_formatter) ax.yaxis.set_major_formatter(lat_formatter)
# Boundary for prefecture
countries_10m = cfeature.NaturalEarthFeature('cultural',
'admin_1_states_provinces_lines',
'10m', edgecolor='black',facecolor='none')
# draw coastline
ax.coastlines()
# draw boundary of prefecture
ax.add_feature(countries_10m, linestyle=':', linewidth=0.2, alpha=0.8)
if args.OUTFIG is not None:
plt.savefig(args.OUTFIG)
# draw figure
plt.show()
if __name__ == "__main__":
main()
使い方
python main_ver1.py -h
で必要な引数などが表示される。
python main_ver1.py sample.nc U python main_ver1.py sample.nc U -t 0 -z 2 -O hoge.ps
概要
xarray でnetcdfを開き、時刻リストや高度リストが表示されるのでユーザーが選択し、
ある変数の2次元平面のデータの切り出しをxarrayで行う。描画もxarrayのインスタンスであるV2Dに対して、
xarrayのplot.contourfを使用。大変お手軽。add_coloarba=Trueにすると、自動的にカラーバーを表示。
さらに図の説明なども全部自動で書いてくれる。colorscaleさえ調整できれば完璧なのに。。。
作業用としてはこれでいいかも。図の縦横比ができるだけ1となるようにするか、縦長の図をつくるように
心がけることが大事。
V2D.plot.contourf(ax=ax,transform=ccrs.PlateCarree(),
levels=clevels,cmap='rainbow',add_colorbar=False,
extend='neither')
