4 import os,sys,shutil,math
5 import matplotlib
as mpl
7 from mpl_toolkits.basemap
import Basemap, cm
9 import matplotlib.pyplot
as plt
14 '''Returns a Basemap object (NPS/SPS) focused in a region.
16 lon_w, lon_e, lat_s, lat_n -- Graphic limits in geographical coordinates.
17 W and S directions are negative.
18 **kwargs -- Aditional arguments for Basemap object.
21 lon_w,lon_e,lat_s,lat_n = bounds
22 lon_0 = lon_w + (lon_e - lon_w) / 2.
23 ref = lat_s
if abs(lat_s) > abs(lat_n)
else lat_n
24 lat_0 = math.copysign(90., ref)
25 proj =
'npstere' if lat_0 > 0
else 'spstere'
26 prj = Basemap(projection=proj, lon_0=lon_0, lat_0=lat_0,
27 boundinglat=0, resolution=
'c')
29 lons = [lon_w, lon_e, lon_w, lon_e, lon_0, lon_0]
30 lats = [lat_s, lat_s, lat_n, lat_n, lat_s, lat_n]
31 x, y = prj(lons, lats)
32 ll_lon, ll_lat = prj(min(x), min(y), inverse=
True)
33 ur_lon, ur_lat = prj(max(x), max(y), inverse=
True)
34 return Basemap(projection=
'stere', lat_0=lat_0, lon_0=lon_0,
35 llcrnrlon=ll_lon, llcrnrlat=ll_lat,
36 urcrnrlon=ur_lon, urcrnrlat=ur_lat, **kwargs)
40 ''' Class that generates all of the generic parts of a map figure.'''
42 ''' Load the parameters dictionary that defines plotting parameters for various variables.
47 '''Definition of parameters for plotting standard maps.
48 The top level variable name must match the "shortName" used in the grib file.
50 subdictionary for various height levels to define either int/min/max values,
51 or contour values directly. Other options that the scripts use:
52 cbar: user-specified color tables
53 scale: a scale factor (should start with an operator (*,/,+,-)
54 unit: a string for unit if the one in the grib file is inappropriate
55 varname: option for using a variable name different than that in the grib file
58 'gh': {
'200': {
'int': 100,
'min': 100,
'max': 10000},
59 '500': {
'int': 100,
'min': 4600,
'max': 6200},
60 '700': {
'int': 50,
'min': 100,
'max': 2500},
61 '850': {
'int': 50,
'min': 750,
'max': 1750},
67 't': {
'200': {
'int': 5,
'min': -85,
'max': -30},
68 '500': {
'int': 5,
'min': -50,
'max': 15},
69 '700': {
'int': 5,
'min': -40,
'max': 30},
70 '850': {
'int': 5,
'min': -40,
'max': 40},
71 'any': {
'int': 5,
'min': -75,
'max': 75},
74 'prmsl': {
'0': {
'int': 10,
'min': 930,
'max': 1070},
78 'varname':
'Mean sea level pressure'},
80 '2t': {
'2': {
'int': 5,
'min': -50,
'max': 50},
83 'varname':
'2m temperature'},
85 '2d': {
'2': {
'int': 5,
'min': -50,
'max': 50},
88 'varname':
'2m dewpoint temperature',
91 'absv':{
'500': {
'int': 5e-5,
'min': -7.e-4,
'max': 7.e-4},
96 'cbar': plt.cm.RdBu_r},
98 'w':{
'700': {
'int': 0.6,
'min': -6,
'max': 6},
99 'cbar': plt.cm.RdBu_r},
101 'wind':{
'200': {
'int': 10,
'min': 0,
'max': 90},
102 '500': {
'int': 10,
'min': 0,
'max': 90},
103 '700': {
'int': 10,
'min': 0,
'max': 90},
104 '850': {
'int': 10,
'min': 0,
'max': 90},
105 'any': {
'int': 5,
'min': 5,
'max': 250}},
106 '10u':{
'10': {
'int': 3,
'min': -30,
'max': 30},
107 'cbar': plt.cm.RdBu_r},
108 '10v':{
'10': {
'int': 3,
'min': -30,
'max': 30},
109 'cbar': plt.cm.RdBu_r},
111 'r' :{'850': {'int': 5, 'min': 0, 'max': 105},
112 'cbar': plt.cm.gist_earth_r},
113 'ncpcp':{
'0': {
'contours': [0,1,2.5,5,7.5,10,15,20,30,40,50,70,100,150,200,250,300,400,500,600]},
115 'acpcp':{
'0': {
'contours': [0,0.001,0.01,0.1,0.5,1,2.5,5,7.5,10,12.5,15,17.5,20,22.5,25,27.5,30,35,40,45,50,55,60,65,70,80,90,100,150,200]},
117 'tp':{
'0': {
'contours': [0,0.1,0.5,1,2.5,5,7.5,10,15,20,30,40,50,70,100,150,200,250,300,400,500,600]},
119 'q': {
'any': {
'int': 2,
'min': 0 ,
'max': 24 },
123 'btmp': {
'0': {
'int': 5,
'min': -100 ,
'max': 10 },
126 'cbar':
'gist_ncar_r'},
127 'pwat':{
'0': {
'int': 5 ,
'min':5 ,
'max': 100},
131 'prate': {
'0': {
'int': 0.2,
'min': 0.2,
'max': 3.6},
133 'unit':
'g m**-2 s**-1',
135 'cprat': {
'0': {
'int': 0.2,
'min': 0.2,
'max': 3.6},
137 'unit':
'g m**-2 s**-1',
140 'ULWRF': {
'0': {
'default':
True},
153 plt.figure(figsize=(15,12))
166 parallels = np.arange(-90.,90,10.)
167 m.drawparallels(parallels,labels=[1,0,0,0],fontsize=10)
168 meridians = np.arange(0.,360.,20.)
169 m.drawmeridians(meridians,labels=[0,0,0,1],fontsize=10)
175 fp_field=fp.get(self.
myvar,
None)
178 lev = str(field[
'level'])
179 atime = field.analDate.strftime(
'%Y%m%d%H')
184 fcsthr=field[
'endStep']
188 vert_unit = self.
coord_str(str(field[
'typeOfLevel']),title=
False)
191 filename=
''.join([var,lev,vert_unit,
'_',grid,
'_',atime,
'_f',
'{:02d}'.format(fcsthr),
'.png'])
194 if not os.path.exists(outdir):
197 plt.savefig(
'/'.join([outdir, filename]))
203 '''Color-fill the field of the figure being plotted'''
207 x, y = m(self.lon,self.lat)
211 check_lev = fp[self.
myvar].get(str(self.level),
None)
212 if check_lev
is not None:
213 var_lev = str(self.level)
219 min = fp[self.
myvar][var_lev].get(
'min',
None)
220 max = fp[self.
myvar][var_lev].get(
'max',
None)
221 int = fp[self.
myvar][var_lev].get(
'int',
None)
224 if min
is None: levs = fp[self.
myvar][var_lev].get(
'contours',
None)
228 colormap = fp[self.
myvar].get(
'cbar',plt.cm.jet)
239 scale = fp[self.
myvar].get(
'scale',
None)
243 clevs = np.arange(min,max,int)
244 elif levs
is not None:
251 cs = m.contourf(x,y,data,cmap=colormap)
253 csl= m.contour(x,y,data,colors=
'k')
254 plt.clabel(csl, fontsize=10, inline=1, fmt=
'%4.0f')
256 cs = m.contourf(x,y,data,clevs,cmap=colormap)
258 csl= m.contour(x,y,data,clevs,colors=
'k')
259 plt.clabel(csl, fontsize=10, inline=1, fmt=
'%4.0f')
261 cbar = plt.colorbar(cs,orientation=
'horizontal',extend=
'both')
264 ''' scale field values'''
266 if scale
is not None:
268 data=np.true_divide(field.values,float(scale[1:]))
269 elif scale[0] ==
'-':
270 data=np.subtract(field.values,eval(scale[1:]))
271 elif scale[0] ==
'*':
272 data=np.multiply(field.values,float(scale[1:]))
278 '''Draw field contours. Does not have to be the main field being processed. Mostly plotting height.'''
282 x, y = m(self.lon,self.lat)
284 check_lev = fp[self.
myvar].get(str(self.level),
None)
285 if check_lev
is not None:
286 var_lev = str(self.level)
292 min = fp[self.
myvar][var_lev].get(
'min',
None)
293 max = fp[self.
myvar][var_lev].get(
'max',
None)
294 int = fp[self.
myvar][var_lev].get(
'int',
None)
297 if min
is None: levs = fp[self.
myvar][var_lev].get(
'contours',
None)
299 scale = fp[var].get(
'scale',
None)
303 clevs = np.arange(min,max,int)
304 elif levs
is not None:
310 cc = m.contour(x,y,data,colors=
'k')
312 cc = m.contour(x,y,data,clevs,colors=
'k')
314 plt.clabel(cc, fontsize=10, inline=1, fmt=
'%4.0f')
318 '''Plot the wind field in barbs. Masks are applied here to thin
319 the quantity of barbs plotted for clarity'''
323 u=self.winds[0].values
324 v=self.winds[1].values
327 maskarray = np.ones(u.shape)
329 maskarray[1::7,1::14] = 0
331 maskarray[1::3,1::6] = 0
333 maskarray[1::20,1::40] = 0
336 mu = np.ma.masked_array(u, mask=maskarray)
337 mv = np.ma.masked_array(v, mask=maskarray)
338 x, y = m(self.lon,self.lat)
339 barb_control = dict(height=0.6, width=0.3, emptybarb=0.07)
340 self.
barbs = m.barbs(x, y, mu, mv, barbcolor=
'k',pivot=
'middle',sizes=barb_control, linewidth=0.4, length=5)
343 '''Determine how to label the vertical coordinate based on the contents of the grib file, or other
346 if coord ==
'isobaricInhPa':
347 vert_unit = str(field[
'pressureUnits'])
348 elif coord ==
'hybrid':
350 vert_unit =
"$\sigma$"
353 elif coord ==
'surface':
355 elif coord ==
'nominalTop':
363 ''' configure plot title'''
366 date = str(field[
'dataDate'])
367 myvar = fp[self.
myvar].get(
'varname',str(field[
'name']))
368 atime = field.analDate.strftime(
'Analysis: %Y%m%d %H UTC')
370 vtime = field.validDate.strftime(
'Valid: %Y%m%d %H UTC')
374 level = str(self.level)
375 coord = str(field[
'typeOfLevel'])
378 var_unit = fp[self.
myvar].get(
'unit',field[
'units'])
381 if self.fhr
is not None:
386 fcsthr=str(field[
'stepRange'])
391 title_str=str(
'wind magnitude (%s, %s)'%(var_unit,maptype))
393 title_str=str(
'%s (%s, %s)'%(myvar,var_unit,maptype))
395 plt.title(
'%s \nFcst Hr: %s' % (atime, fcsthr) , loc=
'left')
396 plt.title(
'%s %s' % (level,vert_unit), position=(0.5, 1.04), fontsize=18)
398 plt.title(
'%s \n Height (gpm), contoured' % (title_str)
401 plt.title(
'%s' % title_str, loc =
'right')
402 plt.xlabel(
'%s' % (vtime), fontsize=18, labelpad=40)
410 if self.height
is not None: self.
contour_field(
'gh',self.height)
416 ''' Class that defines the map projection for the data based on verification grids provided.'''
417 def __init__(self,field,date,myvar,level,area_flag='glob',ncep_grid=None, line=False,
418 resolution=
None, winds=
None, plot_height=
None, def_maps=
None, fhr=
None):
422 self.lat, self.
lon = field.latlons()
433 ''' Defines several common maps used for verification in a Python dict'''
435 'glob': {
'resolution':
'c',
'projection':
'cyl',
'lat_ts':10,
'llcrnrlon':0,
'urcrnrlon':357.5,
'llcrnrlat':-90,
'urcrnrlat':90},
436 'G3': {
'resolution':
'c',
'projection':
'cyl',
'lat_ts':10,
'llcrnrlon':0,
'urcrnrlon':357.5,
'llcrnrlat':-90,
'urcrnrlat':90},
437 'nh_mill': {
'resolution':
'c',
'projection':
'mill',
'lat_ts':10,
'llcrnrlon':0,
'urcrnrlon':357.5,
'llcrnrlat': 0,
'urcrnrlat':90},
438 'sh_mill': {
'resolution':
'c',
'projection':
'mill',
'lat_ts':10,
'llcrnrlon':0,
'urcrnrlon':357.5,
'llcrnrlat':-90,
'urcrnrlat': 0},
439 'trop_mill': {
'resolution':
'c',
'projection':
'mill',
'lat_ts':10,
'llcrnrlon':0,
'urcrnrlon':357.5,
'llcrnrlat':-23,
'urcrnrlat':23},
440 'nps': {
'resolution':
'c',
'projection':
'npstere',
'boundinglat':-0.268,
'lon_0':-105},
441 'sps': {
'resolution':
'c',
'projection':
'spstere',
'boundinglat': -60,
'lon_0': 105},
442 'G218': {
'resolution':
'c',
'projection':
'lcc',
'lat_1':25,
'lat_2':25,
'lon_0':265,
'rsphere':6371200,
'llcrnrlon':226.514,
'llcrnrlat':12.190,
'urcrnrlon':-49.420 ,
'urcrnrlat':57.328},
443 'G104': [-147, -64, 10.8, 89.9],
449 ''' Sets the Basemap object for creating the figure.'''
451 map_def=base_map.get(self.
area_flag,
None)
453 if map_def
is None: map_def=base_map.get(
'glob')
456 self.
m=Basemap(**map_def)
def save_figure(self, outdir)
def contour_field(self, var, field)
def polar_stere(bounds, kwargs)