Test out UGRID-0.9 compliant unstructured grid model datasets with PYUGRID


In [28]:
%matplotlib inline

In [29]:
import numpy as np
import matplotlib.tri as tri
import matplotlib.pyplot as plt
import datetime as dt
import netCDF4

In [30]:
import cartopy.crs as ccrs
from cartopy.io.img_tiles import MapQuestOpenAerial, MapQuestOSM, OSM

In [31]:
import iris
import pyugrid

In [32]:
iris.FUTURE.netcdf_promote = True

In [33]:
#ADCIRC
#url =  'http://comt.sura.org/thredds/dodsC/data/comt_1_archive/inundation_tropical/UND_ADCIRC/Hurricane_Ike_3D_final_run_with_waves'
#FVCOM
#url = 'http://www.smast.umassd.edu:8080/thredds/dodsC/FVCOM/NECOFS/Forecasts/NECOFS_GOM3_FORECAST.nc'
#SELFE
#url = 'http://comt.sura.org/thredds/dodsC/data/comt_1_archive/inundation_tropical/VIMS_SELFE/Hurricane_Ike_2D_final_run_with_waves'

In [34]:
# UMASSD/SMAST Water Quality FVCOM Simulation for MWRA
url = 'http://www.smast.umassd.edu:8080/thredds/dodsC/fvcom/mwra/wq'
var = 'Dissolved oxygen'  # use long_name because DO has no standard_name in this dataset
levs = np.arange(5.,15.,.25)   # contour levels for plotting
klev = 0   # level 0 is top in FVCOM

In [35]:
# UMASSD/SMAST FVCOM Simulations in support of Water Quality for MWRA
url = 'http://www.smast.umassd.edu:8080/thredds/dodsC/fvcom/mwra/fvcom'
var = 'sea_water_salinity'    # use standard_name if it exists
levs = np.arange(28.,33.5,.1)   # contour levels for plotting
klev = 0   # level 0 is top in FVCOM

In [36]:
# Desired time for snapshot
# ....right now (or some number of hours from now) ...
start = dt.datetime.utcnow() + dt.timedelta(hours=6)
# ... or specific time (UTC)
start = dt.datetime(1998,3,2,15,0,0)

In [37]:
nc = netCDF4.Dataset(url)
#print nc.variables.keys()  # list variables
#nc.variables['DO']  # show variable with attributes

In [38]:
cube = iris.load_cube(url,var)    # Iris uses the standard_name or long_name to access variables


/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/iris/fileformats/cf.py:552: UserWarning: Missing CF-netCDF formula term variable u'depth', referenced by netCDF variable u'siglev'
  warnings.warn(message % (variable_name, nc_var_name))
/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/iris/fileformats/cf.py:1006: UserWarning: Ignoring variable u'siglay' referenced by variable u'v': Dimensions (u'siglay', u'node') do not span (u'time', u'siglay', u'nele')
  warnings.warn(msg)
/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/iris/fileformats/cf.py:1006: UserWarning: Ignoring variable u'siglay' referenced by variable u'ww': Dimensions (u'siglay', u'node') do not span (u'time', u'siglay', u'nele')
  warnings.warn(msg)
/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/iris/fileformats/cf.py:1006: UserWarning: Ignoring variable u'siglay' referenced by variable u'u': Dimensions (u'siglay', u'node') do not span (u'time', u'siglay', u'nele')
  warnings.warn(msg)
/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/iris/fileformats/_pyke_rules/compiled_krb/fc_rules_cf_fc.py:1300: UserWarning: Ignoring netCDF variable u'wts' invalid units u'UDUNITS compatible units'
  warnings.warn(msg.encode('ascii', errors='backslashreplace'))

In [39]:
# Get desired time step  
time_var = nc['time']
itime = netCDF4.date2index(start,time_var,select='nearest')

In [40]:
ug = pyugrid.UGrid.from_ncfile(url)

print "There are %i nodes"%ug.nodes.shape[0]
print "There are %i faces"%ug.faces.shape[0]


There are 5472 nodes
There are 9739 faces

In [41]:
print cube


sea_water_salinity / (1)            (time: 131611; -- : 30; -- : 5472)
     Dimension coordinates:
          time                           x            -        -
     Auxiliary coordinates:
          sea_surface_height_above_geoid x            -        x
          Sigma Layers                   -            x        x
          latitude                       -            -        x
          longitude                      -            -        x
          sea_floor_depth_below_geoid    -            -        x
     Attributes:
          Conventions: CF-1.0, UGRID-0.9
          CoordinateProjection: init=nad83:1802
          CoordinateSystem: Cartesian
          GroundWater_Forcing: FVCOM variable GroundWater forcing:
FILE NAME:gom_gwater_forcing.nc
SOURCE:FVCOM...
          NCO: 4.4.4
          River_Forcing: THERE ARE 13 RIVERS IN THIS MODEL.
RIVER INFLOW IS ON THE nodes WHERE TEMPERATURE...
          Surface_Heat_Forcing: FVCOM variable surface heat forcing file:
FILE NAME:wrf_hnd2012.nc
SOURCE:wrf2fvcom...
          Surface_PrecipEvap_Forcing: FVCOM periodic surface precip forcing:
FILE NAME:wrf_hnd2012.nc
SOURCE:wrf2fvcom...
          Surface_Wind_Forcing: FVCOM variable surface Wind forcing:
FILE NAME:wrf_hnd2012.nc
SOURCE:wrf2fvcom...
          Tidal_Forcing: TIDAL ELEVATION FORCING IS OFF!
          cdm_data_type: any
          coverage_content_type: modelResult
          grid: fvcom_grid
          history: Wed Nov  4 12:13:28 2015: ncks -A ../lonlat.nc test.nc
Wed Nov  4 12:08:25...
          institution: School for Marine Science and Technology
          location: node
          mesh: fvcom_mesh
          nco_openmp_thread_number: 1
          references: http://fvcom.smast.umassd.edu, http://codfish.smast.umassd.edu
          source: FVCOM_3.0
          summary: Archive of MWRA simulations to support water quality modeling (1995-pr...
          title: Mass Water Resources Authority (MWRA) FVCOM simulations
          type: data

In [42]:
cube.mesh = ug
cube.mesh_dimension = 1  # (0:time,1:node)

In [43]:
lon = cube.mesh.nodes[:,0]
lat = cube.mesh.nodes[:,1]
nv = cube.mesh.faces

In [44]:
triang = tri.Triangulation(lon,lat,triangles=nv)

In [45]:
zcube = cube[itime, klev, :]

In [46]:
print zcube.data.min()
print zcube.data.max()


0.0
32.2619

try simple plot


In [47]:
plt.tricontourf(triang, zcube.data, levels=levs)


Out[47]:
<matplotlib.tri.tricontour.TriContourSet instance at 0x7fd8c8b281b8>

Try more complex cartopy plot


In [48]:
fig = plt.figure(figsize=(12,12))
ax = plt.axes(projection=ccrs.PlateCarree())
#ax.set_extent([-90, -60, 5, 50])
#ax.coastlines('10m')
plt.tricontourf(triang, zcube.data, levels=levs)
plt.colorbar(fraction=0.035, pad=0.04)
plt.tricontour(triang, zcube.data, colors='k',levels=levs)
tvar = cube.coord('time')
tstr = tvar.units.num2date(tvar.points[itime])
gl = ax.gridlines(draw_labels=True)
gl.xlabels_top = False
gl.ylabels_right = False
plt.title('%s: Elevation (m): %s' % (zcube.attributes['title'],tstr));


---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/IPython/core/formatters.pyc in __call__(self, obj)
    335                 pass
    336             else:
--> 337                 return printer(obj)
    338             # Finally look for special method names
    339             method = _safe_get_formatter_method(obj, self.print_method)

/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/IPython/core/pylabtools.pyc in <lambda>(fig)
    205 
    206     if 'png' in formats:
--> 207         png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
    208     if 'retina' in formats or 'png2x' in formats:
    209         png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))

/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/IPython/core/pylabtools.pyc in print_figure(fig, fmt, bbox_inches, **kwargs)
    115 
    116     bytes_io = BytesIO()
--> 117     fig.canvas.print_figure(bytes_io, **kw)
    118     data = bytes_io.getvalue()
    119     if fmt == 'svg':

/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/matplotlib/backend_bases.pyc in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, **kwargs)
   2156                     orientation=orientation,
   2157                     dryrun=True,
-> 2158                     **kwargs)
   2159                 renderer = self.figure._cachedRenderer
   2160                 bbox_inches = self.figure.get_tightbbox(renderer)

/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/matplotlib/backends/backend_agg.pyc in print_png(self, filename_or_obj, *args, **kwargs)
    519 
    520     def print_png(self, filename_or_obj, *args, **kwargs):
--> 521         FigureCanvasAgg.draw(self)
    522         renderer = self.get_renderer()
    523         original_dpi = renderer.dpi

/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/matplotlib/backends/backend_agg.pyc in draw(self)
    467 
    468         try:
--> 469             self.figure.draw(self.renderer)
    470         finally:
    471             RendererAgg.lock.release()

/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs)
     57     def draw_wrapper(artist, renderer, *args, **kwargs):
     58         before(artist, renderer)
---> 59         draw(artist, renderer, *args, **kwargs)
     60         after(artist, renderer)
     61 

/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/matplotlib/figure.pyc in draw(self, renderer)
   1083         dsu.sort(key=itemgetter(0))
   1084         for zorder, a, func, args in dsu:
-> 1085             func(*args)
   1086 
   1087         renderer.close_group('figure')

/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs)
     57     def draw_wrapper(artist, renderer, *args, **kwargs):
     58         before(artist, renderer)
---> 59         draw(artist, renderer, *args, **kwargs)
     60         after(artist, renderer)
     61 

/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/cartopy/mpl/geoaxes.pyc in draw(self, renderer, inframe)
    336         if self.outline_patch.reclip or self.background_patch.reclip:
    337             clipped_path = clip_path(self.outline_patch.orig_path,
--> 338                                      self.viewLim)
    339             self.outline_patch._path = clipped_path
    340             self.background_patch._path = clipped_path

/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/cartopy/mpl/clip_path.pyc in clip_path(subject, clip_bbox)
    115 
    116         """
--> 117         return subject.clip_to_bbox(clip_bbox)
    118 else:
    119     def clip_path(subject, clip_bbox):

/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/matplotlib/path.pyc in clip_to_bbox(self, bbox, inside)
    932         verts = _path.clip_path_to_rect(self, bbox, inside)
    933         paths = [Path(poly) for poly in verts]
--> 934         return self.make_compound_path(*paths)
    935 
    936 

/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/matplotlib/path.pyc in make_compound_path(cls, *args)
    330         total_length = sum(lengths)
    331 
--> 332         vertices = np.vstack([x.vertices for x in args])
    333         vertices.reshape((total_length, 2))
    334 

/home/usgs/miniconda/envs/ioos/lib/python2.7/site-packages/numpy/core/shape_base.pyc in vstack(tup)
    228 
    229     """
--> 230     return _nx.concatenate([atleast_2d(_m) for _m in tup], 0)
    231 
    232 def hstack(tup):

ValueError: need at least one array to concatenate
<matplotlib.figure.Figure at 0x7fd8c8bfc390>

Try to plot using tiled background


In [ ]:
projection = ccrs.PlateCarree()

fig = plt.figure(figsize=(12,12))
tiler = MapQuestOpenAerial()
ax = plt.axes(projection=projection)

ax.set_extent([-71.5, -70, 41.5, 43], projection)
ax.add_image(tiler, 8, zorder=0)

cs = ax.tricontourf(triang, zcube.data, levels=levs, zorder=1)
ax.tricontour(triang, zcube.data, colors='k', levels=levs, zorder=2)
fig.colorbar(cs)

tvar = cube.coord('time')
tstr = tvar.units.num2date(tvar.points[itime])
gl = ax.gridlines(draw_labels=True)
gl.xlabels_top = False
gl.ylabels_right = False
ax.set_title('%s: Oxygen: %s' % (zcube.attributes['title'],tstr));

In [ ]:
#geodetic = ccrs.Geodetic(globe=ccrs.Globe(datum='WGS84'))
projection = ccrs.PlateCarree()

fig = plt.figure(figsize=(12,12))
tiler = MapQuestOpenAerial()
ax = plt.axes(projection=tiler.crs)

#ax = plt.axes(projection=ccrs.PlateCarree())
ax.set_extent([-71.5, -70, 41.5, 43],projection)
ax.add_image(tiler, 8, zorder=0)

#ax.coastlines()
plt.tricontourf(triang, zcube.data, levels=levs,zorder=1)
plt.colorbar()
plt.tricontour(triang, zcube.data, colors='k',levels=levs,zorder=2)
tvar = cube.coord('time')
tstr = tvar.units.num2date(tvar.points[itime])
gl = ax.gridlines(draw_labels=True)
gl.xlabels_top = False
gl.ylabels_right = False
plt.title('%s: Oxygen: %s' % (zcube.attributes['title'],tstr));

In [49]:
cube.coord(axis="x")


Out[49]:
AuxCoord(array([ 867630.,  869180.,  870980., ...,  822932.,  823078.,  822723.], dtype=float32), standard_name=u'longitude', units=Unit('degrees'), long_name=u'Longitude', var_name='lon', attributes={'grid': 'Bathymetry_Mesh'})

In [ ]: