This notebook describes the recommended process for development of
functions for the salishsea_tools.nowcast.figures
module,
and provides an example of development of such a function.
from __future__ import division
import os
import matplotlib.pyplot as plt
import netCDF4 as nc
from salishsea_tools import nc_tools
%matplotlib inline
The big goal of this notebook is to define conventions for functions
that will live in salishsea_tools.nowcast.figures
and be called
by automation code to produce daily plots showing features of the results
of real-time (nowcast and forecast) run of the SalishSeaCast NEMO model.
Let's start with a simple example objective:
an hourly plot of model sea surface height (ssh) at Pt. Atkinson
To get that plot on a daily basis we need to provide a function
that takes the hourly grid_T
results dataset from NEMO
and returns a Matplotlib figure
object.
So, we'll have a function defintion like:
def ssh_PtAtkinson(grid_T, bathy=None, figsize=(12, 4)):
"""Return a figure containing a plot of hourly sea surface height at Pt. Atkinson.
:arg grid_T: Hourly tracer results dataset from NEMO.
:type grid_T: :class:`netCDF4.Dataset`
:arg bathy: Bathymetry dataset for the SalishSeaCast NEMO model.
:type bathy: :class:`netCDF4.Dataset`
:arg figsize: Figure size (width, height) in inches.
:type figsize: 2-tuple
:returns: Matplotlib figure object
"""
fig, ax = plt.subplots(1, 1, figsize=figsize)
...
return fig
that the automation code can use like:
from salishsea_tools.nowcast import figures
grid_T = nc.Dataset('nowcast/28oct14/SalishSea_1h_20141028_20141028_grid_T.nc')
fig = figures.ssh_PtAtkinson(grid_T)
# Render to figure object for display on a web page
Of course,
it's not just the automation code that can use the salishsea_tools.nowcast.figures
functions,
you and your colleagues can use them in exactly the same way in your notebooks.
There are a bunch of conventions implied in our function definition fragment:
def ssh_PtAtkinson(grid_T, bathy=None, figsize=(12, 4)):
"""Return a figure containing a plot of hourly sea surface height at Pt. Atkinson.
:arg grid_T: Hourly tracer results dataset from NEMO.
:type grid_T: :class:`netCDF4.Dataset`
:arg bathy: Bathymetry dataset for the SalishSeaCast NEMO model.
:type bathy: :class:`netCDF4.Dataset`
:arg figsize: Figure size (width, height) in inches.
:type figsize: 2-tuple
:returns: Matplotlib figure object
"""
fig, ax = plt.subplots(1, 1, figsize=figsize)
...
return fig
plot
,
figure
,
nowcast
,
realtime
,
or forecast
because their package and module context implies those things.netCDF4.Dataset
objects (like grid_T
) into the functions
rather than passing in file names because the chances are good that
a given dataset (like bathymetry) will be used in more than one function.
By making it the caller's job to load the dataset we avoid
having multiple copies of it in memory,
and the repeatedly doing the comparitively slow process of reading the dataset from disk.None
so that we don't have to
deal with it in functions like ssh_PtAtkinson()
that don't use it.figsize
as an argument with a default value
allows the caller to adjust the size of the figure to their needs.
Please choose an aspect ratio for figsize
that is appropriate to
the information in the figure;
it serves as a hint for other users.:arg ...:
,
:type ...:
,
and :returns:
markup
(see the Sphinx Info Field Lists documentation)
so that the nice looking documentation like
this
will be generated automatically.plt.subplots()
to create figure
and axes
instances.
Most of your plotting commands will be axes
method calls
(e.g. ax.plot(...)
),
with a few figure
method calls,
and rare plt
method calls.
That minimized global state and side-effects that may interfere with other plot functions.figure
object so that the automation code can render it appropriately
for inclusion in a web page.
If you,
or someone else,
calls your function in a notebook it will render automatically,
in the notebook if %matplotlib inline
has been set,
or in a separate window otherwise.nowcast.figures
Function¶The recommended workflow to develop a new nowcast.figures
function is:
Create the function in a notebook cell.
Create 1 or more notebook cell(s) containing code
to prepare the inputs for the function, and call the function; i.e. to drive the function.
until the function produces the plot that you want.
Export the function to nowcast.figures
.
Use your favourite code editor to do any necessary clean-up in nowcast.figures
.
Commit and push your nowcast.figures
changes.
#%%writefile -a figures.py
def ssh_PtAtkinson(grid_T, bathy=None, figsize=(12, 4)):
"""Return a figure containing a plot of hourly sea surface height at Pt. Atkinson.
:arg grid_T: Hourly tracer results dataset from NEMO.
:type grid_T: :class:`netCDF4.Dataset`
:arg bathy: Bathymetry dataset for the SalishSeaCast NEMO model.
:type bathy: :class:`netCDF4.Dataset`
:arg figsize: Figure size (width, height) in inches.
:type figsize: 2-tuple
:returns: Matplotlib figure object
"""
fig, ax = plt.subplots(1, 1, figsize=figsize)
ssh = grid_T.variables['sossheig']
results_date = nc_tools.timestamp(grid_T, 0).format('YYYY-MM-DD')
ax.plot(ssh[:, 468, 328], 'o')
ax.set_xlim(0, 23)
ax.set_xlabel('UTC Hour on {}'.format(results_date))
ax.set_ylabel('{label} [{units}]'.format(label=ssh.long_name.title(), units=ssh.units))
ax.grid()
ax.set_title('Pt. Atkinson Hourly Sea Surface Height on {}'.format(results_date))
return fig
grid_T = nc.Dataset(
os.path.expanduser('~/MEOPAR/downloaded_results/SalishSea/nowcast/30oct14/SalishSea_1h_20141030_20141030_grid_T.nc'))
fig = ssh_PtAtkinson(grid_T)
ax = fig.axes[0]
ax.set_axis_bgcolor('#2b3e50')
fig.set_facecolor('#2b3e50')
fig