Source code for ravenpy.utilities.nb_graphs

"""
This module contains functions creating web-friendly interactive graphics using holoviews.

The graphic outputs are meant to be displayed in a notebook.
In a console, use `hvplot.show(fig)` to render the figures.
"""

import matplotlib
import numpy as np
import xarray as xr
from matplotlib import pyplot as plt
from xclim.indices.stats import get_dist

try:
    import holoviews as hv
    import hvplot.xarray

    # from holoviews.streams import Buffer
    # from bokeh.models import Range1d, LinearAxis
except (ImportError, ModuleNotFoundError) as e:
    raise ImportError("Install holoviews and hvplot.") from e

hv.extension("bokeh")


[docs] def hydrographs(ds: xr.Dataset): """Return a graphic showing the discharge simulations and observations.""" basin_name = ds.basin_name.values[0] # selected basin name g = ds.q_sim.hvplot.line( x="time", line_width=1, label="Simulations", ylabel="Streamflow (m³/s)", xlabel="Time", title=basin_name, ) # Plot the observed streamflows if available if hasattr(ds, "q_obs"): g *= ds.q_obs.hvplot.line( x="time", line_width=1.5, color="k", label="Observations" ) return g
[docs] def mean_annual_hydrograph(ds: xr.Dataset): """Return a graphic showing the discharge simulations and observations.""" basin_name = ds.basin_name.values[0] # selected basin name mq_sim = ds.q_sim.groupby("time.dayofyear").mean() g = mq_sim.hvplot.line( x="dayofyear", line_width=1.5, label="Mean simulation", ylabel="Mean streamflow (m³/s)", xlabel="Day of year", title=basin_name, ) # Plot the observed streamflows if available if hasattr(ds, "q_obs"): mq_obs = ds.q_obs.groupby("time.dayofyear").mean() g *= mq_obs.hvplot.line( x="dayofyear", line_width=2, color="k", label="Mean observations" ) return g
[docs] def spaghetti_annual_hydrograph(ds: xr.Dataset): """Create a spaghetti plot of the mean hydrological cycle for one model simulations.""" basin_name = ds.basin_name.values[0] # selected basin name mq_sim = ds.q_sim.groupby("time.dayofyear").mean() g1 = mq_sim.hvplot.line( x="dayofyear", line_width=1.5, label="Mean simulation", ylabel="Mean streamflow (m³/s)", xlabel="Day of year", title=basin_name, ) g1 *= ds.q_sim.hvplot.line( x="time.dayofyear", by="time.year", line_width=1, label="Simulations", legend=False, ) # Plot the observed streamflows if available if hasattr(ds, "q_obs"): mq_obs = ds.q_obs.groupby("time.dayofyear").mean() g2 = mq_obs.hvplot.line( x="dayofyear", line_width=2, color="k", label="Mean observations" ) g2 *= ds.q_obs.hvplot.line( x="time.dayofyear", by="time.year", line_width=1, color="k", label="Observations", legend=False, ) return g1 + g2 return g1
[docs] def ts_fit_graph(ts: xr.DataArray, params: xr.DataArray) -> matplotlib.pyplot.Figure: """Create graphic showing a histogram of the data and the distribution fitted to it. The graphic contains one panel per watershed. Parameters ---------- ts : xr.DataArray Stream flow time series with dimensions (time, nbasins). params : xr.DataArray Fitted distribution parameters returned by `xclim.land.fit` indicator. Returns ------- matplotlib.pyplot.Figure Figure showing a histogram and the parameterized pdf. """ # Note: The hover tool could be customized to show the histogram count in addition to the frequency. n = ts.nbasins.size if n > 1: raise NotImplementedError ts = ts.isel(nbasins=0) params = params.isel(nbasins=0) if params.isnull().any(): raise ValueError("Null values in `params`.") # Using matplotlib's default binning strategy hist, bins, mh = plt.hist(ts, bins="auto", density=True) # Histogram graphic object h = hv.Histogram((hist, bins), kdims=ts.name, label="Histogram") # PDF domain mn = np.min(bins) mx = np.max(bins) q = np.linspace(mn, mx, 200) # Compute PDF dist = params.attrs["scipy_dist"] dc = get_dist(dist)(*params) # Works because dparams is the first dimension. pdf = xr.DataArray( data=dc.pdf(q), dims=(ts.name,) + params.dims[1:], coords={ts.name: q}, name="pdf", ) # PDF line label ps = ", ".join( [f"{key}={x:.1f}" for key, x in zip(params.dparams.data, params.values)] ) label = f"{dist}({ps})" # PDF graphic object p = pdf.hvplot.line(label=label, xlabel=ts.attrs["long_name"], color="orange") # Layout return (h * p).opts(hv.opts.Histogram(tools=["hover"]))