# Copyright 2016-2019 Doug Latornell (43ravens)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Produce a figure that shows surface values of a tracer field for the full GoMSS
model domain. The values are day averages. They are displayed as filled colour contours.
The axes grid and tick labels are an angled lon/lat grid using a Lambert Conformal Conic
map projection.
Testing notebook for this module is
https://nbviewer.jupyter.org/urls/bitbucket.org/gomss-nowcast/gomss_nowcast/raw/default/notebooks/figures/TestDayAvgTracer.ipynb
Development notebook for this module is
https://nbviewer.jupyter.org/urls/bitbucket.org/gomss-nowcast/gomss_nowcast/raw/default/notebooks/figures/DevelopDayAvgTracer.ipynb
"""
from types import SimpleNamespace
import matplotlib.pyplot as plt
import numpy
import xarray
import nowcast.figures.website_theme
from nowcast.figures import shared
def _prep_plot_data(results_archive, run_date, bathy):
"""
:param :py:class:`pathlib.Path` results_archive:
:param :py:class:`arrow.Arrow` run_date:
:param :py:class:`xarray.Dataset` bathy:
:return: :py:class:`types.SimpleNamespace`
"""
yyyymmdd = run_date.format("YYYYMMDD")
dataset_path = (
results_archive / run_date.format("YYYY-MM-DD") / f"GoMSS_NOWCAST_1d_{yyyymmdd}_{yyyymmdd}_grid_T.nc"
)
day_avg_tracers = xarray.open_dataset(dataset_path)
shared.localize_time(day_avg_tracers)
return SimpleNamespace(
day_avg_tracers=day_avg_tracers,
bathy=bathy,
tz_name=day_avg_tracers.attrs["tz_name"],
)
def _prep_fig_axes(figsize, plot_data, theme):
"""
:param 2-tuple figsize: Figure size (width, height) in inches.
:param :py:class:`types.SimpleNamespace` plot_data:
:param :py:mod:`nowcast.figures.website_theme` theme:
:return: :py:class:`matplotlib.figure.Figure`, :py:class:`matplotlib.axes.Axes`,
:py:class:`numpy.ndarray`, :py:class:`numpy.ndarray`
"""
fig, ax_surface = plt.subplots(
figsize=figsize, facecolor=theme.COLOURS["figure"]["facecolor"]
)
x, y = shared.projected_lon_lat_axes(
ax_surface, shared.MAP_PARAMS["full domain"], plot_data.bathy, theme
)
return fig, ax_surface, x, y
def _plot_tracer_surface(ax, x, y, plot_data, var, cmap, theme):
"""
:param :py:class:`matplotlib.axes.Axes` ax:
:param :py:class:`numpy.ndarray` x:
:param :py:class:`numpy.ndarray` y:
:param :py:class:`types.SimpleNamespace` plot_data:
:param str var:
:param :py:class:`matplotlib.colors.ListedColormap` cmap:
:param :py:mod:`nowcast.figures.website_theme` theme:
:return: :py:class:`matplotlib.contour.QuadContourSet`,
:py:class:`matplotlib.contour.QuadContourSet`
"""
tracer = plot_data.day_avg_tracers.data_vars[var].isel(time_counter=0, deptht=0)
# tracer as filled contours
contour_set = ax.contourf(
x,
y,
tracer,
cmap=cmap,
levels=numpy.linspace(
numpy.floor(tracer.where(tracer > 0).min()),
numpy.floor(tracer.where(tracer > 0).max()),
20,
),
extend="max",
)
# land
ax.contourf(
x,
y,
plot_data.bathy.Bathymetry,
levels=(-0.01, 0.01),
colors=theme.COLOURS["land"],
)
# coastline
ax.contour(
x,
y,
plot_data.bathy.Bathymetry,
levels=(-0.01, 0.01),
colors=theme.COLOURS["coastline"],
)
# 1000m isobath
isobath = ax.contour(
x,
y,
plot_data.bathy.Bathymetry,
levels=(1000,),
colors=theme.COLOURS["contour lines"]["1000m isobath"],
)
return contour_set, isobath
def _surface_axes_labels(ax, plot_data, var, contour_set, isobath, theme):
"""
:param :py:class:`matplotlib.axes.Axes` ax:
:param :py:class:`types.SimpleNamespace` plot_data:
:param str var:
:param :py:class:`matplotlib.contour.QuadContourSet` contour_set:
:param :py:class:`matplotlib.contour.QuadContourSet` isobath:
:param :py:mod:`nowcast.figures.website_theme` theme:
:return: None
"""
# Colour bar labels
cbar = plt.colorbar(contour_set, ax=ax)
cbar.ax.axes.tick_params(
labelcolor=theme.COLOURS["cbar"]["tick labels"],
labelsize=theme.FONTS["cbar"]["tick labels"].get_size(),
)
long_name = plot_data.day_avg_tracers.data_vars[var].long_name
units = plot_data.day_avg_tracers.data_vars[var].units
cbar.set_label(
f"Surface {long_name.title()} [{units}]",
color=theme.COLOURS["cbar"]["label"],
fontproperties=theme.FONTS["cbar"]["label"],
)
plt.clabel(isobath, fmt={isobath.levels[0]: f"{isobath.levels[0]:.0f} m"})
# Axes title
time = plot_data.day_avg_tracers.temp.time_counter
year = time.dt.year.values[0]
month = time.dt.month.values[0]
day = time.dt.day.values[0]
ax.set_title(
f"{year}-{month:02d}-{day:02d}\n\n",
color=theme.COLOURS["text"]["figure title"],
fontproperties=theme.FONTS["figure title"],
fontsize=theme.FONTS["figure title"].get_size(),
)
# Axes aspect ratio from latitude
ax.set_aspect(
1 / numpy.cos(plot_data.day_avg_tracers.nav_lat.median() * numpy.pi / 180)
)
# Axes element colours
theme.set_axis_colors(ax)