magnus.plotting
Pre-packaged figures for Mag \(\nu\) s.
Every figure in notebooks/ used to be built by hand: roughly 25–40 lines of
gridspec_kw, tick locators, legend keywords and savefig per plot,
copy-pasted and lightly varied. This module collapses that into one call per
figure while reproducing the same output, so that switching an existing figure
over to it leaves the figure unchanged.
Taking stock of the fifty-odd figures showed that most of them are the same
figure with different data. Curves against baseline, curves against energy,
curves against a mixing angle, and the convergence studies of the
matrix-exponential notebook all share one shape: a set of curves plotted
against a swept variable, optionally over a short relative-error subpanel.
plot_curves() is that shape, and the plot_probability_vs_* helpers
are thin wrappers that only preset labels and limits.
plot_curves_stacked() is its small-multiples form: the same plot repeated
once per case down a shared abscissa, where the comparison is between panels.
The genuinely distinct layouts are the profile-plus-probability stack, the
bi-probability plane, and the oscillogram.
API conventions
The functions take named arguments for the quantities every figure has
(data, labels, limits, scales, ticks, title, legend placement, output path) and
explicit pass-through dictionaries for the long tail of Matplotlib
settings: legend_kw, grid_kw, savefig_kw, subplots_kw, and per
curve any Line2D keyword.
There is deliberately no bare **kwargs on any of these functions except
the three presets, which forward verbatim to plot_curves() under the name
**_forbidden, so a typo still raises and names the offending key. A
catch-all signature accepts a misspelled keyword in silence, and this project
has already paid for that once: oscprob’s keyword chain forwarded unknown
names down several layers before failing somewhere unrecognizable, which is why
magnus.oscprob.osc_prob() now raises on stray keys. Here every keyword is
either named in the signature – so a typo is a TypeError at the call
site – or lands in a dictionary destined for one specific Matplotlib call –
so a typo is an error from that call, naming the offending key. Nothing is
swallowed.
The module brings its own text and tick sizes (HOUSE_RC), so a figure looks the
same wherever it is drawn; it reads no matplotlibrc. Font family and LaTeX rendering
are left to the caller’s Matplotlib settings.
All functions return (fig, ax) so that the caller can keep customizing:
fig for figure-level work and saving, ax for anything Matplotlib
exposes on an axes. With return_probability=True, the functions that
compute through the Earth wrappers also return what they drew.
Requirements
Matplotlib ships with Magνs, so this module is available in any installation and needs nothing extra.
Added in version 1.0.0.
Attributes
Default figure size, in inches, used throughout the notebooks. |
|
Height of the relative-error subpanel, relative to the main panel. |
|
Legend keywords repeated verbatim on essentially every notebook figure. |
|
Grid keywords used by the notebooks. |
|
Default |
|
Text and tick sizes every plotting function draws with. |
Exceptions
Raised when |
Functions
|
Return the LaTeX label for an oscillation probability. |
|
Plot a set of curves against a swept variable, with an optional error subpanel. |
|
Plot small multiples: one panel per case, stacked over a shared abscissa. |
|
Plot oscillation probabilities against baseline. |
|
Plot oscillation probabilities against neutrino energy. |
|
Stack a matter-density panel above one or more probability panels. |
|
Overlay phase-averaged probabilities on the oscillating ones. |
|
Plot neutrino against antineutrino appearance probability. |
|
Plot an oscillogram: probability over zenith angle and energy. |
Module Contents
- exception magnus.plotting.MatplotlibNotFoundError[source]
Bases:
ImportErrorRaised when
magnus.plottingis used without Matplotlib installed.Added in version 1.0.0.
- magnus.plotting.HOUSE_FIGSIZE: Tuple[float, float] = (18.0, 9.0)[source]
Default figure size, in inches, used throughout the notebooks.
Added in version 1.0.0.
- magnus.plotting.HOUSE_RESIDUAL_HEIGHT: float = 0.3[source]
Height of the relative-error subpanel, relative to the main panel.
Added in version 1.0.0.
- magnus.plotting.HOUSE_LEGEND_KW: Dict[str, Any][source]
Legend keywords repeated verbatim on essentially every notebook figure.
Added in version 1.0.0.
- magnus.plotting.HOUSE_GRID_KW: Dict[str, Any][source]
Grid keywords used by the notebooks.
Added in version 1.0.0.
- magnus.plotting.HOUSE_SAVEFIG_KW: Dict[str, Any][source]
Default
savefig()keywords; figures go to../fig/as PDF.Added in version 1.0.0.
- magnus.plotting.HOUSE_RC: Dict[str, Any][source]
Text and tick sizes every plotting function draws with.
The module’s own defaults, the same values the notebooks use. Before, the module left these to the
matplotlibrcof wherever it ran, so outside the notebooks directory (the documentation included) the 18-by-9-inch figures got Matplotlib’s 10-point axis and tick labels. A value the caller has changed from Matplotlib’s default (inrcParamsor a style) is left alone.Added in version 1.2.0.
- magnus.plotting.prob_label(nu_i: int, nu_f: int, nubar: bool | None = False) str[source]
Return the LaTeX label for an oscillation probability.
A
prob_labelhelper was defined separately in several notebooks, with hand-writtenif/elifchains covering only the three active flavors. This version also covers the sterile states, so the sterile-neutrino notebook can use it too.Added in version 1.0.0.
- Parameters:
- Returns:
A LaTeX string such as
'$P_{\\nu_e \\to \\nu_\\mu}$'.- Return type:
- Raises:
ValueError – If either flavor index is not one of the known values.
Examples
import magnus.globaldefs as gd from magnus.plotting import prob_label print(prob_label(gd.NUMU, gd.NUE)) print(prob_label(gd.NUMU, gd.NUE, nubar=True))
$P_{\nu_\mu \to \nu_e}$ $P_{\bar{\nu}_\mu \to \bar{\nu}_e}$
- magnus.plotting.plot_curves(x: Sequence[float], curves: Sequence[Sequence[float] | Dict[str, Any]], *, xlabel: str | None = None, ylabel: str | None = None, title: str | None = None, xlim: Tuple[float, float] | None = None, ylim: Tuple[float, float] | None = None, xscale: str = 'linear', yscale: str = 'linear', xmajor: float | None = None, xminor: float | None = None, ymajor: float | None = None, yminor: float | None = None, residual: Sequence[float] | None = None, residual_label: str | None = None, residual_ylim: Tuple[float, float] | None = None, residual_ymajor: float | None = None, residual_yminor: float | None = None, residual_height: float = HOUSE_RESIDUAL_HEIGHT, residual_kw: Dict[str, Any] | None = None, annotations: Sequence[Dict[str, Any]] | None = None, legend: bool = True, legend_title: str | None = None, legend_loc: str | None = None, legend_kw: Dict[str, Any] | None = None, grid: bool = False, grid_kw: Dict[str, Any] | None = None, ylabel_labelpad: float = 25.0, title_fontsize: float = 20.0, figsize: Tuple[float, float] = HOUSE_FIGSIZE, subplots_kw: Dict[str, Any] | None = None, savefig: str | None = None, savefig_kw: Dict[str, Any] | None = None, tight_layout: bool = True)[source]
Plot a set of curves against a swept variable, with an optional error subpanel.
This is the workhorse: most notebook figures are an instance of it. The
plot_probability_vs_baselineandplot_probability_vs_energywrappers differ from it only in their preset labels and limits, and the convergence studies of the matrix-exponential notebook use it directly with a slab count or grid size on the abscissa.Added in version 1.0.0.
- Parameters:
x (sequence of float) – Abscissa, shared by every curve and by the residual panel.
curves (sequence) – One entry per curve. An entry is either a bare ordinate array, or a dict carrying the ordinate under
'y'plus anyLine2Dkeyword (label,color,ls,lw, …). Entries without an explicit color take the'C0','C1', … cycle in order.xlabel (str, optional) – Axis labels and title.
ylabelgoes on the main panel.ylabel (str, optional) – Axis labels and title.
ylabelgoes on the main panel.title (str, optional) – Axis labels and title.
ylabelgoes on the main panel.xlim (tuple of float, optional) – Axis limits.
xlimis applied to the residual panel too, so the two panels stay aligned.ylim (tuple of float, optional) – Axis limits.
xlimis applied to the residual panel too, so the two panels stay aligned.xscale (str, optional) – Matplotlib axis scales, e.g.
'log'. Default is'linear'.xscaleis applied to the residual panel as well.yscale (str, optional) – Matplotlib axis scales, e.g.
'log'. Default is'linear'.xscaleis applied to the residual panel as well.xmajor (float, optional) – Major/minor tick spacings for the main panel.
xminor (float, optional) – Major/minor tick spacings for the main panel.
ymajor (float, optional) – Major/minor tick spacings for the main panel.
yminor (float, optional) – Major/minor tick spacings for the main panel.
residual (sequence of float, optional) – If given, a short subpanel is added below the main panel and this is plotted in it – typically a relative error against a reference curve. The main panel’s tick labels are then suppressed, as in the notebooks.
residual_label (str, optional) – Ordinate label for the residual subpanel.
residual_ylim (tuple of float, optional) – Ordinate limits for the residual subpanel.
residual_ymajor (float, optional) – Tick spacings for the residual subpanel.
residual_yminor (float, optional) – Tick spacings for the residual subpanel.
residual_height (float, optional) – Height of the residual subpanel relative to the main panel. Default is
HOUSE_RESIDUAL_HEIGHT.residual_kw (dict, optional) – Extra
Line2Dkeywords for the residual curve. Defaults to a thin black solid line.annotations (sequence of dict, optional) – Text placed on the main panel. Each entry needs
'text'and'xy'(axes fractions by default) and may carry any otherannotate()keyword. Used by the BSM notebooks to record the parameter values a figure was made with.legend (bool, optional) – Whether to draw a legend. Default is
True; it is drawn only if at least one curve carries alabel.legend_title (str, optional) – Legend title.
legend_loc (str, optional) – Legend location.
legend_kw (dict, optional) – Extra keywords merged over
HOUSE_LEGEND_KWand forwarded tolegend().grid (bool, optional) – Whether to draw a grid. Default is
False.grid_kw (dict, optional) – Extra keywords merged over
HOUSE_GRID_KW.ylabel_labelpad (float, optional) – Padding of the main ordinate label. Default is
25.0.title_fontsize (float, optional) – Title font size. Default is
20.0.figsize (tuple of float, optional) – Figure size in inches. Default is
HOUSE_FIGSIZE.subplots_kw (dict, optional) – Extra keywords for
subplots().savefig (str, optional) – If given, the figure is written here.
savefig_kw (dict, optional) – Extra keywords merged over
HOUSE_SAVEFIG_KW.tight_layout (bool, optional) – Whether to call
tight_layout(). Default isTrue.
- Returns:
fig (matplotlib.figure.Figure) – The figure, ready for further customization or saving.
ax (matplotlib.axes.Axes or numpy.ndarray of Axes) – A single axes when there is no residual panel; an array of two (main, residual) when there is.
Examples
import matplotlib matplotlib.use('Agg') import numpy as np from magnus.plotting import plot_curves # starts away from zero: the reference appears in a denominator below, # and sin(0)**2 is exactly 0 L = np.linspace(50.0, 1000.0, 200) exact = np.sin(L / 200.0) ** 2 approx = exact + 1e-3 * np.cos(L / 50.0) fig, ax = plot_curves( L, [dict(y=approx, label='Magnus expansion', color='C1'), dict(y=exact, label='Standard formula', color='k', ls='--')], xlabel=r'Baseline, $L$ [km]', ylabel='Probability', ylim=(0, 1), residual=(approx - exact) / exact, residual_label=r'$\epsilon_{\rm rel}$', legend_title='Method', ) print(len(ax), ax[0].get_ylim())
2 (np.float64(0.0), np.float64(1.0))
- magnus.plotting.plot_curves_stacked(x: Sequence[float], panels: Sequence[Sequence[Sequence[float] | Dict[str, Any]]], *, xlabel: str | None = None, ylabel: str | None = None, title: str | None = None, xlim: Tuple[float, float] | None = None, ylim: Tuple[float, float] | None = None, xscale: str = 'linear', yscale: str = 'linear', xmajor: float | None = None, xminor: float | None = None, ymajor: float | None = None, yminor: float | None = None, panel_labels: Sequence[str] | None = None, panel_label_xy: Tuple[float, float] = (0.02, 0.1), panel_label_kw: Dict[str, Any] | None = None, annotations: Sequence[Dict[str, Any]] | None = None, legend: bool = True, legend_panel: int = 0, legend_proxies: Sequence[Dict[str, Any]] | None = None, legend_title: str | None = None, legend_loc: str | None = None, legend_kw: Dict[str, Any] | None = None, grid: bool = False, grid_kw: Dict[str, Any] | None = None, ylabel_kw: Dict[str, Any] | None = None, title_fontsize: float = 23.0, figsize: Tuple[float, float] | None = None, height_ratios: Sequence[float] | None = None, subplots_kw: Dict[str, Any] | None = None, savefig: str | None = None, savefig_kw: Dict[str, Any] | None = None, tight_layout: bool = True)[source]
Plot small multiples: one panel per case, stacked over a shared abscissa.
The layout for “the same quantity, once per configuration” – one panel per detector, per baseline, per zenith angle – where the comparison the reader makes is between panels, so every panel must share limits, scales and tick spacings exactly. Only the bottom panel keeps its tick labels and abscissa label, and the ordinate label is a single figure-level label spanning the stack.
This differs from
plot_probability_with_profile(), whose panels show different quantities (a density profile above a probability), and fromplot_curves(), whose optional second panel is a relative error rather than another instance of the same plot.Added in version 1.0.0.
Changed in version 1.2.0: Each panel’s curves are checked as
plot_curves()checks its curves: 1-D, finite, as long asx, and on a log y axis with at least one entry above 0 (issue #160 §12).- Parameters:
x (sequence of float) – Abscissa, shared by every panel.
panels (sequence of sequence) – One entry per panel, each a sequence of curves in the form
plot_curves()accepts: a bare ordinate array, or a dict carrying the ordinate under'y'plus anyLine2Dkeyword. Curves without an explicit color take the'C0','C1', … cycle within their panel, so the n-th curve of every panel matches by default.xlabel (str, optional) – Abscissa label, placed on the bottom panel only.
ylabel (str, optional) – Ordinate label. Drawn once for the whole stack with
supylabel(), since every panel shows the same quantity. Being figure-level, it takes nolabelpad; useylabel_kwfor its placement.title (str, optional) – Title, placed above the top panel.
xlim (tuple of float, optional) – Axis limits, applied to every panel.
ylim (tuple of float, optional) – Axis limits, applied to every panel.
xscale (str, optional) – Matplotlib axis scales, applied to every panel. Default
'linear'.yscale (str, optional) – Matplotlib axis scales, applied to every panel. Default
'linear'.xmajor (float, optional) – Major/minor tick spacings, applied to every panel.
xminor (float, optional) – Major/minor tick spacings, applied to every panel.
ymajor (float, optional) – Major/minor tick spacings, applied to every panel.
yminor (float, optional) – Major/minor tick spacings, applied to every panel.
panel_labels (sequence of str, optional) – One caption per panel, annotated inside it – the usual way of saying which case a panel is. Must match the number of panels.
panel_label_xy (tuple of float, optional) – Position of those captions, in axes fractions. Default
(0.02, 0.10).panel_label_kw (dict, optional) – Extra
annotate()keywords for them.annotations (sequence of dict, optional) – Free-form text. Each entry needs
'text'and'xy', may name a'panel'(index, default 0), and may carry any otherannotate()keyword.legend (bool, optional) – Whether to draw a legend. Default
True; drawn only if there is something to put in it.legend_panel (int, optional) – Which panel carries the legend. Default
0.legend_proxies (sequence of dict, optional) – Legend entries that describe a style shared across panels rather than any one curve – e.g. “solid: 3+1, dashed: standard” when the color varies from panel to panel. Each entry is a set of
Line2Dkeywords includinglabel, drawn as an empty proxy artist. When given, these replace the labels picked up from the curves themselves. This exists because the alternative, and what the notebooks did, is plotting dummy points outside the axis limits to manufacture legend handles.legend_title (str, optional) – Legend title and location.
legend_loc (str, optional) – Legend title and location.
legend_kw (dict, optional) – Extra keywords merged over
HOUSE_LEGEND_KW.grid (bool, optional) – Whether to draw a grid on every panel. Default
False.grid_kw (dict, optional) – Extra keywords merged over
HOUSE_GRID_KW.ylabel_kw (dict, optional) – Extra keywords for
supylabel().title_fontsize (float, optional) – Title font size. Default
23.0.figsize (tuple of float, optional) – Figure size in inches. Defaults to
HOUSE_FIGSIZE’s width and half its height per panel, which reproduces the notebooks’ proportions.height_ratios (sequence of float, optional) – Relative panel heights. Default: equal.
subplots_kw (dict, optional) – Extra keywords for
subplots().savefig (str, optional) – If given, the figure is written here.
savefig_kw (dict, optional) – Extra keywords merged over
HOUSE_SAVEFIG_KW.tight_layout (bool, optional) – Whether to call
tight_layout(). DefaultTrue.
- Returns:
fig (matplotlib.figure.Figure) – The figure, ready for further customization or saving.
ax (numpy.ndarray of Axes) – One axes per panel, top to bottom. Always an array, including for a single panel, so that indexing does not depend on the panel count.
Examples
import matplotlib matplotlib.use('Agg') import numpy as np from magnus.plotting import plot_curves_stacked E = np.linspace(1.0, 40.0, 200) cases = [0.5, 1.0, 2.0] panels = [ [dict(y=np.sin(k*E/8.0)**2, color=f'C{i}'), dict(y=np.sin(k*E/8.0)**2*0.8, color='0.7', ls='--')] for i, k in enumerate(cases) ] fig, ax = plot_curves_stacked( E, panels, xlabel=r'Neutrino energy, $E_\nu$ [GeV]', ylabel='Probability', ylim=(0, 1), xlim=(1.0, 40.0), panel_labels=[f'baseline {k:.1f} kton-yr' for k in cases], legend_proxies=[dict(label='3+1', color='k', ls='-'), dict(label=r'standard', color='k', ls='--')], ) print(ax.shape, ax[0].get_xticklabels()[0].get_text() == '')
(3,) True
- magnus.plotting.plot_probability_vs_baseline(distances: Sequence[float], curves: Sequence[Sequence[float] | Dict[str, Any]], *, nu_i: int | None = None, nu_f: int | None = None, nubar: bool | None = None, num_flavors: int | None = None, xlabel: str = 'Baseline, $L$ [km]', ylabel: str | None = None, ylim: Tuple[float, float] = (0.0, 1.0), xscale: str = 'log', ymajor: float | None = 0.1, yminor: float | None = 0.02, **_forbidden: Any)[source]
Plot oscillation probabilities against baseline.
A thin preset over
plot_curves(): log abscissa, ordinate on \([0, 1]\) with the notebooks’ tick spacings, and an ordinate label built from the flavor pair.Added in version 1.0.0.
Changed in version 1.2.0: Takes nubar, for the default ordinate label (issue #145 §2).
- Parameters:
distances (sequence of float) – Baselines [km].
curves (sequence) – As in
plot_curves().nu_i (int, optional) – Flavor pair, used to build the ordinate label via
prob_label()whenylabelis not given.nu_f (int, optional) – Flavor pair, used to build the ordinate label via
prob_label()whenylabelis not given.num_flavors (int, optional) – If given, prefixes the ordinate label with
'Two-','Three-','Four-'or'Five-neutrino probability'.nubar (bool, optional) – True if the curves are antineutrino probabilities, for the default ordinate label. Default: None, read as False.
xlabel (str, optional) – Abscissa label.
ylabel (str, optional) – Ordinate label; overrides the one built from the flavor pair.
ylim (tuple of float, optional) – Ordinate limits. Default is
(0.0, 1.0).xscale (str, optional) – Abscissa scale. Default is
'log'.ymajor (float, optional) – Ordinate tick spacings. Pass None to hand the axis back to Matplotlib’s own locator. Default: 0.10 and 0.02.
yminor (float, optional) – Ordinate tick spacings. Pass None to hand the axis back to Matplotlib’s own locator. Default: 0.10 and 0.02.
**_forbidden – Every remaining keyword of
plot_curves()is accepted and forwarded unchanged; unknown names raiseTypeErrorthere.
- Returns:
fig (matplotlib.figure.Figure)
ax (matplotlib.axes.Axes or numpy.ndarray of Axes)
Examples
import matplotlib matplotlib.use('Agg') import numpy as np import magnus.globaldefs as gd from magnus.plotting import plot_probability_vs_baseline L = np.logspace(1, 5, 200) P = np.sin(L / 3000.0) ** 2 fig, ax = plot_probability_vs_baseline( L, [dict(y=P, label='Magnus expansion')], nu_i=gd.NUE, nu_f=gd.NUE, num_flavors=2, xlim=(L[0], L[-1]), ) print(ax.get_xlabel())
Baseline, $L$ [km]
- magnus.plotting.plot_probability_vs_energy(energies: Sequence[float], curves: Sequence[Sequence[float] | Dict[str, Any]], *, nu_i: int | None = None, nu_f: int | None = None, nubar: bool | None = None, num_flavors: int | None = None, energy_unit: str = 'GeV', xlabel: str | None = None, ylabel: str | None = None, ylim: Tuple[float, float] = (0.0, 1.0), xscale: str = 'log', ymajor: float | None = 0.1, yminor: float | None = 0.02, **_forbidden: Any)[source]
Plot oscillation probabilities against neutrino energy.
The energy counterpart of
plot_probability_vs_baseline().Added in version 1.0.0.
Changed in version 1.2.0: Takes nubar, for the default ordinate label (issue #145 §2); energies that look like eV under a larger unit raise EnergyUnitWarning (issue #160 §12).
- Parameters:
energies (sequence of float) – Neutrino energies, in the unit named by
energy_unit.curves (sequence) – As in
plot_curves().nu_i (int, optional) – Flavor pair for the ordinate label.
nu_f (int, optional) – Flavor pair for the ordinate label.
num_flavors (int, optional) – Flavor count, for the ordinate label prefix.
nubar (bool, optional) – True if the curves are antineutrino probabilities, for the default ordinate label. Default: None, read as False.
energy_unit (str, optional) – Unit shown in the abscissa label. Default is
'GeV'.xlabel (str, optional) – Abscissa label; overrides the one built from
energy_unit.ylabel (str, optional) – Ordinate label.
ylim (tuple of float, optional) – Ordinate limits. Default is
(0.0, 1.0).xscale (str, optional) – Abscissa scale. Default is
'log'.ymajor (float, optional) – Ordinate tick spacings. Pass None to hand the axis back to Matplotlib’s own locator. Default: 0.10 and 0.02.
yminor (float, optional) – Ordinate tick spacings. Pass None to hand the axis back to Matplotlib’s own locator. Default: 0.10 and 0.02.
**_forbidden – Forwarded to
plot_curves().
- Returns:
fig (matplotlib.figure.Figure)
ax (matplotlib.axes.Axes or numpy.ndarray of Axes)
Examples
import matplotlib matplotlib.use('Agg') import numpy as np import magnus.globaldefs as gd from magnus.plotting import plot_probability_vs_energy E = np.logspace(-1, 1, 200) P = np.cos(1.0 / E) ** 2 fig, ax = plot_probability_vs_energy( E, [dict(y=P, label='Magnus expansion')], nu_i=gd.NUMU, nu_f=gd.NUE, xlim=(E[0], E[-1]), ) print(ax.get_xlabel())
Neutrino energy, $E_\nu$ [GeV]
- magnus.plotting.plot_probability_with_profile(x: Sequence[float], profiles: Sequence[Sequence[float] | Dict[str, Any]] | None = None, panels: Sequence[Sequence[Sequence[float] | Dict[str, Any]]] | None = None, *, trajectories: Sequence[Dict[str, Any]] | None = None, x_axis: str | None = None, x_unit: float | None = None, energy: float | None = None, nu_i: int | None = None, nu_f: int | None = None, nubar: bool | None = None, num_flavors: int | None = None, osc_params: Dict[str, float] | None = None, electron_fraction: float | None = None, electron_fraction_core: float | None = None, electron_fraction_mantle: float | None = None, electron_fraction_crust: float | None = None, electron_fraction_ocean: float | None = None, ratio_number_neutrons_to_protons: float | None = None, wrapper_kw: Dict[str, Any] | None = None, show_profile: bool | None = None, panel_per_trajectory: bool | None = None, return_probability: bool = False, xlabel: str | None = None, profile_ylabel: str = '$\\frac{N_e}{N_{\\rm Av}}$ [cm$^{-3}$]', panel_ylabels: Sequence[str | None] | None = None, panel_annotations: Sequence[str | None] | None = None, panel_annotation_xy: Tuple[float, float] = (0.02, 0.88), panel_annotation_fontsize: float = 23.0, shared_ylabel: str | None = None, shared_ylabel_labelpad: float = 20.0, title: str | None = None, title_fontsize: float = 23.0, xlim: Tuple[float, float] | None = None, xscale: str = 'log', xmajor: float | None = None, xminor: float | None = None, profile_ylim: Tuple[float, float] | None = None, profile_ymajor: float | None = None, profile_yminor: float | None = None, profile_height: float = 0.4, panel_ylim: Tuple[float, float] | None = (0.0, 1.0), panel_yscale: str = 'linear', panel_ymajor: float | None = 0.1, panel_yminor: float | None = 0.02, legend: bool = True, legend_title: str | None = None, legend_loc: str | None = None, legend_kw: Dict[str, Any] | None = None, legend_on_panel: int = 0, grid: bool = True, grid_kw: Dict[str, Any] | None = None, ylabel_labelpad: float = 25.0, figsize: Tuple[float, float] | None = None, subplots_kw: Dict[str, Any] | None = None, savefig: str | None = None, savefig_kw: Dict[str, Any] | None = None, tight_layout: bool = False)[source]
Stack a matter-density panel above one or more probability panels.
This is the layout of the long-baseline notebook: the electron-density profile along the trajectory on top, then one probability panel per detector or per profile, sharing the abscissa. With a single probability panel it is the profile-plus-probability figure of the introduction and the two-flavor notebooks.
It draws curves you computed, or, given
trajectoriesinstead ofprofilesandpanels, computes them through the Earth wrappers (magnus.oscprob.osc_prob_3nu_earth()and its two-, four- and five-flavor siblings), which declare the PREM layer boundaries as slab edges and use a layered electron fraction unless told otherwise. The density panel then shows the electron density those wrappers integrate along each trajectory.Added in version 1.0.0.
Changed in version 1.2.0: Computes the probabilities through the Earth wrappers when given
trajectories;profilesandpanelsdefault to None.Changed in version 1.2.0: Takes nubar (issue #145 §2), labels the computed probability panel (issue #146 §2), and computes NSI and LIV through the Earth wrappers (issue #146 §1).
- Parameters:
x (sequence of float) – Shared abscissa, or, when the panels have different abscissae, the one used by the profile panel. Individual curves may carry their own
x. When computing, baselines measured from where the neutrino enters the Earth (x_axis='baseline') or energies (x_axis='energy'), in units ofx_unit.profiles (sequence or None) – Curves for the density panel, in the form
plot_curves()takes. A curve may add its own abscissa under'x'. PassNone(or an empty sequence) to omit the density panel entirely and get a plain stack of probability panels sharing an abscissa – the layout the long-baseline notebook uses for a probability above its energy-smoothed version. Leave it None when computing.panels (sequence of sequence) – One entry per probability panel; each entry is a sequence of curves. Required unless computing, and then left None.
trajectories (sequence of dict, optional) – Compute instead of draw: one curve per entry, each a path through the Earth given as
'costhz'(the cosine of the zenith angle) or as'loc_ini'and'loc_fin'(two named locations ofmagnus.earth.loc_coords_dms, or their coordinates, joined by the chord between them). An entry may carry its own abscissa under'x'– a baseline grid ending at its own chord length, say – and anyLine2Dkeyword (color,ls,label…) for its curve.x_axis (str, optional) – What the abscissa is when computing,
'baseline'or'energy'.'baseline'(the default): one wrapper call per trajectory over all its baselines, atenergy; a baseline longer than the trajectory’s chord is an error.'energy': one call per trajectory over all its energies, at the full chord.x_unit (float, optional) – What one unit of the abscissa is, in the wrappers’ units: a length in \(\text{eV}^{-1}\) or an energy in eV. Default
magnus.globaldefs.UNIT_KMfor baselines (xin km) andmagnus.globaldefs.UNIT_GEVfor energies (xin GeV).energy (float, optional) – Neutrino energy [eV], required on the baseline axis and refused on the energy axis.
nu_i (int, optional) – Initial and final flavors when computing, e.g.
magnus.globaldefs.NUMUandmagnus.globaldefs.NUE.nu_f (int, optional) – Initial and final flavors when computing, e.g.
magnus.globaldefs.NUMUandmagnus.globaldefs.NUE.num_flavors (int, optional) – 2, 3, 4 or 5: which Earth wrapper computes the probabilities.
nubar (bool, optional) – True for antineutrinos. In compute mode it is also passed to the wrapper, so the curves and their label agree; a value contradicting
wrapper_kw['nubar']is refused. Default: None, which readswrapper_kw['nubar']in compute mode and False otherwise.osc_params (dict, optional) – Mixing parameters, passed to the wrapper as keywords:
sthandDm2(required) at two flavors; at three to five flavors any of the wrapper’s own (s12, …,D41…), the rest taking the wrapper’s defaults.magnus.globaldefs.load_nufit_params()returns such a dict.electron_fraction (float, optional) – The Earth’s composition, as the wrappers take it: one \(Y_e\) for the whole Earth, or per PREM layer. Default: None, the layered values. The density panel follows them too.
electron_fraction_core (float, optional) – The Earth’s composition, as the wrappers take it: one \(Y_e\) for the whole Earth, or per PREM layer. Default: None, the layered values. The density panel follows them too.
electron_fraction_mantle (float, optional) – The Earth’s composition, as the wrappers take it: one \(Y_e\) for the whole Earth, or per PREM layer. Default: None, the layered values. The density panel follows them too.
electron_fraction_crust (float, optional) – The Earth’s composition, as the wrappers take it: one \(Y_e\) for the whole Earth, or per PREM layer. Default: None, the layered values. The density panel follows them too.
electron_fraction_ocean (float, optional) – The Earth’s composition, as the wrappers take it: one \(Y_e\) for the whole Earth, or per PREM layer. Default: None, the layered values. The density panel follows them too.
ratio_number_neutrons_to_protons (float, optional) – Passed to the wrapper; matters from four flavors up. Default: None, derived from the same \(Y_e\).
wrapper_kw (dict, optional) – Any other wrapper keyword, e.g.
rtolornubar.show_profile (bool, optional) – Whether to draw the density panel when computing. Default: yes on the baseline axis, no on the energy axis, where the abscissa is not a position along the trajectory (so
Truethere is an error).panel_per_trajectory (bool, optional) – When computing, one probability panel per trajectory (the default) or all curves in one panel.
return_probability (bool, optional) – When computing, also return the probabilities drawn. Default False.
xlabel (str, optional) – Abscissa label, placed under the bottom panel. Default
'Baseline, $L$ [km]', or, when computing on the energy axis, a neutrino-energy label in GeV or MeV (for those twox_unitvalues).profile_ylabel (str, optional) – Ordinate label of the density panel.
panel_ylabels (sequence of str, optional) –
Ordinate labels for the probability panels. Entries may be
None. In compute mode, when neither this norshared_ylabelis given, every probability panel is labelled with the channel ofnu_iandnu_f(andnubar).Changed in version 1.2.0: That label is the probability symbol alone: the longer “Three-neutrino probability, …” ran into the density label at the house text size.
panel_annotations (sequence, optional) – Text placed inside each probability panel, one entry per panel, at
panel_annotation_xyin axes coordinates. An entry is a string, or a dict with'text'plus any otherannotate()keyword – abbox, for instance, when the text would otherwise sit over dense curves. Entries may beNone. The three-flavor notebook uses this to name the channel each panel shows, rather than repeating it in the ordinate label.panel_annotation_xy (tuple of float, optional) – Position of those annotations, in axes fractions. Default
(0.02, 0.88).panel_annotation_fontsize (float, optional) – Their font size. Default is
23.0.shared_ylabel (str, optional) – A single ordinate label spanning the whole stack, drawn on a frameless overlay axes. Use it instead of
panel_ylabelswhen every panel shows the same quantity.shared_ylabel_labelpad (float, optional) – Padding of that shared label. Default is
20.0.title (str, optional) – Title, placed above the top panel, which is the density panel only when
profilesis given.title_fontsize (float, optional) – Title font size. Default is
23.0.xscale (str, optional) – Shared abscissa scale. Default is
'log'.xmajor (float, optional) – Major/minor tick spacings on the shared abscissa. Only meaningful on a linear scale.
xminor (float, optional) – Major/minor tick spacings on the shared abscissa. Only meaningful on a linear scale.
profile_ylim (tuple of float, optional) – Ordinate limits of the density panel.
profile_ymajor (float, optional) – Tick spacings for the density panel.
profile_yminor (float, optional) – Tick spacings for the density panel.
profile_height (float, optional) – Height of the density panel relative to a probability panel. Default is
0.4.panel_ylim (tuple of float, optional) – Ordinate limits shared by the probability panels.
Noneautoscales.panel_yscale (str, optional) – Ordinate scale shared by the panels, e.g.
'log'when they carry something other than a probability. Default is'linear'.panel_ymajor (float, optional) – Tick spacings for the probability panels.
panel_yminor (float, optional) – Tick spacings for the probability panels.
legend (bool, optional) – Whether to draw a legend.
legend_title (str, optional) – Legend title.
legend_loc (str, optional) – Legend location.
legend_kw (dict, optional) – Extra keywords merged over
HOUSE_LEGEND_KW.legend_on_panel (int, optional) – Index of the probability panel carrying the legend, or
-1to give every panel its own. Default is0.grid (bool, optional) – Whether to draw grids. Default is
True.grid_kw (dict, optional) – Extra keywords merged over
HOUSE_GRID_KW.ylabel_labelpad (float, optional) – Padding of the density panel’s ordinate label. The probability panels use a fixed padding of 15 and do not read this. Default: 25.0.
figsize (tuple of float, optional) – Figure size. Defaults to
(18, 9)for one probability panel, growing by 4.5 inches per extra panel.subplots_kw (dict, optional) – Extra keywords for
subplots().savefig (str, optional) – If given, the figure is written here.
savefig_kw (dict, optional) – Extra keywords merged over
HOUSE_SAVEFIG_KW.tight_layout (bool, optional) – Whether to call
tight_layout. Default isFalse, matching the notebooks, whose explicitsubplots_adjustthis would override.
- Returns:
fig (matplotlib.figure.Figure)
ax (numpy.ndarray of Axes) – Length
1 + len(panels)with a density panel, which comes first; lengthlen(panels)without one.probability (list of numpy.ndarray) – Only with
return_probability=True: one array per trajectory, over its abscissa.
- Raises:
ValueError – If
panelsis missing or empty when drawing; iftrajectoriesis given together withprofilesorpanels, or any computing argument withouttrajectories; if a trajectory names neither or both ofcosthzand the two locations; ifx_axisis unknown,energyis missing on the baseline axis or given on the energy axis, orshow_profile=Trueon the energy axis; iftrajectoriesis empty, orwrapper_kwholdssource_depthordetector_depth; and for the channel, flavor-count and duplicate-keyword checks ofplot_oscillogram().
Examples
import matplotlib matplotlib.use('Agg') import numpy as np from magnus.plotting import plot_probability_with_profile L = np.logspace(2, 4, 300) n_e = 5.0 * np.exp(-L / 5000.0) P = np.sin(L / 900.0) ** 2 fig, ax = plot_probability_with_profile( L, [dict(y=n_e, color='C0')], [[dict(y=P, label='PREM')]], xlim=(L[0], L[-1]), profile_ylim=(0, 6), ) print(len(ax))
2
Computed through the Earth wrappers instead, along a chord that crosses the core, with the electron density it samples on top:
import matplotlib matplotlib.use('Agg') import numpy as np import magnus.globaldefs as gd from magnus.plotting import plot_probability_with_profile L = np.linspace(100.0, 11000.0, 200) # [km]; the chord is 11 467 km long fig, ax, P = plot_probability_with_profile( L, trajectories=[dict(costhz=-0.9, label=r'$\cos\theta_z = -0.9$')], energy=5.0*gd.UNIT_GEV, nu_i=gd.NUMU, nu_f=gd.NUE, num_flavors=3, xscale='linear', return_probability=True) print(len(ax), P[0].shape)
2
(200,)
- magnus.plotting.plot_probability_with_average(x: Sequence[float], probabilities: Sequence[float] | Sequence[Sequence[float]], averages: float | Sequence[float] | Sequence[Sequence[float]], *, labels: Sequence[str] | None = None, colors: Sequence[str] | None = None, average_label: str = 'Phase-averaged', oscillating_kw: Dict[str, Any] | None = None, average_kw: Dict[str, Any] | None = None, **_forbidden: Any)[source]
Overlay phase-averaged probabilities on the oscillating ones.
The figure of the averaged-probability notebook: rapidly oscillating curves, each with its phase-averaged value drawn through it as a dashed line of the same color – for instance what
magnus.oscprob.osc_prob()returns withaverage=True(the average overaverage_spread).Several channels are usually shown at once, so the legend carries one entry per channel plus a single entry explaining the dashed style, rather than repeating “averaged” once per curve.
Added in version 1.0.0.
- Parameters:
x (sequence of float) – Abscissa, typically baseline [km].
probabilities (sequence of float or sequence of sequence of float) – One oscillating probability, or several.
averages (float or sequence) – The corresponding phase-averaged values: a scalar per curve (broadcast across
x), or a full curve each. Must matchprobabilitiesin number.labels (sequence of str, optional) – Legend label per channel.
colors (sequence of str, optional) – Color per channel. Defaults to the
'C0','C1', … cycle; each average takes its channel’s color.average_label (str, optional) – Text of the single legend entry explaining the dashed lines.
oscillating_kw (dict, optional) – Extra
Line2Dkeywords applied to every oscillating or every averaged curve.average_kw (dict, optional) – Extra
Line2Dkeywords applied to every oscillating or every averaged curve.**_forbidden – Forwarded to
plot_probability_vs_baseline().
- Returns:
fig (matplotlib.figure.Figure)
ax (matplotlib.axes.Axes or numpy.ndarray of Axes)
- Raises:
ValueError – If the number of averages does not match the number of probabilities.
Examples
import matplotlib matplotlib.use('Agg') import numpy as np from magnus.plotting import plot_probability_with_average L = np.linspace(1.0, 1000.0, 500) P = np.sin(L / 7.0) ** 2 fig, ax = plot_probability_with_average(L, P, 0.5, xscale='linear') print(len(ax.get_lines()))
2
- magnus.plotting.plot_biprobability(prob_nu: Sequence[Sequence[float]] | None = None, prob_nubar: Sequence[Sequence[float]] | None = None, *, configurations: Sequence[Dict[str, Any]] | None = None, dcp: Sequence[float] | None = None, energy: float | None = None, nu_i: int | None = None, nu_f: int | None = None, num_flavors: int | None = None, osc_params: Dict[str, float] | None = None, electron_fraction: float | None = None, electron_fraction_core: float | None = None, electron_fraction_mantle: float | None = None, electron_fraction_crust: float | None = None, electron_fraction_ocean: float | None = None, ratio_number_neutrons_to_protons: float | None = None, wrapper_kw: Dict[str, Any] | None = None, return_probability: bool = False, labels: Sequence[str] | None = None, curve_kw: Sequence[Dict[str, Any]] | None = None, markers: Sequence[Dict[str, Any]] | None = None, xlabel: str | None = None, ylabel: str | None = None, title: str | None = None, title_fontsize: float = 20.0, xlim: Tuple[float, float] | None = None, ylim: Tuple[float, float] | None = None, xmajor: float | None = None, xminor: float | None = None, ymajor: float | None = None, yminor: float | None = None, annotations: Sequence[Dict[str, Any]] | None = None, legend: bool = True, legend_title: str = '$\\delta_{\\rm CP}$', legend_loc: str | None = None, legend_kw: Dict[str, Any] | None = None, figsize: Tuple[float, float] = (9.0, 9.0), subplots_kw: Dict[str, Any] | None = None, savefig: str | None = None, savefig_kw: Dict[str, Any] | None = None, tight_layout: bool = True)[source]
Plot neutrino against antineutrino appearance probability.
The bi-probability plane: for each configuration, the locus traced out as \(\delta_{\rm CP}\) runs over \([-\pi, \pi]\), with optional markers at selected phases.
It draws probabilities you computed, or, given
configurationsinstead, computes them through the Earth wrappers (magnus.oscprob.osc_prob_3nu_earth()and its four- and five-flavor siblings), which declare the PREM layer boundaries as slab edges and use a layered electron fraction unless told otherwise.Added in version 1.0.0.
Changed in version 1.2.0: Computes the probabilities through the Earth wrappers when given
configurations; markers may name a phase ('dcp');nu_iandnu_fset the default axis labels.- Parameters:
prob_nu (sequence of sequence of float) – One entry per curve, each a sequence of probabilities over the same grid of \(\delta_{\rm CP}\) values. Required unless computing, and then left None.
prob_nubar (sequence of sequence of float) – One entry per curve, each a sequence of probabilities over the same grid of \(\delta_{\rm CP}\) values. Required unless computing, and then left None.
configurations (sequence of dict, optional) – Compute instead of draw: one curve per entry, each a path through the Earth –
'costhz', with'L'[\(\text{eV}^{-1}\)] or, by default, the full chord; or'loc_ini'and'loc_fin', two locations joined by the chord between them – plus, optionally, its own'energy'and any other wrapper keyword for that curve alone (the inverted-ordering parameters for an inverted-ordering curve, say). A configuration’s entry overrides the sharedenergy,osc_params, composition orwrapper_kwvalue for its curve. Style the curves withlabelsandcurve_kw, as when drawing.dcp (sequence of float, optional) – The phases the curves run over, in the wrapper’s convention (radians, or degrees under
angles='deg'). Default: 100 points from \(-\pi\) to \(\pi\).energy (float, optional) – Neutrino energy [eV] shared by the configurations that give none.
nu_i (int, optional) – The channel: the default axis labels, and, when computing, what is computed. Default \(\nu_\mu \to \nu_e\). Give both or neither.
nu_f (int, optional) – The channel: the default axis labels, and, when computing, what is computed. Default \(\nu_\mu \to \nu_e\). Give both or neither.
num_flavors (int, optional) – 3, 4 or 5: which Earth wrapper computes the probabilities (two flavors have no CP phase).
osc_params (dict, optional) – Mixing parameters shared by all curves, as the wrapper takes them. A
dCPin it, or in a configuration, is replaced by the phases indcp(and a marker’s), so a set frommagnus.globaldefs.load_nufit_params()can be passed whole.electron_fraction (float, optional) – The Earth’s composition, as the wrappers take it. Default: None, the layered values.
electron_fraction_core (float, optional) – The Earth’s composition, as the wrappers take it. Default: None, the layered values.
electron_fraction_mantle (float, optional) – The Earth’s composition, as the wrappers take it. Default: None, the layered values.
electron_fraction_crust (float, optional) – The Earth’s composition, as the wrappers take it. Default: None, the layered values.
electron_fraction_ocean (float, optional) – The Earth’s composition, as the wrappers take it. Default: None, the layered values.
ratio_number_neutrons_to_protons (float, optional) – Passed to the wrapper; matters from four flavors up.
wrapper_kw (dict, optional) – Any other wrapper keyword, e.g.
rtol.return_probability (bool, optional) – Also return the probabilities drawn. Default False.
labels (sequence of str, optional) – Legend label per curve.
curve_kw (sequence of dict, optional) – Per-curve
Line2Dkeywords.markers (sequence of dict, optional) – Markers at selected phases. Each entry gives its position either as
'index'(a position along the curve) or as'xy'(an explicit coordinate pair, which is what you have when the marked phases were computed separately from the curve) or, when computing, as'dcp'(a phase, computed for each curve it marks). Optionally'marker','label','filled'and'curve'(which curve it belongs to, default all).xlabel (str, optional) – Axis labels. Default to the
nu_i,nu_fpair.ylabel (str, optional) – Axis labels. Default to the
nu_i,nu_fpair.title (str, optional) – Title.
title_fontsize (float, optional) – Title font size.
xmajor (float, optional) – Tick spacings.
xminor (float, optional) – Tick spacings.
ymajor (float, optional) – Tick spacings.
yminor (float, optional) – Tick spacings.
annotations (sequence of dict, optional) – Passed to
annotate(); each entry needs'text'and'xy', and may carry any other annotate keyword. Coordinates are axes fractions.legend (bool, optional) – Whether to draw a legend.
legend_title (str, optional) – Legend title. Default is
'$\\delta_{\\rm CP}$'.legend_loc (str, optional) – Legend location.
legend_kw (dict, optional) – Extra keywords merged over
HOUSE_LEGEND_KW.figsize (tuple of float, optional) – Figure size. Default is
(9.0, 9.0), the square panel this plot uses.subplots_kw (dict, optional) – Extra keywords for
subplots().savefig (str, optional) – If given, the figure is written here.
savefig_kw (dict, optional) – Extra keywords merged over
HOUSE_SAVEFIG_KW.tight_layout (bool, optional) –
Whether to call
tight_layout. Default isTrue.Changed in version 1.2.0: Default
True: at the house text size the ordinate label was cut off.
- Returns:
fig (matplotlib.figure.Figure)
ax (matplotlib.axes.Axes)
prob_nu, prob_nubar (numpy.ndarray or sequence) – Only with
return_probability=True: the probabilities drawn, arrays of shape(len(configurations), len(dcp))when computed, the inputs as given otherwise.
- Raises:
ValueError – If the two probabilities have different numbers of curves, or one is missing when drawing; if
configurationsis given together with them, or a computing argument withoutconfigurations; if a marker gives none or more than one ofindex,xyanddcp, ordcpwhen drawing; if a configuration has no energy, no geometry or both geometries,Lwith two locations, or a per-point keyword (nubar,nu_i,nu_f); if only one ofnu_i,nu_fis given; and for the flavor-count and duplicate-keyword checks ofplot_oscillogram(), here withnum_flavors3, 4 or 5.
Examples
import matplotlib matplotlib.use('Agg') import numpy as np from magnus.plotting import plot_biprobability d = np.linspace(-np.pi, np.pi, 100) P_nu = 0.05 + 0.02 * np.sin(d) P_nubar = 0.04 + 0.02 * np.sin(d + 0.4) fig, ax = plot_biprobability([P_nu], [P_nubar], labels=['NO']) print(ax.get_xlabel())
$P_{\nu_\mu \to \nu_e}$Computed through the Earth wrappers instead, from Fermilab to Homestake at 2 GeV, both orderings, with the phase \(\delta_{\rm CP} = 0\) marked:
import matplotlib matplotlib.use('Agg') import numpy as np import magnus.globaldefs as gd from magnus.plotting import plot_biprobability where = dict(loc_ini='fermilab', loc_fin='homestake') fig, ax, P_nu, P_nubar = plot_biprobability( configurations=[dict(where, **gd.load_nufit_params('NuFIT 6.1', 'NO')), dict(where, **gd.load_nufit_params('NuFIT 6.1', 'IO'))], dcp=np.linspace(-np.pi, np.pi, 25), energy=2.0*gd.UNIT_GEV, num_flavors=3, labels=['NO', 'IO'], markers=[dict(dcp=0.0, marker='*', label='0')], return_probability=True) print(P_nu.shape)
(2, 25)
- magnus.plotting.plot_oscillogram(costhz: Sequence[float], log10_energy: Sequence[float], probability: Sequence[Sequence[float]] | None = None, *, nu_i: int | None = None, nu_f: int | None = None, nubar: bool | None = None, num_flavors: int | None = None, osc_params: Dict[str, float] | None = None, electron_fraction: float | None = None, electron_fraction_core: float | None = None, electron_fraction_mantle: float | None = None, electron_fraction_crust: float | None = None, electron_fraction_ocean: float | None = None, ratio_number_neutrons_to_protons: float | None = None, wrapper_kw: Dict[str, Any] | None = None, return_probability: bool = False, levels: int = 120, cmap: str = 'plasma', xlabel: str = 'Zenith angle, $\\cos(\\theta_z)$', ylabel: str = 'Neutrino energy, $\\log_{10}(E_\\nu/{\\rm GeV})$', cbar_label: str | None = None, cbar_label_prefix: str = '', cbar_fontsize: float = 25.0, cbar_labelsize: float = 25.0, annotation: str | None = None, annotation_fontsize: float = 23.0, xlim: Tuple[float, float] | None = None, ylim: Tuple[float, float] | None = None, xmajor: float | None = 0.2, xminor: float | None = 0.02, ymajor: float | None = 0.1, yminor: float | None = 0.02, figsize: Tuple[float, float] = (9.0, 9.0), contourf_kw: Dict[str, Any] | None = None, subplots_kw: Dict[str, Any] | None = None, savefig: str | None = None, savefig_kw: Dict[str, Any] | None = None, tight_layout: bool = False)[source]
Plot an oscillogram: probability over zenith angle and energy.
A filled contour map of the oscillation probability in the plane of \(\cos\theta_z\) (equivalently, baseline through the Earth) and \(\log_{10} E_\nu\), with a color bar and the channel annotated in the corner over a white stroke so it stays legible against the color map.
Given a
probabilityarray, it draws it. Given none, it computes it first through the Earth wrappers (magnus.oscprob.osc_prob_3nu_earth()and its two-, four- and five-flavor siblings), one call per zenith angle over the whole energy array, so each is an energy scan the energy-batched engine answers. The wrappers declare the PREM layer boundaries as slab edges and use a layered electron fraction unless it is overridden here.Added in version 1.0.0.
Changed in version 1.2.0:
probabilityis optional: without it, the oscillogram is computed through the Earth wrappers. Addsnum_flavors,osc_params, the electron-fraction keywords,wrapper_kwandreturn_probability.Changed in version 1.2.0: Takes nubar and labels an antineutrino oscillogram as such (issue #145), computes NSI and LIV through the Earth wrappers (issue #146 §1), and refuses log10_energy above 19 in compute mode (issue #160 §12).
- Parameters:
costhz (sequence of float) – Zenith-angle cosines, the abscissa. The physical range is \([-1, 0]\); at \(\cos\theta_z \geq 0\) the path inside the Earth has zero length and the computed probability is the identity.
log10_energy (sequence of float) – \(\log_{10}\) of the energy in GeV, the ordinate.
probability (sequence of sequence of float, optional) – Probability with shape
(len(log10_energy), len(costhz)). If None (default), it is computed through the Earth wrappers, which needsnu_i,nu_fandnum_flavors. Give either this or the arguments that compute it, not both.nu_i (int, optional) – Flavor pair, used for the color-bar label and the annotation when those are not given explicitly, and as the channel when the probability is computed. For two flavors they index the wrapper’s \(2 \times 2\) matrix (0 or 1).
nu_f (int, optional) – Flavor pair, used for the color-bar label and the annotation when those are not given explicitly, and as the channel when the probability is computed. For two flavors they index the wrapper’s \(2 \times 2\) matrix (0 or 1).
num_flavors (int, optional) – 2, 3, 4 or 5: which Earth wrapper computes the probability.
nubar (bool, optional) – True for antineutrinos. In compute mode it is also passed to the wrapper, so the grid and its label agree; a value contradicting
wrapper_kw['nubar']is refused. Default: None, which readswrapper_kw['nubar']in compute mode and False otherwise.osc_params (dict, optional) – Mixing parameters, passed to the wrapper by name (
sthandDm2at two flavors, where they are required;s12, …,D31and the sterile ones at three to five flavors, where the wrapper’s default set applies to any left out).electron_fraction (float, optional) – Electron fraction, everywhere or per PREM layer. None (default) keeps the wrappers’ layered values. Passed to the wrapper unchanged, with the wrapper’s meaning and validation.
electron_fraction_core (float, optional) – Electron fraction, everywhere or per PREM layer. None (default) keeps the wrappers’ layered values. Passed to the wrapper unchanged, with the wrapper’s meaning and validation.
electron_fraction_mantle (float, optional) – Electron fraction, everywhere or per PREM layer. None (default) keeps the wrappers’ layered values. Passed to the wrapper unchanged, with the wrapper’s meaning and validation.
electron_fraction_crust (float, optional) – Electron fraction, everywhere or per PREM layer. None (default) keeps the wrappers’ layered values. Passed to the wrapper unchanged, with the wrapper’s meaning and validation.
electron_fraction_ocean (float, optional) – Electron fraction, everywhere or per PREM layer. None (default) keeps the wrappers’ layered values. Passed to the wrapper unchanged, with the wrapper’s meaning and validation.
ratio_number_neutrons_to_protons (float, optional) – Passed to the wrapper unchanged; None keeps its default.
wrapper_kw (dict, optional) – Any other keyword the Earth wrapper accepts (
rtol,atol,nubar,integration_method,magnus_exp_order, …). The channel,energy,costhz,Land the composition keywords above cannot be given here too.loc_ini,loc_finand the depths are not refused but do not belong here: each column of the oscillogram is one zenith angle, from surface to surface.return_probability (bool, optional) – If True, also return the probability drawn. Default is False.
levels (int, optional) – Number of filled contour levels. Default is
120.cmap (str, optional) – Color map. Default is
'plasma'.xlabel (str, optional) – Axis labels.
ylabel (str, optional) – Axis labels.
cbar_label (str, optional) – Color-bar label; overrides the one built from the flavor pair.
cbar_label_prefix (str, optional) – Text placed before the probability label on the color bar.
cbar_fontsize (float, optional) – Color-bar label and tick-label sizes.
cbar_labelsize (float, optional) – Color-bar label and tick-label sizes.
annotation (str, optional) – Corner annotation. Defaults to the probability label when the flavor pair is given; pass
''to suppress it.annotation_fontsize (float, optional) – Corner annotation size.
xlim (tuple of float, optional) – Axis limits. Default to the data range.
ylim (tuple of float, optional) – Axis limits. Default to the data range.
xmajor (float, optional) – Tick spacings. Pass None to hand an axis back to Matplotlib’s own locator. Default: 0.2, 0.02, 0.1 and 0.02.
xminor (float, optional) – Tick spacings. Pass None to hand an axis back to Matplotlib’s own locator. Default: 0.2, 0.02, 0.1 and 0.02.
ymajor (float, optional) – Tick spacings. Pass None to hand an axis back to Matplotlib’s own locator. Default: 0.2, 0.02, 0.1 and 0.02.
yminor (float, optional) – Tick spacings. Pass None to hand an axis back to Matplotlib’s own locator. Default: 0.2, 0.02, 0.1 and 0.02.
figsize (tuple of float, optional) – Figure size. Default is
(9.0, 9.0).contourf_kw (dict, optional) – Extra keywords for
contourf().subplots_kw (dict, optional) – Extra keywords for
subplots().savefig (str, optional) – If given, the figure is written here.
savefig_kw (dict, optional) – Extra keywords merged over
HOUSE_SAVEFIG_KW.tight_layout (bool, optional) – Whether to call
tight_layout. Default isFalse.
- Returns:
fig (matplotlib.figure.Figure)
ax (matplotlib.axes.Axes)
probability (np.ndarray) – Only with
return_probability=True: the probability drawn, shape(len(log10_energy), len(costhz)).
- Raises:
ValueError – If the probability has the wrong shape; if it is given together with any argument that would compute it; if it is to be computed without
nu_i,nu_for a validnum_flavors, or at two flavors withoutosc_params; or if a keyword arrives both explicitly and inwrapper_kw.
Examples
A precomputed probability is drawn as given:
import matplotlib matplotlib.use('Agg') import numpy as np import magnus.globaldefs as gd from magnus.plotting import plot_oscillogram c = np.linspace(-1.0, 0.0, 40) lE = np.linspace(-1.0, 1.0, 30) P = np.sin(np.outer(10 ** lE, 1.0 + c)) ** 2 fig, ax = plot_oscillogram(c, lE, P, nu_i=gd.NUMU, nu_f=gd.NUMU) print(ax.get_xlabel())
Zenith angle, $\cos(\theta_z)$
Without one, it is computed through the Earth wrappers, here at three flavors with the default mixing parameters and the layered electron fraction:
import matplotlib matplotlib.use('Agg') import numpy as np import magnus.globaldefs as gd from magnus.plotting import plot_oscillogram import warnings from magnus.magnus import MagnusConvergenceWarning c = np.linspace(-1.0, -0.1, 25) lE = np.linspace(0.0, 1.0, 20) # A few of these chords need the adaptive refinement to widen its first grids; # this is the expected, informational MagnusConvergenceWarning discussed in the # package README. with warnings.catch_warnings(): warnings.simplefilter('ignore', MagnusConvergenceWarning) fig, ax, P = plot_oscillogram(c, lE, nu_i=gd.NUMU, nu_f=gd.NUE, num_flavors=3, return_probability=True) print(P.shape, round(float(P.max()), 3))
(20, 25) 0.492