primat.plotting — plotting helpers

primat.plotting

Shared plotting conventions for nuclide abundance curves, so that every front end (the notebooks/ figures and the Streamlit GUI) draws the same nuclide with the same colour and line style.

Convention

  • Colour encodes the chemical element (the proton number Z): every isotope of hydrogen is one colour, every isotope of helium another, and so on. This is what the eye groups first, so it carries the most salient coordinate.

  • Line style encodes the isotope within an element: the lightest isotope is solid, the next is dashed, then dash-dot, dotted, and progressively finer custom dash patterns. Isotopes are ranked by mass number A, so the ordering is reproducible across plots that show different subsets of the network.

  • The free neutron n is not a chemical element; it is drawn in black, solid, as a neutral reference curve.

The single public entry point is nuclide_styles(), which takes the list of nuclide names (as used throughout primat, e.g. ["n", "p", "H2", "He4", "Li7", ...]) and returns, for each name, a (color, linestyle, label) triple ready to pass to matplotlib’s plot(..., color=, linestyle=, label=).

Example

>>> from primat.plotting import nuclide_styles
>>> styles = nuclide_styles(["n", "p", "H2", "H3", "He3", "He4"])
>>> color, ls, label = styles["He4"]
>>> # color is the helium colour; ls distinguishes He4 from He3; label = '$^{4}$He'
primat.plotting.parse_nuclide(name)[source]

Split a primat nuclide name into (element_symbol, mass_number A).

Handles the two non-standard names used as bookkeeping aliases in the network: the free neutron "n" -> ("n", 1) (treated specially by the colour map) and the free proton "p" -> ("H", 1) (hydrogen-1). Every other name is of the form <element><A> (e.g. "He4", "Be7") and is split with a regex into its leading letters (the element symbol) and trailing digits (the mass number).

Parameters:

name (str) – Nuclide name as used in abundance_names / run.A keys.

Returns:

(str, int) – Element symbol and mass number. For the neutron the symbol is the sentinel "n" (not a real element), with A = 1.

Return type:

tuple[str, int]

Examples

>>> parse_nuclide("He4")
('He', 4)
>>> parse_nuclide("p")
('H', 1)
>>> parse_nuclide("n")
('n', 1)
primat.plotting.abundance_evolution_curves(evolution, A, names, t_grid)[source]

Compute per-nuclide A_i Y_i(t) curves ready to plot, backend-agnostic.

The single piece of curve-preparation logic shared by every front end that draws an abundance-evolution figure (the Streamlit GUI’s primat.gui.panels.render_evolution_panel() and the notebooks/ figures): build each nuclide’s Y(t) interpolator from a plain primat.evolution.EvolutionResult (via primat.evolution.Y_interpolator(), so it works on the result of either primat.backend.run_bbn() backend, never requiring a live Python PRIMAT instance), evaluate it on t_grid, weight by the mass number A, and drop non-positive points (a log-y plot cannot show them). Colour/linestyle/label come from nuclide_styles().

Parameters:
  • evolution (primat.evolution.EvolutionResult) – E.g. run_bbn(params, ...)["evolution"] (requires output_time_evolution=True).

  • A (dict) – Nuclide name -> mass number (e.g. {name: NZ[0] + NZ[1] for name, NZ in cfg.Nuclides.items()}, the same mapping primat.gui.run_view. GuiRun/primat.main.PRIMAT expose as .A).

  • names (sequence of str) – Nuclide names to compute a curve for (e.g. a subset of evolution.Y.keys()).

  • t_grid (np.ndarray) – Cosmic time [s] grid to evaluate each Y(t) interpolator on.

Returns:

dict{name: (t_masked, y_masked, color, linestyle, label)}t_masked/ y_masked are t_grid/A[name] * Y(t_grid) restricted to where the abundance is strictly positive.

Return type:

dict[str, tuple[‘NDArray[np.float64]’, ‘NDArray[np.float64]’, str, object, str]]

Example

>>> import numpy as np
>>> from primat.backend import run_bbn
>>> result = run_bbn({"network": "small", "output_time_evolution": True})
>>> A = {"n": 1, "p": 1, "H2": 2, "H3": 3, "He3": 3, "He4": 4, "Li7": 7, "Be7": 7}
>>> t = np.logspace(0, 5, 500)
>>> curves = abundance_evolution_curves(result["evolution"], A, result["evolution"].Y, t)
primat.plotting.nuclide_styles(names)[source]

Map each nuclide name to a (color, linestyle, label) triple.

Colour is fixed per chemical element (ELEMENT_COLORS); line style distinguishes isotopes of the same element, assigned by ascending mass number A so the lightest isotope present is solid, the next dashed, etc. (cycling through LINESTYLES). The free neutron is black/solid.

Because the isotope ranking is computed within each element from the names actually passed in, the same nuclide can in principle receive a different line style in two plots that show different isotope subsets – but the colour (the dominant visual cue) is always identical, and in practice the notebooks/GUI pass the full network’s nuclide list, so the styles are stable too.

Parameters:

names (sequence of str) – Nuclide names (e.g. run.abundance_names).

Returns:

dict{name: (color, linestyle, label)} for every input name.

Return type:

dict[str, tuple[str, object, str]]

Example

>>> styles = nuclide_styles(["n", "p", "H2", "He3", "He4"])
>>> styles["p"][0] == styles["H2"][0]   # same hydrogen colour
True
>>> styles["p"][1] != styles["H2"][1]   # different isotope line styles
True