国立研究開発法人防災科学技術研究所 水・土砂防災研究部門
国立研究開発法人防災科学技術研究所 水・土砂防災研究部門
トップ 一覧 検索 ヘルプ RSS ログイン

Pytyon(描画関係メモ)_version1

4次元データ(T,Z,Y,X)の時間と高度を指定し、2次元断面(スカラー)を描画するためのpython (ver1)

  version1: anaconda-2020.11 (CENTOS8環境)

お手軽版(colorscaleの調整ができないが、とにかく描画ができる)
main_ver1.py(51)

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')

ver1.png