|
| 1 | +# make plot of ozone concentration data on |
| 2 | +# lambert conformal conic map projection, drawing coastlines, state and |
| 3 | +# country boundaries, and parallels/meridians. |
| 4 | + |
| 5 | +# the data is interpolated to the native projection grid. |
| 6 | +from mpl_toolkits.basemap import Basemap, shiftgrid |
| 7 | +import numpy as np |
| 8 | +import matplotlib.pyplot as plt |
| 9 | +import netCDF4 |
| 10 | +plt.rcParams['text.usetex'] = False |
| 11 | + |
| 12 | +# read in netCDF4 file. Results from CAMx v6 |
| 13 | +# test case, converted to netcdf by PseudoNetCDF |
| 14 | +# pseudonetcdf.googlecode.com |
| 15 | +camx = netCDF4.Dataset('camx.sample.nc') |
| 16 | + |
| 17 | +#alternatively read directly from CAMx uamiv file |
| 18 | +#if available |
| 19 | +# |
| 20 | +# from PseudoNetCDF.camxfiles.Memmaps import uamiv |
| 21 | +# camx = uamiv('camx.bin') |
| 22 | + |
| 23 | +# Get Ozone Variable |
| 24 | +o3 = camx.variables['O3'] |
| 25 | + |
| 26 | +# Get projection space |
| 27 | +llcrnrx = camx.XORIG |
| 28 | +llcrnry = camx.YORIG |
| 29 | +urcrnrx = llcrnrx + (o3[:].shape[-1] + 1) * camx.XCELL |
| 30 | +urcrnry = llcrnry + (o3[:].shape[-2] + 1) * camx.XCELL |
| 31 | + |
| 32 | +# Get edge values for pcolor |
| 33 | +xedge = np.linspace(0, urcrnrx - llcrnrx, camx.NCOLS + 1) |
| 34 | +yedge = np.linspace(0, urcrnry - llcrnry, camx.NCOLS + 1) |
| 35 | +X, Y = np.meshgrid(xedge, yedge) |
| 36 | + |
| 37 | + |
| 38 | +# setup of basemap ('lcc' = lambert conformal conic). |
| 39 | +# projection parameters from CAMx file |
| 40 | +m = Basemap(projection = 'lcc', |
| 41 | + lon_0=camx.P_GAM, lat_0 = 40., |
| 42 | + lat_1 = camx.P_ALP, lat_2 = camx.P_BET, |
| 43 | + llcrnrx = llcrnrx, llcrnry = llcrnry, |
| 44 | + urcrnry = urcrnry, urcrnrx = urcrnrx) |
| 45 | + |
| 46 | +# create the figure. |
| 47 | +fig=plt.figure(figsize=(8,8)) |
| 48 | + |
| 49 | +# add an axes. |
| 50 | +ax = fig.add_axes([0.1,0.1,0.8,0.8]) |
| 51 | +ax.set_axis_bgcolor('lightgrey') |
| 52 | +# associate this axes with the Basemap instance. |
| 53 | +m.ax = ax |
| 54 | + |
| 55 | +# plot tile plot with pcolor |
| 56 | +# Use first time and first layer (i.e., o3[0, 0] (time, layer, row, col)) |
| 57 | +# Edge cells have precisely 0 value, and are masked |
| 58 | +# to avoid an unnecessary color range. |
| 59 | +# Each color bin contains precisely 10% of values |
| 60 | +# which makes for a pretty plot. |
| 61 | +from matplotlib.colors import ListedColormap |
| 62 | +WhGrYlBu = ListedColormap(['#ffffff', '#b7f6ff', '#70edff', '#29e4ff', '#00e1fb', '#0fffc6', '#3bffa4', '#68ff82', '#94ff60', '#c0ff3e', '#edff1c', '#fff400', '#ffc700', '#ff9b00', '#ff6e00', '#ff4200', '#ff1500', '#e80000', '#bb0000', '#8f0000']) |
| 63 | +#.from_list('WhGrYlBu', ['white', 'white', 'cyan', 'lightblue', 'lightgreen', 'green', 'yellow', 'orange', 'red', 'red']) |
| 64 | + |
| 65 | +toplot = np.ma.masked_values(o3[0, 0], 0.) * 1000. |
| 66 | +bounds = np.percentile(toplot.compressed().ravel(), np.linspace(5, 95, 9).tolist()) |
| 67 | +ptch = m.pcolor(X, Y, toplot, cmap = WhGrYlBu, norm = plt.matplotlib.colors.BoundaryNorm(bounds, 20), vmin = bounds[0], vmax = bounds[-1]) |
| 68 | + |
| 69 | +# Add a colorbar using proportional spacing, but |
| 70 | +# colors based on 10 distinct bins |
| 71 | +cb = m.colorbar(ptch, location='right',pad='10%', boundaries = bounds, spacing = 'proportional', format = '%.3f', extend = 'both') # draw colorbar |
| 72 | + |
| 73 | +# Add units to the colorbar |
| 74 | +cb.ax.set_xlabel('%s*1000.' % o3.units.strip()) |
| 75 | + |
| 76 | + |
| 77 | +# plot blue dot on Houston, Baton Rouge, and Atlanta |
| 78 | +def add_dot(lon, lat, label): |
| 79 | + xpt,ypt = m(lon,lat) |
| 80 | + m.plot([xpt],[ypt],'bo') |
| 81 | + ax.annotate(label, xy=(xpt, ypt), xytext=(xpt+1e5, ypt+1e5), |
| 82 | + bbox=dict(boxstyle="round4", fc="w"), |
| 83 | + arrowprops=dict(facecolor='black'), |
| 84 | + ) |
| 85 | +add_dot(-95.361328,29.754505, 'Houston') |
| 86 | +add_dot(-91.140320, 30.458283, 'Baton Rouge') |
| 87 | +add_dot(-84.387982, 33.748995, 'Atlanta') |
| 88 | +# draw coastlines and political boundaries. |
| 89 | +m.drawcoastlines() |
| 90 | +m.drawcountries() |
| 91 | +m.drawstates() |
| 92 | +# draw parallels and meridians. |
| 93 | +# label on left, right and bottom of map. |
| 94 | +parallels = np.arange(20.,60,10.) |
| 95 | +m.drawparallels(parallels,labels=[1,1,0,1]) |
| 96 | +meridians = np.arange(-120., 70.,10.) |
| 97 | +m.drawmeridians(meridians,labels=[1,1,0,1]) |
| 98 | + |
| 99 | +# set title. |
| 100 | +ax.set_title('O$_3$ as predicted by the CAMx v6 Test-Case\neach color division has 10% of cells 5-95% and 5% in triagles') |
| 101 | +import textwrap |
| 102 | +histstr = 'Processing: %s' % '\n'.join(textwrap.wrap(camx.history.strip(), 140)) |
| 103 | + |
| 104 | +fig.text(0.01, 0.01, histstr, horizontalalignment = 'left', verticalalignment = 'bottom', size = 8) |
| 105 | +plt.draw() |
| 106 | +plt.show() |
0 commit comments