forked from 3rdparty/wrf-python
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
291 lines
10 KiB
291 lines
10 KiB
#!/usr/bin/env python |
|
|
|
import traceback |
|
import sys |
|
import sqlite3 |
|
from datetime import datetime as dt |
|
|
|
import numpy as n |
|
import matplotlib |
|
matplotlib.use('agg') |
|
import matplotlib.pyplot as plt |
|
|
|
#from wrf.core import Constants |
|
#from wrf.var.temp import calc_temp |
|
#from wrf.plot.matplotlib.defaults import (get_basemap, get_default_map_opts, |
|
# get_null_opts) |
|
|
|
#from wrf.plot.matplotlib.helper import (add_plot_info_text, plot_map, |
|
# plot_contourf) |
|
|
|
#__all__ = ["plot_2d"] |
|
|
|
|
|
|
|
|
|
def get_basemap(wrfnc): |
|
#TODO: handle multiple projections |
|
lat2d = wrfnc.variables["XLAT"][0,:,:] |
|
lon2d = wrfnc.variables["XLONG"][0,:,:] |
|
|
|
ny = len(wrfnc.dimensions["south_north"]) |
|
nx = len(wrfnc.dimensions["west_east"]) |
|
nz = len(wrfnc.dimensions["bottom_top"]) |
|
|
|
dx = wrfnc.DX |
|
dy = wrfnc.DY |
|
center_lat = wrfnc.CEN_LAT |
|
center_lon = wrfnc.CEN_LON |
|
true_lat1 = wrfnc.TRUELAT1 |
|
true_lat2 = wrfnc.TRUELAT2 |
|
|
|
basemap = Basemap(projection="lcc", |
|
lat_0=center_lat, |
|
lon_0=center_lon, |
|
lat_1=true_lat1, |
|
lat_2=true_lat2, |
|
llcrnrlon=lon2d[0,0], |
|
llcrnrlat=lat2d[0,0], |
|
urcrnrlon=lon2d[ny-1, nx-1], |
|
urcrnrlat=lat2d[ny-1, nx-1], |
|
resolution='i') |
|
|
|
return basemap |
|
|
|
def get_default_map_opts(): |
|
landcolor = (204/255.0, 204/255.0, 153/255.0) |
|
oceancolor = (102/255.0, 204/255.0, 255/255.0) |
|
return MapOptions( |
|
coastargs = {"linewidth":1.0, "linestyle":'solid', "color":'k'}, |
|
countryargs = {"linewidth":0.5, "linestyle":'solid', "color":'k'}, |
|
stateargs = {"linewidth":0.5, "linestyle":'solid', "color":'k'}, |
|
mapboundaryargs = {"color":'k', "linewidth":1.0, |
|
"fill_color":oceancolor}, |
|
continentfillargs = {"color":landcolor, "lake_color":oceancolor, |
|
"zorder":0}) |
|
|
|
|
|
def get_null_opts(): |
|
return FilledContourOptions(fcontourargs={}, |
|
colorbarargs={"location" : "bottom", |
|
"size" : "5%", "pad" : "2%", |
|
"extend" : "both"}) |
|
|
|
def add_plot_info_text(ax, |
|
top_left_text="", top_right_text="", |
|
bot_left_text="", bot_right_text=""): |
|
|
|
plt.ioff() |
|
if top_left_text != "": |
|
plt.text(0.005,.995,top_left_text, |
|
bbox=dict(facecolor="white"), |
|
horizontalalignment="left", |
|
verticalalignment="top", |
|
transform = ax.transAxes, |
|
fontsize=10) |
|
|
|
if top_right_text != "": |
|
plt.text(.995,.995,top_right_text, |
|
bbox=dict(facecolor="white"), |
|
horizontalalignment="right", |
|
verticalalignment="top", |
|
transform = ax.transAxes, |
|
fontsize=10) |
|
|
|
if bot_left_text != "": |
|
plt.text(0.005,0.005,bot_left_text, |
|
bbox=dict(facecolor="white"), |
|
horizontalalignment="left", |
|
verticalalignment="bottom", |
|
transform = ax.transAxes, |
|
fontsize=10) |
|
|
|
if bot_right_text != "": |
|
plt.text(.995,0.005,bot_right_text, |
|
bbox=dict(facecolor="white"), |
|
horizontalalignment="right", |
|
verticalalignment="bottom", |
|
transform = ax.transAxes, |
|
fontsize=10) |
|
|
|
def plot_map(basemap, mapoptions): |
|
plt.ioff() |
|
if mapoptions.mapboundaryargs is not None: |
|
basemap.drawmapboundary(**mapoptions.mapboundaryargs) |
|
|
|
if mapoptions.continentfillargs is not None: |
|
basemap.fillcontinents(**mapoptions.continentfillargs) |
|
|
|
if mapoptions.coastargs is not None: |
|
basemap.drawcoastlines(**mapoptions.coastargs) |
|
|
|
if mapoptions.countryargs is not None: |
|
basemap.drawcountries(**mapoptions.countryargs) |
|
|
|
if mapoptions.stateargs is not None: |
|
basemap.drawstates(**mapoptions.stateargs) |
|
|
|
if mapoptions.countyargs is not None: |
|
basemap.drawcounties(**mapoptions.countyargs) |
|
|
|
if mapoptions.riverargs is not None: |
|
basemap.drawrivers(**mapoptions.riverargs) |
|
|
|
def plot_contourf(x,y,data,basemap, contourfoptions): |
|
plt.ioff() |
|
cs1 = None |
|
if contourfoptions.contourargs is not None: |
|
cs1 = basemap.contour(x,y,data,**contourfoptions.contourargs) |
|
|
|
cs2 = None |
|
if contourfoptions.fcontourargs is not None: |
|
cs2 = basemap.contourf(x,y,data,**contourfoptions.fcontourargs) |
|
|
|
cb = None |
|
if contourfoptions.colorbarargs is not None: |
|
cb = basemap.colorbar(cs2, **contourfoptions.colorbarargs) |
|
|
|
if contourfoptions.labelargs is not None: |
|
plt.clabel(cs1, **contourfoptions.labelargs) |
|
|
|
return cs1, cs2, cb |
|
|
|
def get_null_opts(): |
|
return FilledContourOptions(fcontourargs={}, |
|
colorbarargs={"location" : "bottom", |
|
"size" : "5%", "pad" : "2%", |
|
"extend" : "both"}) |
|
|
|
class MapOptions(object): |
|
def __init__(self, |
|
coastargs = None, |
|
countyargs = None, |
|
countryargs = None, |
|
riverargs = None, |
|
stateargs = None, |
|
mapboundaryargs = None, |
|
continentfillargs = None): |
|
self.coastargs = coastargs |
|
self.countyargs = countyargs |
|
self.countryargs = countryargs |
|
self.riverargs = riverargs |
|
self.stateargs = stateargs |
|
self.mapboundaryargs = mapboundaryargs |
|
self.continentfillargs = continentfillargs |
|
|
|
def plot_2d(wrfnc, varname=None, outfile=None, title=None, |
|
map_opts=None, plot_opts=None, |
|
top_left_info="", top_right_info="", |
|
bot_left_info="", bot_right_info="", |
|
wks_type="png", var=None, |
|
time_in=0): |
|
|
|
try: |
|
plt.ioff() |
|
print "generating %s.%s" % (outfile, wks_type) |
|
if var is not None: |
|
field = var |
|
elif varname is not None: |
|
field = wrfnc.variables[varname][time_in,:,:] |
|
|
|
lat2d = wrfnc.variables["XLAT"][time_in,:,:] |
|
lon2d = wrfnc.variables["XLONG"][time_in,:,:] |
|
times = wrfnc.variables["Times"][time_in,:] |
|
model_time = "".join(times) |
|
start_date = dt.strptime(model_time, "%Y-%m-%d_%H:%M:%S") |
|
|
|
ny = len(wrfnc.dimensions["south_north"]) |
|
nx = len(wrfnc.dimensions["west_east"]) |
|
nz = len(wrfnc.dimensions["bottom_top"]) |
|
|
|
fig = plt.figure(figsize=(8,8), dpi=200) |
|
ax = fig.add_axes([0.1,0.1,0.8,0.8]) |
|
|
|
bm = get_basemap(wrfnc) |
|
if map_opts is None: |
|
map_opts = get_default_map_opts() |
|
if plot_opts is None: |
|
plot_opts = get_null_opts() |
|
|
|
x,y = bm(lon2d, lat2d) |
|
|
|
plot_map(bm,map_opts) |
|
|
|
plt.xticks(rotation=70) |
|
tplot = plot_contourf(x,y,field,bm,plot_opts) |
|
|
|
|
|
add_plot_info_text(ax, |
|
top_left_info, top_right_info, |
|
bot_left_info, bot_right_info) |
|
|
|
ax.set_title(title,fontdict={"fontsize" : 20}) |
|
|
|
plt.savefig("%s.%s" % (outfile, wks_type)) |
|
|
|
plt.clf() |
|
plt.close(fig) |
|
except: |
|
# print the stack trace since it will be lost when used in a |
|
# multiprocessing worker. |
|
print traceback.format_exc() |
|
raise |
|
finally: |
|
sys.stdout.flush() |
|
|
|
def main(): |
|
parser = argparse.ArgumentParser(description="Generate meteorological " |
|
"plots for a specific data file") |
|
parser.add_argument("-v", "--var", required=True, |
|
help="variable name") |
|
parser.add_argument("-f", "--filename", required=True, |
|
help="WRF file to plot") |
|
parser.add_argument("-o", "--outdir", default=".", required=False, |
|
help="output directory for images") |
|
parser.add_argument("-l", "--levels", required=False, type=float, |
|
nargs="+", |
|
default=None, |
|
help=("the start, end, and increment for contour levels" |
|
" as a list of items with spaces between them" |
|
"example: 1 10 2 ")) |
|
parser.add_argument("-c", "--customlevels", required=False, type=float, |
|
nargs="+", |
|
default=None, |
|
help=("a list of space delimited contour levels" |
|
"example: 1 2 3 4 5 19 28 200 ")) |
|
|
|
args = parser.parse_args() |
|
|
|
if not os.path.exists(args.filename): |
|
raise RuntimeError ("%s not found" % args.filename) |
|
|
|
if not os.path.exists(args.outdir): |
|
os.makedirs(args.outdir) |
|
|
|
basename = os.path.basename(args.filename) |
|
wrfnc = NetCDF(args.filename, mode='r') |
|
|
|
outfile = os.path.join(args.outdir, domain, args.var, "%s.%s" % (basename,args.var)) |
|
if not os.path.exists(os.path.dirname(outfile)): |
|
os.makedirs(os.path.dirname(outfile)) |
|
|
|
if args.levels is not None or args.customlevels is not None: |
|
plot_opts = get_null_opts() |
|
if args.levels is not None: |
|
if len(args.levels) < 2 or len(args.levels) > 3: |
|
raise RuntimeError("levels argument is invalid") |
|
plot_opts.fcontourargs["levels"] = [x for x in n.arange(args.levels[0], |
|
args.levels[1], |
|
args.levels[2])] |
|
plot_opts.fcontourargs["extend"] = "both" |
|
elif args.customlevels is not None: |
|
plot_opts.fcontourargs["levels"] = args.customlevels |
|
plot_opts.fcontourargs["extend"] = "both" |
|
else: |
|
plot_opts = None |
|
|
|
plot_2d(wrfnc, args.var, outfile, "%s"%args.var, |
|
plot_opts = plot_opts) |
|
|
|
if __name__ == "__main__": |
|
main() |