baynes_sound_agrif
Figure Module¶Development of functions for nowcast.figures.research.baynes_sound_agrif
web site figure module.
Goal: A 4 panel figures showing surface values of temperature, salinity, diatoms biomass, and nitrate concentration at 12:30 Pacific time. Each panel to show all of the Baynes Sound sub-grid as well as a fringe of the full domain on the 3 non-land sides. Ideally the axes tick labels will be lon/lat with angled grid lines.
from pathlib import Path
from types import SimpleNamespace
import arrow
import cartopy
import cmocean
import matplotlib.pyplot as plt
import numpy
from salishsea_tools import viz_tools
import xarray
from nowcast.figures import shared
import nowcast.figures.website_theme
%matplotlib inline
_prep_plot_data()
Function¶def _prep_plot_data(sstracers_path, bs_phys_path, bs_bio_path, run_date, ss_grid_url, bs_grid_path):
SS_BAYNES_SOUND_X, SS_BAYNES_SOUND_Y = slice(112, 166), slice(550, 699)
ss_grid = xarray.open_dataset(ss_grid_url, mask_and_scale=False) \
.sel(gridX=SS_BAYNES_SOUND_X, gridY=SS_BAYNES_SOUND_Y)
ss_water_mask = (ss_grid.bathymetry!=0).values
bs_grid = xarray.open_dataset(bs_grid_path, mask_and_scale=False)
bs_water_mask = (bs_grid.Bathymetry!=0).values
ss_tracers = xarray.open_dataset(ss_tracers_path)
shared.localize_time(ss_tracers, time_coord='time_counter')
bs_phys = xarray.open_dataset(bs_phys_path)
bs_bio = xarray.open_dataset(bs_bio_path)
for dataset in (bs_phys, bs_bio):
shared.localize_time(dataset, time_coord='time_counter')
ss_temperature = _get_data_array(ss_tracers.votemper, ss_water_mask, run_date)
bs_temperature = _get_data_array(bs_phys.votemper, bs_water_mask, run_date)
bs_temperature.attrs['long_name'] = 'Conservative Temperature'
ss_salinity = _get_data_array(ss_tracers.vosaline, ss_water_mask, run_date)
bs_salinity = _get_data_array(bs_phys.vosaline, bs_water_mask, run_date)
bs_salinity.attrs['long_name'] = 'Reference Salinity'
ss_diatoms = _get_data_array(ss_tracers.diatoms, ss_water_mask, run_date)
bs_diatoms = _get_data_array(bs_bio.diatoms, bs_water_mask, run_date)
ss_nitrate = _get_data_array(ss_tracers.nitrate, ss_water_mask, run_date)
bs_nitrate = _get_data_array(bs_bio.nitrate, bs_water_mask, run_date)
return SimpleNamespace(
ss_temperature=ss_temperature,
bs_temperature=bs_temperature,
ss_salinity=ss_salinity,
bs_salinity=bs_salinity,
ss_diatoms=ss_diatoms,
bs_diatoms=bs_diatoms,
ss_nitrate=ss_nitrate,
bs_nitrate=bs_nitrate,
run_date=run_date,
tz_name=bs_phys.attrs['tz_name'],
ss_grid=ss_grid,
bs_grid=bs_grid,
)
def _get_data_array(ds_var, water_mask, run_date):
try:
return ds_var \
.isel(nearsurface_T=0) \
.sel(time_counter=run_date.format('YYYY-MM-DD 12:30')) \
.where(water_mask)
except ValueError:
return ds_var \
.isel(deptht=0) \
.sel(time_counter=run_date.format('YYYY-MM-DD 12:30')) \
.where(water_mask)
_prep_fig_axes()
Function¶def _prep_fig_axes(figsize, plot_data, theme):
rotated_crs = cartopy.crs.RotatedPole(pole_longitude=120.0, pole_latitude=63.75)
fig, axs = plt.subplots(
1, 4, figsize=figsize,
facecolor=theme.COLOURS['figure']['facecolor'],
subplot_kw={"projection": rotated_crs, "facecolor": theme.COLOURS['dark land']},
)
return fig, axs
_plot_surface_fields()
Function¶def _plot_surface_fields(axs, plot_data, theme):
vars = [
(plot_data.ss_temperature, plot_data.bs_temperature, cmocean.cm.thermal),
(plot_data.ss_salinity, plot_data.bs_salinity, cmocean.cm.haline),
(plot_data.ss_diatoms, plot_data.bs_diatoms, cmocean.cm.algae),
(plot_data.ss_nitrate, plot_data.bs_nitrate, cmocean.cm.matter),
]
for i, (ss_var, bs_var, cmap) in enumerate(vars):
_plot_surface_field(axs[i], ss_var, bs_var, cmap, plot_data.ss_grid, plot_data.bs_grid, theme)
def _plot_surface_field(ax, ss_var, bs_var, cmap, ss_grid, bs_grid, theme):
plain_crs = cartopy.crs.PlateCarree()
clevels = numpy.linspace(
numpy.floor(bs_var.where(bs_var>0).min()),
numpy.ceil(bs_var.where(bs_var>0).max()),
20
)
ax.contourf(
ss_grid.longitude, ss_grid.latitude, ss_var, transform=plain_crs,
cmap=cmap, levels=clevels, extend='max'
)
map_extent = ax.get_extent()
contour_set = ax.contourf(
bs_grid.nav_lon, bs_grid.nav_lat, bs_var, transform=plain_crs,
cmap=cmap, levels=clevels, extend='max'
)
ax.set_extent(map_extent, crs=ax.projection)
cbar = plt.colorbar(contour_set, ax=ax)
cbar.ax.axes.tick_params(labelcolor=theme.COLOURS['cbar']['tick labels'])
cbar.set_label(
f'{bs_var.attrs["long_name"]} [{bs_var.attrs["units"]}]',
color=theme.COLOURS['text']['axis'],
fontproperties=theme.FONTS['axis'],
)
isobath = ax.contour(
bs_grid.nav_lon, bs_grid.nav_lat, bs_grid.Bathymetry,
(25,), transform=plain_crs,
colors=theme.COLOURS['contour lines']['Baynes Sound entrance'],
)
ax.clabel(isobath, fmt={isobath.levels[0]: f'{isobath.levels[0]:.0f} m'})
_axes_labels()
Function¶def _axes_labels(axs, theme):
for ax in axs:
glines = ax.gridlines(draw_labels=True, auto_inline=False)
glines.right_labels, glines.top_labels = False, False
glines.xlabel_style = {"color": theme.COLOURS['text']['axis'], "fontproperties": theme.FONTS["axis small"]}
glines.ylabel_style = {"color": theme.COLOURS['text']['axis'], "fontproperties": theme.FONTS["axis small"]}
make_figure()
Function¶This is is the function that will be called by the nowcast.workers.make_plots
worker to return a matplotlib.figure.Figure
object.
def make_figure(
ss_tracers_path, bs_phys_path, bs_bio_path,
run_date,
ss_grid_url, bs_grid_path,
figsize=(22, 9),
theme=nowcast.figures.website_theme):
plot_data = _prep_plot_data(ss_tracers_path, bs_phys_path, bs_bio_path, run_date, ss_grid_url, bs_grid_path)
fig, axs = _prep_fig_axes(figsize, plot_data, theme)
_plot_surface_fields(axs, plot_data, theme)
_axes_labels(axs, theme)
time = plot_data.bs_temperature.time_counter
year = time.dt.year.values.item()
month = time.dt.month.values.item()
day = time.dt.day.values.item()
hour = time.dt.hour.values.item()
minute = time.dt.minute.values.item()
fig.suptitle(
f'{year}-{month:02d}-{day:02d} {hour:02d}:{minute:02d} {plot_data.tz_name}',
color=theme.COLOURS['text']['figure title'],
fontproperties=theme.FONTS['figure title'],
fontsize=theme.FONTS['figure title'].get_size(),
)
fig.canvas.draw()
fig.tight_layout(rect=[0, 0.03, 1, 0.95])
return fig
The %%timeit
cell magic lets us keep an eye on how log the figure takes to process.
Setting -n1 -r1
prevents it from processing the figure more than once
as it might try to do to generate better statistics.
# %%timeit -n1 -r1
from importlib import reload
from nowcast.figures import website_theme
reload(website_theme)
agrif_results_archive = Path('/results/SalishSea/nowcast-agrif.201702/')
run_date = arrow.get('2020-08-19')
ddmmmyy = run_date.format('DDMMMYY').lower()
yyyymmdd = run_date.format('YYYYMMDD')
ss_tracers_path = agrif_results_archive/ddmmmyy/'BaynesSoundSurface_grid_T.nc'
bs_phys_path = agrif_results_archive/ddmmmyy/f'1_SalishSea_1h_{yyyymmdd}_{yyyymmdd}_grid_T.nc'
bs_bio_path = agrif_results_archive/ddmmmyy/f'1_SalishSea_1h_{yyyymmdd}_{yyyymmdd}_ptrc_T.nc'
ss_grid_url = 'https://salishsea.eos.ubc.ca/erddap/griddap/ubcSSnBathymetryV17-02'
bs_grid_path = Path('/media/doug/warehouse/MEOPAR/grid/subgrids/BaynesSound/bathymetry_201702_BS.nc')
fig = make_figure(ss_tracers_path, bs_phys_path, bs_bio_path, run_date, ss_grid_url, bs_grid_path)