diff --git a/docs/conf.py b/docs/conf.py index 357afc7b8..fc7badce4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -83,7 +83,7 @@ "examples/_*.py", "examples/**/_*.py", # GPJax's notebook helper predates that naming convention and is imported by - # name (`from utils import use_mpl_style`), so it cannot simply be renamed. + # name (`from utils import clean_legend`), so it cannot simply be renamed. "examples/utils.py", # Image/style assets, plus one stray legacy module (static/jaxkern/main.py) # that source_suffix would otherwise read as a notebook. @@ -317,21 +317,11 @@ # GitHub Pages used to send. html_extra_path = ["_redirects", "_headers"] html_theme_options = { - # `accent_color` only accepts a radix ramp *name*. shibuya writes the value - # verbatim into `` and its stylesheet carries - # one `[data-accent-color=]` block per radix ramp, each mapping - # `--accent-1..12` onto that ramp. A hex value matches no block, so the whole - # accent ramp goes undefined -- confirmed in a browser: with - # `data-accent-color="#7a2e2a"` both `--accent-9` and the `--sy-c-link` it - # feeds compute to the empty string, the active sidebar entry drops back to - # body-text grey and code blocks lose their tint entirely. - # - # So the named ramp stays, and supplies the derived tints (code-block and - # admonition surfaces, hover states). `red` replaces the previous `crimson` - # because the brand is now #7a2e2a, a true red at hue 3 degrees; crimson is a - # pink-red at hue 348 and its tints read pink against it. The exact brand hex - # is pinned over `--accent-9` in stylesheets/extra.css. - "accent_color": "red", + # `accent_color` only accepts a radix ramp *name*: a hex value matches none of + # shibuya's `[data-accent-color=]` blocks and leaves `--accent-*` + # undefined. As in impulso, it names the token family, and + # stylesheets/extra.css re-tones the crimson scale to ledger oxblood. + "accent_color": "crimson", "color_mode": "auto", # follow the reader's light/dark preference "github_url": "https://github.com/QuantClimate/GPJax", "nav_links": [ diff --git a/docs/examples/backend.py b/docs/examples/backend.py index 33ccc5364..0b91c936b 100644 --- a/docs/examples/backend.py +++ b/docs/examples/backend.py @@ -27,11 +27,17 @@ # [official documentation](https://docs.kidger.site/equinox/). # +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% import typing as tp import equinox as eqx -from utils import use_mpl_style from gpjax.mean_functions import ( AbstractMeanFunction, Constant, @@ -72,7 +78,7 @@ def glue(*args, **kwargs): # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() cols = mpl.rcParams["axes.prop_cycle"].by_key()["color"] diff --git a/docs/examples/barycentres.py b/docs/examples/barycentres.py index 453e82546..3f4fb4bac 100644 --- a/docs/examples/barycentres.py +++ b/docs/examples/barycentres.py @@ -30,10 +30,16 @@ # significantly more favourable uncertainty estimation. # +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% import typing as tp -from utils import use_mpl_style import jax # Enable Float64 for more stable matrix inversions. @@ -60,7 +66,7 @@ def glue(*args, **kwargs): key = jr.key(123) # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() cols = plt.rcParams["axes.prop_cycle"].by_key()["color"] diff --git a/docs/examples/classification.py b/docs/examples/classification.py index fe3c5c24c..4c09bce96 100644 --- a/docs/examples/classification.py +++ b/docs/examples/classification.py @@ -25,9 +25,15 @@ # closed form, is covered in the [regression notebook](regression.py); everything that # follows is a consequence of losing that closed form. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% import equinox as eqx -from utils import use_mpl_style from gpjax.linalg import add_jitter, cholesky_factor from gpjax.parameters import val import jax @@ -57,7 +63,7 @@ identity_matrix = jnp.eye # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() key = jr.key(42) cols = plt.rcParams["axes.prop_cycle"].by_key()["color"] diff --git a/docs/examples/collapsed_vi.py b/docs/examples/collapsed_vi.py index f22c2716b..d1108303f 100644 --- a/docs/examples/collapsed_vi.py +++ b/docs/examples/collapsed_vi.py @@ -32,9 +32,15 @@ # the uncollapsed bound of the # [sparse stochastic variational inference notebook](uncollapsed_vi.py). +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% # Enable Float64 for more stable matrix inversions. -from utils import use_mpl_style from jax import ( config, jit, @@ -54,7 +60,7 @@ # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() key = jr.key(42) diff --git a/docs/examples/constructing_new_kernels.py b/docs/examples/constructing_new_kernels.py index 6ce0edc6a..633b6804f 100644 --- a/docs/examples/constructing_new_kernels.py +++ b/docs/examples/constructing_new_kernels.py @@ -24,9 +24,15 @@ # to a GP prior; if not, our [introduction to kernels](intro_to_kernels.py) builds that # intuition first. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% # Enable Float64 for more stable matrix inversions. -from utils import use_mpl_style from gpjax.kernels.base import val from gpjax.kernels.computations import DenseKernelComputation from gpjax.parameters import PositiveReal @@ -49,7 +55,7 @@ # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() key = jr.key(42) diff --git a/docs/examples/deep_kernels.py b/docs/examples/deep_kernels.py index 6003285cc..604b8a2fc 100644 --- a/docs/examples/deep_kernels.py +++ b/docs/examples/deep_kernels.py @@ -26,9 +26,15 @@ # {cite:t}`wilson2016deep`, transforming the inputs to our # Gaussian process model's kernel through a neural network can offer a solution to this. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% import equinox as eqx -from utils import use_mpl_style from gpjax.kernels.computations import ( AbstractKernelComputation, DenseKernelComputation, @@ -58,7 +64,7 @@ # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() cols = mpl.rcParams["axes.prop_cycle"].by_key()["color"] key = jr.key(42) diff --git a/docs/examples/dual_svgp.py b/docs/examples/dual_svgp.py index 2918d7171..d342f145d 100644 --- a/docs/examples/dual_svgp.py +++ b/docs/examples/dual_svgp.py @@ -31,6 +31,13 @@ # denotes the stored sites; $\mathbf{a}_i = # \mathbf{K}_{zz}^{-1}\mathbf{k}_z(x_i)$. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% # Enable Float64 for more stable matrix inversions. import time @@ -45,7 +52,7 @@ import matplotlib.pyplot as plt import optax as ox import paramax -from utils import clean_legend, use_mpl_style +from utils import clean_legend config.update("jax_enable_x64", True) @@ -67,7 +74,7 @@ key = jr.key(123) # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() cols = mpl.rcParams["axes.prop_cycle"].by_key()["color"] diff --git a/docs/examples/graph_kernels.py b/docs/examples/graph_kernels.py index 6811745b3..6d5f2b08d 100644 --- a/docs/examples/graph_kernels.py +++ b/docs/examples/graph_kernels.py @@ -25,10 +25,16 @@ # kernels supported within GPJax, see the # [kernels notebook](constructing_new_kernels.py). +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% import random -from utils import use_mpl_style # Enable Float64 for more stable matrix inversions. from jax import config @@ -52,7 +58,7 @@ def glue(*args, **kwargs): # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() key = jr.key(42) diff --git a/docs/examples/heteroscedastic_inference.py b/docs/examples/heteroscedastic_inference.py index 61f3d428c..8f4439ca0 100644 --- a/docs/examples/heteroscedastic_inference.py +++ b/docs/examples/heteroscedastic_inference.py @@ -46,6 +46,13 @@ # moments of each into an ELBO. For non-Gaussian likelihoods the same structure # remains; only the expected log-likelihood changes. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% tags=["remove-cell"] import os @@ -60,7 +67,6 @@ import matplotlib.pyplot as plt import optax as ox -from utils import use_mpl_style import gpjax as gpx from gpjax.likelihoods import ( HeteroscedasticGaussian, @@ -76,7 +82,7 @@ config.update("jax_enable_x64", True) -use_mpl_style() +gpx.plotting.use_style() key = jr.key(123) cols = mpl.rcParams["axes.prop_cycle"].by_key()["color"] diff --git a/docs/examples/intro_to_gps.py b/docs/examples/intro_to_gps.py index 28dda00e0..f02e7b42f 100644 --- a/docs/examples/intro_to_gps.py +++ b/docs/examples/intro_to_gps.py @@ -120,6 +120,13 @@ # # We can plot three different parameterisations of this density. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% import warnings @@ -131,13 +138,11 @@ import pandas as pd import seaborn as sns -from utils import ( - confidence_ellipse, - use_mpl_style, -) +from gpjax import plotting +from utils import confidence_ellipse # set the default style for plotting -use_mpl_style() +plotting.use_style() key = jr.key(42) diff --git a/docs/examples/intro_to_kernels.py b/docs/examples/intro_to_kernels.py index 2bca91465..73e168281 100644 --- a/docs/examples/intro_to_kernels.py +++ b/docs/examples/intro_to_kernels.py @@ -21,11 +21,17 @@ # # In this guide we provide an introduction to kernels, and the role they play in Gaussian process models. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% # Enable Float64 for more stable matrix inversions. from pathlib import Path -from utils import use_mpl_style from gpjax.typing import Array from jax import config import jax.numpy as jnp @@ -50,7 +56,7 @@ key = jr.key(42) # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() cols = mpl.rcParams["axes.prop_cycle"].by_key()["color"] # %% [markdown] diff --git a/docs/examples/likelihoods_guide.py b/docs/examples/likelihoods_guide.py index dddebe37f..ef2efc1e6 100644 --- a/docs/examples/likelihoods_guide.py +++ b/docs/examples/likelihoods_guide.py @@ -72,6 +72,13 @@ # these methods in the forthcoming sections, but first, we will show how to instantiate # a likelihood object. To do this, we'll need a dataset. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% mystnb={"figure": {"caption": "Fifty noisy observations of a sinusoid, shown alongside the latent function that generated them.", "name": "fig-likelihoods-guide-data"}} import jax @@ -81,14 +88,13 @@ import jax.random as jr import matplotlib.pyplot as plt -from utils import use_mpl_style import gpjax as gpx config.update("jax_enable_x64", True) # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() cols = plt.rcParams["axes.prop_cycle"].by_key()["color"] key = jr.key(42) diff --git a/docs/examples/multioutput.py b/docs/examples/multioutput.py index 2ece5d6ff..aa16b0068 100644 --- a/docs/examples/multioutput.py +++ b/docs/examples/multioutput.py @@ -31,8 +31,14 @@ # coregionalization matrix to see what the model has discovered about the output # structure. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% -from utils import use_mpl_style from jax import config import jax.numpy as jnp import jax.random as jr @@ -46,7 +52,7 @@ import gpjax as gpx key = jr.key(42) -use_mpl_style() +gpx.plotting.use_style() cols = mpl.rcParams["axes.prop_cycle"].by_key()["color"] # %% [markdown] diff --git a/docs/examples/natgrads.py b/docs/examples/natgrads.py index 16fae1e2c..39d9b90bd 100644 --- a/docs/examples/natgrads.py +++ b/docs/examples/natgrads.py @@ -31,6 +31,13 @@ # [dual sparse GP notebook](dual_svgp.py) applies the same ideas to site # parameters. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% # Enable Float64 for more stable matrix inversions. import time @@ -45,7 +52,7 @@ import matplotlib.pyplot as plt import optax as ox import paramax -from utils import clean_legend, use_mpl_style +from utils import clean_legend config.update("jax_enable_x64", True) @@ -65,7 +72,7 @@ key = jr.key(123) # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() cols = mpl.rcParams["axes.prop_cycle"].by_key()["color"] diff --git a/docs/examples/natural_gradients.py b/docs/examples/natural_gradients.py index 4d7cf7f2d..fc1416112 100644 --- a/docs/examples/natural_gradients.py +++ b/docs/examples/natural_gradients.py @@ -82,6 +82,13 @@ # [stochastic sparse GP notebook](uncollapsed_vi.py) first — everything below # assumes the SVGP evidence lower bound. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% import equinox as eqx import jax @@ -93,7 +100,7 @@ import matplotlib as mpl import matplotlib.pyplot as plt import paramax -from utils import clean_legend, use_mpl_style +from utils import clean_legend config.update("jax_enable_x64", True) @@ -120,7 +127,7 @@ key = jr.key(123) # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() cols = mpl.rcParams["axes.prop_cycle"].by_key()["color"] diff --git a/docs/examples/numpyro_integration.py b/docs/examples/numpyro_integration.py index 6590bdb9c..10df140a8 100644 --- a/docs/examples/numpyro_integration.py +++ b/docs/examples/numpyro_integration.py @@ -25,6 +25,13 @@ # scenario where we have a structured mean function in the form of a linear model, and a GP # capturing the residuals. We will infer the parameters of both the linear model and the GP jointly. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% tags=["remove-cell"] import os @@ -32,7 +39,6 @@ ci = os.environ.get("GPJAX_DOCS_CI") == "1" # %% -from utils import use_mpl_style import gpjax as gpx from jax import config import jax.numpy as jnp @@ -49,7 +55,7 @@ config.update("jax_enable_x64", True) -use_mpl_style() +gpx.plotting.use_style() cols = mpl.rcParams["axes.prop_cycle"].by_key()["color"] key = jr.key(123) diff --git a/docs/examples/oak.py b/docs/examples/oak.py index 2f610b191..9b4815f5f 100644 --- a/docs/examples/oak.py +++ b/docs/examples/oak.py @@ -36,13 +36,19 @@ # # We illustrate the full workflow on the UCI Auto MPG dataset. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% # Enable Float64 for more stable matrix inversions. from jax import config config.update("jax_enable_x64", True) -from utils import use_mpl_style import jax.numpy as jnp import jax.random as jr from jaxtyping import install_import_hook @@ -60,7 +66,7 @@ ) key = jr.key(123) -use_mpl_style() +gpx.plotting.use_style() colours = mpl.rcParams["axes.prop_cycle"].by_key()["color"] # %% [markdown] diff --git a/docs/examples/oceanmodelling.py b/docs/examples/oceanmodelling.py index a4203fd49..3d51e3da5 100644 --- a/docs/examples/oceanmodelling.py +++ b/docs/examples/oceanmodelling.py @@ -33,10 +33,16 @@ # surface drifter trajectories from the Gulf of Mexico spanning 28 years. # +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% from pathlib import Path -from utils import use_mpl_style from gpjax.kernels.computations import DenseKernelComputation from jax import ( config, @@ -67,7 +73,7 @@ def glue(*args, **kwargs): # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() key = jr.key(42) diff --git a/docs/examples/oilmm.py b/docs/examples/oilmm.py index d8d876e49..ad5dff33d 100644 --- a/docs/examples/oilmm.py +++ b/docs/examples/oilmm.py @@ -43,10 +43,16 @@ # correlated North Atlantic wave-height outputs, optimises the model's parameters # via the OILMM log marginal likelihood, and visualises its predictions. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% from pathlib import Path -from utils import use_mpl_style from jax import config import jax.numpy as jnp import jax.random as jr @@ -61,7 +67,7 @@ import gpjax as gpx key = jr.key(123) -use_mpl_style() +gpx.plotting.use_style() cols = mpl.rcParams["axes.prop_cycle"].by_key()["color"] # %% [markdown] diff --git a/docs/examples/poisson.py b/docs/examples/poisson.py index e45960524..d7fc9532e 100644 --- a/docs/examples/poisson.py +++ b/docs/examples/poisson.py @@ -26,6 +26,13 @@ # [classification notebook](classification.py) settles for a point estimate of the # latent function and a Gaussian approximation around it, we sample it here instead. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% tags=["remove-cell"] import os @@ -37,7 +44,6 @@ import blackjax import equinox as eqx -from utils import use_mpl_style import jax from jax import config import jax.numpy as jnp @@ -56,7 +62,7 @@ config.update("jax_enable_x64", True) # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() cols = mpl.rcParams["axes.prop_cycle"].by_key()["color"] key = jr.key(42) diff --git a/docs/examples/regression.py b/docs/examples/regression.py index 6ca2c4ccb..7a9e870be 100644 --- a/docs/examples/regression.py +++ b/docs/examples/regression.py @@ -24,11 +24,15 @@ # [introduction to Gaussian processes](intro_to_gps.py) derives the same model from # Bayes' theorem. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% # Enable Float64 for more stable matrix inversions. -from utils import ( - use_mpl_style, -) from jax import config import jax.numpy as jnp import jax.random as jr @@ -36,7 +40,7 @@ import matplotlib as mpl import matplotlib.pyplot as plt -from utils import use_mpl_style, clean_legend +from utils import clean_legend config.update("jax_enable_x64", True) @@ -48,7 +52,7 @@ key = jr.key(123) # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() cols = mpl.rcParams["axes.prop_cycle"].by_key()["color"] diff --git a/docs/examples/spatial_linear_gp.py b/docs/examples/spatial_linear_gp.py index 132c68864..996aa234a 100644 --- a/docs/examples/spatial_linear_gp.py +++ b/docs/examples/spatial_linear_gp.py @@ -43,6 +43,13 @@ # masks a non-linear residual. Composing models lets us represent both # behaviours without forcing a single mechanism to fit every feature of the data. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% tags=["remove-cell"] import os @@ -65,12 +72,11 @@ Predictive, ) -from utils import use_mpl_style import gpjax as gpx jax.config.update("jax_enable_x64", True) -use_mpl_style() +gpx.plotting.use_style() cols = mpl.rcParams["axes.prop_cycle"].by_key()["color"] diff --git a/docs/examples/state_space_gps.py b/docs/examples/state_space_gps.py index 29ea147d3..3ea0223e2 100644 --- a/docs/examples/state_space_gps.py +++ b/docs/examples/state_space_gps.py @@ -37,6 +37,13 @@ # 4. contrast the smoothed posterior with the *causal* (filtered) one, and # 5. confirm empirically that inference scales linearly in $N$. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% tags=["remove-cell"] import os @@ -47,7 +54,7 @@ # Enable Float64 for more stable matrix factorisations. from pathlib import Path -from utils import clean_legend, use_mpl_style +from utils import clean_legend import jax from jax import config import jax.numpy as jnp @@ -72,7 +79,7 @@ key = jr.key(123) # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() cols = mpl.rcParams["axes.prop_cycle"].by_key()["color"] # %% [markdown] diff --git a/docs/examples/uncollapsed_vi.py b/docs/examples/uncollapsed_vi.py index dd93ead97..1fb2ab90e 100644 --- a/docs/examples/uncollapsed_vi.py +++ b/docs/examples/uncollapsed_vi.py @@ -33,9 +33,15 @@ # [classification notebook](classification.py). +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% # Enable Float64 for more stable matrix inversions. -from utils import use_mpl_style from jax import config import jax.numpy as jnp import jax.random as jr @@ -54,7 +60,7 @@ key = jr.key(123) # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() cols = mpl.rcParams["axes.prop_cycle"].by_key()["color"] diff --git a/docs/examples/utils.py b/docs/examples/utils.py index 0409a37ab..0086fe555 100644 --- a/docs/examples/utils.py +++ b/docs/examples/utils.py @@ -1,8 +1,5 @@ -from pathlib import Path - from matplotlib import transforms from matplotlib.patches import Ellipse -import matplotlib.pyplot as plt import numpy as np @@ -74,8 +71,3 @@ def clean_legend(ax): ax.legend(by_label.values(), by_label.keys()) return ax - -def use_mpl_style(): - style_file = Path(__file__).parent / "gpjax.mplstyle" - plt.style.use(style_file) - diff --git a/docs/examples/xarray_workflow.py b/docs/examples/xarray_workflow.py index 28a3873f4..0801884ec 100644 --- a/docs/examples/xarray_workflow.py +++ b/docs/examples/xarray_workflow.py @@ -39,6 +39,13 @@ # # The module needs the optional extra: `pip install "gpjax[xarray]"`. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% from jax import config import jax.numpy as jnp @@ -46,7 +53,6 @@ from jaxtyping import install_import_hook import matplotlib.pyplot as plt import numpy as np -from utils import use_mpl_style import xarray as xr config.update("jax_enable_x64", True) @@ -56,7 +62,7 @@ from gpjax.xarray import from_xarray key = jr.key(42) -use_mpl_style() +gpx.plotting.use_style() # %% [markdown] # ## A synthetic temperature field diff --git a/docs/examples/yacht.py b/docs/examples/yacht.py index 2a68826c8..9bda58390 100644 --- a/docs/examples/yacht.py +++ b/docs/examples/yacht.py @@ -25,9 +25,15 @@ # contained in this notebook can be adapted to applied problems concerning datasets # other than the one presented here. +# %% tags=["remove-cell"] +import logging + +# The build host may not have the ledger fonts (Public Sans, Spectral); hide +# matplotlib's font fallback messages. +logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) + # %% # Enable Float64 for more stable matrix inversions. -from utils import use_mpl_style from jax import config import jax.numpy as jnp import jax.random as jr @@ -56,7 +62,7 @@ def glue(*args, **kwargs): # set the default style for plotting -use_mpl_style() +gpx.plotting.use_style() cols = mpl.rcParams["axes.prop_cycle"].by_key()["color"] key = jr.key(42) diff --git a/docs/reference/index.md b/docs/reference/index.md index 36f8190bd..e13c3bb99 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -24,6 +24,7 @@ linalg integrators scan summary +plotting typing citation ``` diff --git a/docs/reference/plotting.md b/docs/reference/plotting.md new file mode 100644 index 000000000..9e1499fa8 --- /dev/null +++ b/docs/reference/plotting.md @@ -0,0 +1,11 @@ +# Plotting + +```{eval-rst} +.. currentmodule:: gpjax.plotting + +.. autosummary:: + :toctree: generated/ + :nosignatures: + + use_style +``` diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index f5b83f963..9d5de487d 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -3,49 +3,86 @@ * Everything here is a survivor of the old mkdocs-material `extra.css`; the * ~110 lines that targeted `.md-*` classes, the Material colour variables and * the `permalinks.css` headerlink mask are all Material-only and were dropped - * with the theme. Shibuya's `accent_color` covers the palette that - * `--md-primary-fg-color` used to force. */ + * with the theme. Shibuya's `accent_color`, re-toned below, covers the palette + * that `--md-primary-fg-color` used to force. */ /* -- Brand accent ------------------------------------------------------------ * - * conf.py can only name a radix ramp (`accent_color = "red"`); shibuya has no - * way to take a hex. The ramp supplies every derived tint, and the exact brand - * hex is pinned over the one step that carries the visible accent. - * - * `--accent-9` is that step. shibuya defines `--sy-c-link: var(--accent-9)`, and - * `--sy-c-link` is what colours `.globaltoc > ul a.current`, `.localtoc > ul - * li.active > a` and (via `--yue-c-link-border`) the underline under every prose - * link, so overriding `--accent-9` alone reaches all of them. - * - * Scoped to `html[data-accent-color]` (specificity 0,2,0) to outrank shibuya's - * own `[data-accent-color=red]` block (0,1,0). It is deliberately NOT scoped to - * `html.light` / `html.dark`: shibuya switches colour mode with a class on this - * same element and never re-declares `--accent-9`, so one unscoped declaration - * holds in both modes. */ -html[data-accent-color] { - --gpjax-brand: #7a2e2a; - --accent-9: var(--gpjax-brand); - /* Local alias for the hand-styled pieces below. Note this is *not* a shibuya - variable -- the theme stylesheet never reads `--linkcolor`. */ - --linkcolor: var(--gpjax-brand); + * The same oxblood scale as impulso (../impulso/docs/stylesheets/extra.css), + * so the two sites share one accent. */ +/* Re-tone the theme's Radix "crimson" accent to the ledger's oxblood + (qc_core.plotting.COLORS.oxblood #7a2e2a light, #cf6f60 dark). shibuya + maps every --accent-* token from --crimson-* (conf.py `accent_color`), so + overriding the scale recolors links, active nav, hovers, and focus rings + in one place. Selectors mirror the theme's own; both blocks are needed + because this file loads after the theme, where a lone :root block would + also override the theme's .dark values. Steps follow Radix semantics: + 1-2 backgrounds, 3-5 washes, 6-8 borders, 9-10 solid, 11-12 text. */ +:root, +.light, +.light-theme { + --crimson-1: #fdf9f8; + --crimson-2: #fbf1ef; + --crimson-3: #f4e7e4; + --crimson-4: #eedad5; + --crimson-5: #e7cbc5; + --crimson-6: #ddb8b0; + --crimson-7: #cf9d93; + --crimson-8: #bd7d71; + --crimson-9: #7a2e2a; + --crimson-10: #5f231f; + --crimson-11: #7a2e2a; + --crimson-12: #43201d; + --crimson-a1: rgba(122, 46, 42, 0.03); + --crimson-a2: rgba(122, 46, 42, 0.05); + --crimson-a3: rgba(122, 46, 42, 0.1); + --crimson-a4: rgba(122, 46, 42, 0.15); + --crimson-a5: rgba(122, 46, 42, 0.21); + --crimson-a6: rgba(122, 46, 42, 0.28); + --crimson-a7: rgba(122, 46, 42, 0.38); + --crimson-a8: rgba(122, 46, 42, 0.52); + --crimson-a9: rgba(97, 6, 1, 0.84); + --crimson-a10: rgba(73, 5, 0, 0.88); + --crimson-a11: rgba(97, 6, 1, 0.84); + --crimson-a12: rgba(46, 7, 4, 0.9); + --crimson-contrast: #faf9f7; + --crimson-surface: #f8efeccc; } -/* Dark mode needs a lighter step of the same ramp. The brand hex is built for a - * white page: on shibuya's dark background (#111113) #7a2e2a measures 2.02:1, - * under both the 4.5:1 AA text threshold and the 3:1 threshold for UI. Links and - * the active sidebar entry are effectively unreadable. - * - * #d07b76 is the same colour lifted for a dark ground -- hue 3deg and saturation - * 0.49 are both unchanged, only lightness moves (0.32 -> 0.64), which is how a - * radix-style ramp is meant to be traversed. It measures 6.09:1, past AA and - * close to AAA. A true colour-theory complement (cyan-green, hue 183deg) was - * rejected: it reads as a different brand. - * - * `html.dark[data-accent-color]` is (0,2,1) against the (0,1,1) above, so it - * wins regardless of source order. shibuya always sets the mode class, including - * under `color_mode: "auto"`, so this holds when following the OS preference. */ -html.dark[data-accent-color] { - --gpjax-brand: #d07b76; +.dark, +.dark-theme { + --crimson-1: #1d1412; + --crimson-2: #241815; + --crimson-3: #35201b; + --crimson-4: #422620; + --crimson-5: #4e2c25; + --crimson-6: #5e352c; + --crimson-7: #754138; + --crimson-8: #955347; + --crimson-9: #cf6f60; + --crimson-10: #dd8171; + --crimson-11: #f2a291; + --crimson-12: #fbe1da; + --crimson-a1: rgba(207, 111, 96, 0.03); + --crimson-a2: rgba(207, 111, 96, 0.06); + --crimson-a3: rgba(207, 111, 96, 0.12); + --crimson-a4: rgba(207, 111, 96, 0.17); + --crimson-a5: rgba(207, 111, 96, 0.23); + --crimson-a6: rgba(207, 111, 96, 0.3); + --crimson-a7: rgba(207, 111, 96, 0.42); + --crimson-a8: rgba(207, 111, 96, 0.56); + --crimson-a9: rgba(252, 135, 117, 0.82); + --crimson-a10: rgba(254, 148, 130, 0.87); + --crimson-a11: rgba(255, 171, 153, 0.95); + --crimson-a12: rgba(255, 230, 222, 0.98); + --crimson-contrast: #201b19; + --crimson-surface: #35201b80; +} + +/* Local alias for the hand-styled pieces below. Note this is *not* a shibuya + variable -- the theme stylesheet never reads `--linkcolor`. */ +:root { + --linkcolor: var(--accent-9); } /* -- Notebook cells follow the site's colour mode ---------------------------- diff --git a/gpjax/__init__.py b/gpjax/__init__.py index 13cd56057..a0f257518 100644 --- a/gpjax/__init__.py +++ b/gpjax/__init__.py @@ -28,6 +28,7 @@ natural_gradients, objectives, parameters, + plotting, state_space, typing as typing, variational_families, @@ -82,6 +83,7 @@ "natural_gradients", "objectives", "parameters", + "plotting", "state_space", "summarise", "typing", diff --git a/docs/examples/gpjax.mplstyle b/gpjax/gpjax.mplstyle similarity index 100% rename from docs/examples/gpjax.mplstyle rename to gpjax/gpjax.mplstyle diff --git a/gpjax/plotting.py b/gpjax/plotting.py new file mode 100644 index 000000000..7f26cf7c8 --- /dev/null +++ b/gpjax/plotting.py @@ -0,0 +1,45 @@ +"""Matplotlib styling for GPJax figures. + +`use_style` applies QuantClimate's "Calibrated Ledger" style when the optional +`qc-core` package is installed, and the Matplotlib style that ships with GPJax +when it is not. Matplotlib is imported only when `use_style` is called, so it +stays an optional dependency of GPJax. +""" + +from pathlib import Path +import typing as tp + +__all__ = ["STYLE_PATH", "use_style"] + +#: The fallback Matplotlib style file that ships with GPJax. +STYLE_PATH: Path = Path(__file__).with_name("gpjax.mplstyle") + + +def use_style() -> tp.Literal["ledger", "gpjax"]: + """Apply the GPJax plotting style to Matplotlib globally. + + If `qc-core` is installed, this applies its Calibrated Ledger style, which + also registers the ledger colour names (for example, `color="oxblood"`). + Otherwise, it applies the style file at `STYLE_PATH`. + + Returns: + The name of the style that was applied: `"ledger"` or `"gpjax"`. + + Raises: + ImportError: If Matplotlib is not installed. + """ + try: + from matplotlib import style + except ImportError as error: + raise ImportError( + "gpjax.plotting needs Matplotlib. Install it with `pip install matplotlib`." + ) from error + + try: + from qc_core import plotting as qc_plotting + except ImportError: + style.use(STYLE_PATH) + return "gpjax" + + qc_plotting.use_ledger_style() + return "ledger" diff --git a/pyproject.toml b/pyproject.toml index 4e46de0f7..588106caa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,6 +72,7 @@ docs = [ "playwright>=1.49", # -- Example notebook dependencies (unchanged) -- "matplotlib>=3.7.1", + "qc-core>=0.0.4", # QuantClimate "Calibrated Ledger" plot style "seaborn>=0.12.2", "networkx>=3.0", "ipython>=8.11.0", @@ -91,6 +92,10 @@ xarray = [ [tool.uv] exclude-newer = "7 days" +# qc-core is QuantClimate's own package, published by PyPI trusted publishing +# from QuantClimate/core, so it skips the cooldown. A new qc-core release can +# then reach the docs on the day it ships. +exclude-newer-package = { qc-core = false } managed = true # PEP 735 dependency group. Must stay here rather than under `[tool.uv]`: diff --git a/tests/test_plotting.py b/tests/test_plotting.py new file mode 100644 index 000000000..0bf2eeb2c --- /dev/null +++ b/tests/test_plotting.py @@ -0,0 +1,37 @@ +import sys + +import pytest + +mpl = pytest.importorskip("matplotlib") + +from gpjax import plotting + + +def test_use_style_applies_ledger_style_when_qc_core_is_installed() -> None: + pytest.importorskip("qc_core") + with mpl.rc_context(): + assert plotting.use_style() == "ledger" + assert mpl.rcParams["figure.facecolor"] == "#faf9f7" + + +def test_use_style_falls_back_to_packaged_style_without_qc_core( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # A `None` entry in sys.modules makes `import qc_core` raise ImportError. + monkeypatch.setitem(sys.modules, "qc_core", None) + expected = mpl.rc_params_from_file(plotting.STYLE_PATH, use_default_template=False) + with mpl.rc_context(): + assert plotting.use_style() == "gpjax" + assert mpl.rcParams["axes.prop_cycle"] == expected["axes.prop_cycle"] + + +def test_use_style_raises_clear_error_without_matplotlib( + monkeypatch: pytest.MonkeyPatch, +) -> None: + monkeypatch.setitem(sys.modules, "matplotlib", None) + with pytest.raises(ImportError, match="needs Matplotlib"): + plotting.use_style() + + +def test_fallback_style_ships_with_the_package() -> None: + assert plotting.STYLE_PATH.is_file() diff --git a/uv.lock b/uv.lock index e6a75fde6..f62a5a867 100644 --- a/uv.lock +++ b/uv.lock @@ -20,6 +20,9 @@ resolution-markers = [ exclude-newer = "0001-01-01T00:00:00Z" # This has no effect and is included for backwards compatibility when using relative exclude-newer values. exclude-newer-span = "P7D" +[options.exclude-newer-package] +qc-core = false + [[package]] name = "absl-py" version = "2.3.1" @@ -827,6 +830,7 @@ docs = [ { name = "networkx" }, { name = "pandas" }, { name = "playwright" }, + { name = "qc-core" }, { name = "scikit-learn" }, { name = "seaborn" }, { name = "shibuya" }, @@ -896,6 +900,7 @@ requires-dist = [ { name = "pandas", marker = "extra == 'docs'", specifier = ">=1.5.3" }, { name = "paramax", specifier = ">=0.0.5" }, { name = "playwright", marker = "extra == 'docs'", specifier = ">=1.49" }, + { name = "qc-core", marker = "extra == 'docs'", specifier = ">=0.0.4" }, { name = "rich", specifier = ">=13.0.0" }, { name = "scikit-learn", marker = "extra == 'docs'", specifier = ">=1.5.1" }, { name = "scipy", specifier = ">=1.14" }, @@ -2913,6 +2918,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/01/1b/5dbe84eefc86f48473947e2f41711aded97eecef1231f4558f1f02713c12/pyzmq-27.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c9f7f6e13dff2e44a6afeaf2cf54cee5929ad64afaf4d40b50f93c58fc687355", size = 544862, upload-time = "2025-09-08T23:09:56.509Z" }, ] +[[package]] +name = "qc-core" +version = "0.0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "matplotlib" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/f9/455c4568d27a9103dce16d68b39034759837ac37315fced082590abc3e43/qc_core-0.0.4.tar.gz", hash = "sha256:57ca906269fee22a8bc63e10ab24e45a531fc925da910142bd0a786ead637871", size = 985836, upload-time = "2026-10-04T06:34:47.79Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/9d/5061a16bbe69e1a121ed12f3f9024571535cb04025fc6ac6bff964c96622/qc_core-0.0.4-py3-none-any.whl", hash = "sha256:1dab55e0cf797a5c88b2e2799009aee7d7306723562dc89879cbe14366f7c022", size = 985536, upload-time = "2026-10-04T06:34:46.535Z" }, +] + [[package]] name = "readme-renderer" version = "44.0"