Plotting¶
Publication-quality plotting utilities for SED fits, SFH recovery, corner plot comparisons, and convergence diagnostics tables. Designed for ApJ/MNRAS figures.
Style Setup¶
- tengri.analysis.plotting.setup_style(style='tengri')[source]¶
Configure matplotlib for publication-quality astronomy figures.
Defaults to a single cohesive style across every tengri notebook and example, built on top of the scienceplots
sciencepreset — the standard Nature/PRL/ApJ-compatible look (serif fonts, thin inward ticks on all four sides, frameless legends, no grid).- Parameters:
style (str) –
Which composite style to apply. One of:
"tengri"(default) —scienceplots.science+no-latex+ tengri-specific tick and font-size overrides. Safe everywhere (no system LaTeX required)."tengri-nature"— Nature-journal variant (single-column width, sans-serif Arial). Use for slide decks."tengri-minimal"— same tengri overrides but skip scienceplots so the style works whenscienceplotsis unavailable. Keeps the BAGPIPES-inspired look as a fallback.
- Return type:
None
Examples
>>> from tengri.analysis.plotting import setup_style >>> setup_style() # default: science + tengri overrides >>> setup_style("tengri-minimal") # fallback if scienceplots absent
SFH Plots¶
- tengri.analysis.plotting.plot_sfh(model, posterior, true_params=None, ax=None, color=None, label='Posterior', method='RT', show_draws=True, n_draws=30, ci_levels=(16, 84), xlim=(0, 13.5), show_mean_sfh=True)[source]¶
Plot SFH posterior with uncertainty band — BAGPIPES/Prospector style.
Features: - Filled 68% credible interval (not sample spaghetti) - Optional faint sample draws underneath - Truth as solid black line - Mean SFH backbone as dashed line - Clean axis labels with proper units
- Parameters:
model (SEDModel) – Fitted model instance.
posterior (Posterior) – Posterior from
Fitter.run().true_params (dict, optional) – Ground truth parameters for mock recovery plots.
ax (matplotlib Axes, optional) – Axes to plot on. Creates new figure if None.
color (str, optional) – Line color. Defaults to sampler-specific color from style sheet.
label (str) – Legend label. Default
"Posterior".method (str) – Sampler name for auto-coloring (
"RT","geoVI","NUTS","MAP").show_draws (bool) – If True, draw faint individual SFH samples. Default True.
n_draws (int) – Number of sample draws to plot. Default 30.
ci_levels (tuple of float) – Percentile levels for the filled credible interval. Default
(16, 84).xlim (tuple of float) – x-axis limits in lookback time. [Gyr]
show_mean_sfh (bool) – If True, overplot the smooth mean SFH backbone as a dashed line. Default True.
- Returns:
ax
- Return type:
matplotlib Axes
Examples
from tengri import plot_sfh ax = plot_sfh(model, posterior, true_params=true_params, method="NUTS") ax.figure.savefig("sfh_recovery.pdf")
- tengri.analysis.plotting.plot_sfh_comparison(model, results, true_params=None, methods=None, figsize=(15, 4))[source]¶
Side-by-side SFH recovery for multiple methods.
BAGPIPES-style multi-panel layout.
- Parameters:
model (SEDModel) – Fitted model instance.
results (dict) – Mapping from method name to
Posterior(e.g.{"NUTS": post, "VI": post2}).true_params (dict, optional) – Ground truth parameters for mock recovery plots.
methods (list of str, optional) – Panel order. Defaults to
list(results.keys()).figsize (tuple of float) – Figure size in inches. Default
(15, 4).
- Returns:
fig (matplotlib Figure)
axes (list of matplotlib Axes)
Examples
from tengri import plot_sfh_comparison results = {"NUTS": posterior_nuts, "VI": posterior_vi} fig, axes = plot_sfh_comparison(model, results, true_params=true_params) fig.savefig("sfh_comparison.pdf")
SED Plots¶
- tengri.analysis.plotting.plot_sed_fit(wave_eff, flux_obs, noise, flux_true=None, posterior_draws=None, ax=None, band_names=None, show_residuals=True)[source]¶
Plot observed photometry with model fit — Prospector style.
- Parameters:
wave_eff (array_like, shape (n_bands,)) – Effective filter wavelengths. [Angstrom]
flux_obs (array_like, shape (n_bands,)) – Observed photometric fluxes. [erg/s/cm²/Hz]
noise (array_like, shape (n_bands,)) – 1-sigma photometric uncertainties. [erg/s/cm²/Hz]
flux_true (array_like, shape (n_bands,), optional) – True (noiseless) fluxes for mock recovery plots.
posterior_draws (array_like, shape (n_draws, n_bands), optional) – Posterior predictive flux draws for uncertainty shading.
ax (matplotlib Axes, optional) – Axes to plot on. Creates new figure if None.
band_names (list of str, optional) – Filter names for axis labels.
show_residuals (bool) – If True, adds a residual panel below the main SED panel. Default True.
- Returns:
fig
- Return type:
matplotlib Figure
Examples
from tengri import plot_sed_fit import numpy as np wave = np.array([4800.0, 6200.0, 7700.0, 9000.0]) flux = np.array([1.2e-18, 1.8e-18, 2.1e-18, 1.9e-18]) noise = flux * 0.05 fig = plot_sed_fit(wave, flux, noise, show_residuals=False)
- tengri.analysis.plotting.plot_spectrum_fit(wave_obs, spec_obs, noise, spec_true=None, spec_draws=None, features=None, z=0.1)[source]¶
Plot spectroscopic fit with residuals — CIGALE style.
- Parameters:
wave_obs (array_like, shape (n_pix,)) – Observed-frame wavelength grid. [Angstrom]
spec_obs (array_like, shape (n_pix,)) – Observed spectrum flux density. [erg/s/cm²/Hz]
noise (array_like, shape (n_pix,)) – 1-sigma per-pixel uncertainties. [erg/s/cm²/Hz]
spec_true (array_like, shape (n_pix,), optional) – True (noiseless) spectrum for mock recovery plots.
spec_draws (array_like, shape (n_draws, n_pix), optional) – Posterior predictive spectrum draws for uncertainty shading.
features (dict, optional) – Rest-frame line/feature wavelengths to annotate, e.g.
{"Hα": 6563.0}.z (float) – Redshift for shifting feature wavelengths to observed frame. Default 0.1.
- Returns:
fig
- Return type:
matplotlib Figure
Examples
from tengri import plot_spectrum_fit fig = plot_spectrum_fit( wave_obs, spec_obs, noise, spec_draws=posterior_spec_draws, features={"Hα": 6563.0, "Hβ": 4861.0}, z=0.5, ) fig.savefig("spectrum_fit.pdf")
Corner Plots¶
- tengri.analysis.plotting.safe_corner(posterior, **kwargs)[source]¶
Wrapper around Posterior.plot_corner that handles degenerate posteriors.
- Parameters:
posterior (Posterior) – Fitted posterior object with a
plot_cornermethod.**kwargs – Additional keyword arguments passed to
posterior.plot_corner.
- Returns:
fig – Corner plot figure, or None if generation failed.
- Return type:
matplotlib.figure.Figure or None
Examples
from tengri import safe_corner fig = safe_corner(posterior, params=["sfh_dpl_alpha", "dust_tau_bc"]) if fig is not None: fig.savefig("corner.pdf")
- tengri.analysis.plotting.plot_corner_comparison(posteriors, labels, colors=None, truths=None, params=None)[source]¶
Overlay multiple posteriors on a single corner plot.
- Parameters:
posteriors (list of Posterior) – Posterior objects to overlay.
labels (list of str) – Legend labels for each posterior (e.g.
["NUTS", "VI", "MAP"]).colors (list of str, optional) – Colors for each posterior. Defaults to sampler palette.
truths (dict, optional) – True parameter values for recovery plots.
params (list of str, optional) – Parameter names to include. Defaults to all free parameters.
- Returns:
fig – Combined corner plot, or None if all posteriors failed.
- Return type:
matplotlib Figure or None
Examples
from tengri import plot_corner_comparison fig = plot_corner_comparison( [post_nuts, post_vi], labels=["NUTS", "VI"], truths=true_params, params=["sfh_dpl_alpha", "dust_tau_bc"], ) if fig is not None: fig.savefig("corner_comparison.pdf")
Diagnostics¶
- tengri.analysis.plotting.diagnostics_table(results, names=None)[source]¶
Print a formatted diagnostics comparison table.
- Parameters:
- Return type:
None
Examples
from tengri import diagnostics_table results = {"NUTS": posterior_nuts, "VI": posterior_vi} diagnostics_table(results) # Method Wall time ESS (min) ESS (med) Accept % # ---------------------------------------------------------------- # NUTS 42.3s 812 934 82.4% # VI 3.1s — — —
Constants¶
- tengri.analysis.plotting.COLORS = {'data': '#333333', 'g': '#008837', 'geovi': '#ff7f0e', 'i': '#fc8d59', 'map': '#888888', 'mcmc_nuts': '#2ca02c', 'mcmc_raytrace': '#1f77b4', 'mgvi': '#9467bd', 'model': '#d62728', 'nuts': '#2ca02c', 'r': '#d73027', 'rt': '#1f77b4', 'seq': ['#d4d4d4', '#a8a8a8', '#1f77b4', '#2ca02c', '#d62728'], 'sfh_full': '#ff7f0e', 'sfh_gp': '#2ca02c', 'sfh_mean': '#1f77b4', 'truth': '#1a1a1a', 'u': '#7b3294', 'vi': '#ff7f0e', 'vi_linear': '#9467bd', 'z': '#4575b4'}¶
dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s
(key, value) pairs
- dict(iterable) -> new dictionary initialized as if via:
d = {} for k, v in iterable:
d[k] = v
- dict(**kwargs) -> new dictionary initialized with the name=value pairs
in the keyword argument list. For example: dict(one=1, two=2)
- tengri.analysis.plotting.SDSS_WAVE_EFF = array([3551, 4686, 6166, 7480, 8932])¶
ndarray(shape, dtype=None, buffer=None, offset=0, strides=None, order=None) –
ndarray(shape, dtype=float, buffer=None, offset=0, strides=None, order=None)
An array object represents a multidimensional, homogeneous array of fixed-size items. An associated data-type object describes the format of each element in the array (its byte-order, how many bytes it occupies in memory, whether it is an integer, a floating point number, or something else, etc.)
Arrays should be constructed using array, zeros or empty (refer to the See Also section below). The parameters given here refer to a low-level method (ndarray(…)) for instantiating an array.
For more information, refer to the numpy module and examine the methods and attributes of an array.
- Parameters:
below) ((for the __new__ method; see Notes)
shape (tuple of ints) – Shape of created array.
dtype (data-type, optional) – Any object that can be interpreted as a numpy data type. Default is numpy.float64.
buffer (object exposing buffer interface, optional) – Used to fill the array with data.
offset (int, optional) – Offset of array data in buffer.
strides (tuple of ints, optional) – Strides of data in memory.
order ({'C', 'F'}, optional) – Row-major (C-style) or column-major (Fortran-style) order.
- tengri.analysis.plotting.T¶
Transpose of the array.
- Type:
ndarray
- tengri.analysis.plotting.data¶
The array’s elements, in memory.
- Type:
buffer
- tengri.analysis.plotting.dtype¶
Describes the format of the elements in the array.
- Type:
dtype object
- tengri.analysis.plotting.flags¶
Dictionary containing information related to memory use, e.g., ‘C_CONTIGUOUS’, ‘OWNDATA’, ‘WRITEABLE’, etc.
- Type:
- tengri.analysis.plotting.flat¶
Flattened version of the array as an iterator. The iterator allows assignments, e.g.,
x.flat = 3(See ndarray.flat for assignment examples; TODO).- Type:
numpy.flatiter object
- tengri.analysis.plotting.imag¶
Imaginary part of the array.
- Type:
ndarray
- tengri.analysis.plotting.real¶
Real part of the array.
- Type:
ndarray
- tengri.analysis.plotting.nbytes¶
The total number of bytes required to store the array data, i.e.,
itemsize * size.- Type:
- tengri.analysis.plotting.strides¶
The step-size required to move from one element to the next in memory. For example, a contiguous
(3, 4)array of typeint16in C-order has strides(8, 2). This implies that to move from element to element in memory requires jumps of 2 bytes. To move from row-to-row, one needs to jump 8 bytes at a time (2 * 4).- Type:
tuple of ints
- tengri.analysis.plotting.ctypes¶
Class containing properties of the array needed for interaction with ctypes.
- Type:
ctypes object
- tengri.analysis.plotting.base¶
If the array is a view into another array, that array is its base (unless that array is also a view). The base array is where the array data is actually stored.
- Type:
ndarray
See also
arrayConstruct an array.
zerosCreate an array, each element of which is zero.
emptyCreate an array, but leave its allocated memory unchanged (i.e., it contains “garbage”).
dtypeCreate a data-type.
numpy.typing.NDArrayAn ndarray alias generic w.r.t. its dtype.type <numpy.dtype.type>.
Notes
There are two modes of creating an array using
__new__:If buffer is None, then only shape, dtype, and order are used.
If buffer is an object exposing the buffer interface, then all keywords are interpreted.
No
__init__method is needed because the array is fully initialized after the__new__method.Examples
These examples illustrate the low-level ndarray constructor. Refer to the See Also section above for easier ways of constructing an ndarray.
First mode, buffer is None:
>>> import numpy as np >>> np.ndarray(shape=(2,2), dtype=float, order='F') array([[0.0e+000, 0.0e+000], # random [ nan, 2.5e-323]])
Second mode:
>>> np.ndarray((2,), buffer=np.array([1,2,3]), ... offset=np.int_().itemsize, ... dtype=int) # offset = 1*itemsize, i.e. skip first element array([2, 3])
- tengri.analysis.plotting.SPECTRAL_FEATURES = {'D4000': 4000.0, 'H$\\alpha$': 6563.0, 'H$\\beta$': 4861.0, 'H$\\delta$': 4102.0, 'H$\\gamma$': 4340.0, 'Ly$\\alpha$': 1216.0, 'Mg b': 5175.0, 'Na D': 5893.0, '[O III]': 5007.0}¶
dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object’s
(key, value) pairs
- dict(iterable) -> new dictionary initialized as if via:
d = {} for k, v in iterable:
d[k] = v
- dict(**kwargs) -> new dictionary initialized with the name=value pairs
in the keyword argument list. For example: dict(one=1, two=2)