plasma_plots.plotting
Small, composable plotting functions for labeled Struphy output.
Every function takes labeled xarray objects (fields with dimensions t, eta1, eta2,
eta3, …, time series, marker datasets) and returns a [PlotResult][PlotResult] or, for animations, a
matplotlib.animation.FuncAnimation. They remain importable for plotting arbitrary labeled
arrays. The optional xarray accessor exposes them as array.plasma.plot.*.
Slices of N-dimensional fields are described by a [View][View]: which dimensions to select, which
two to draw and whether in logical or physical coordinates. The slice functions
([plot_slice()][plot_slice], [plot_panels()][plot_panels], [animate_slices()][animate_slices], [save_frames()][save_frames],
[InteractiveSliceViewer][InteractiveSliceViewer]) share the same rendering options.
Attributes
| Name | Description |
|---|---|
LOGICAL | No description. |
ORBIT_CLASS_COLORS | No description. |
OVERLAY_KEYS | No description. |
PLANES | No description. |
PLOT_STYLE | No description. |
REFERENCE_STYLES | No description. |
logger | No description. |
Classes
| Name | Description |
|---|---|
InteractiveSliceViewer | Slider view with the same rendering options as static and exported slices. |
PlotResult | An already-drawn figure and what was drawn; saving never redraws it. |
View | A reusable selection and rendering recipe for an N-dimensional product. |
Functions
| Name | Description |
|---|---|
animate_fields | Animate several fields side by side, frame by frame in sync over the same sweep. |
animate_lines | Animate a one-dimensional profile over sweep, optionally with its exact profile. |
animate_markers | Animate marker positions over time, optionally over a field animated in sync. |
animate_slices | Animate slices with fixed color limits over the selected sweep by default. |
color_limits | Color limits of the finite values of data. |
energy_names | The energies among scalar names: en_* and *_energy, without totals and equilibria. |
logical_grids | Return 2-D logical coordinate grids and their labels. |
physical_grids | Return physical auxiliary coordinates already attached to a selected field. |
plot_compare | Plot a one-dimensional aligned difference or ratio of two arrays. |
plot_continuous_spectrum | Plot the continuum frequencies omega(x) of each mode. |
plot_convergence | Log-log plot of an error norm against resolution or step size, e.g. from a convergence study. |
plot_critical_points | The flux function's contours with its O-points (dots) and X-points (crosses). |
plot_dispersion | The space-time power spectrum of a (t, dim) field, as a dispersion-relation plot. |
plot_energy_budget | An energy budget: the energy parts, the relative drift of the total, and exchanges. |
plot_equilibrium_profile | Plot radial profiles of a fluid equilibrium along eta1 (at eta2 = eta3 = 0). |
plot_field_with_orbits | A 2-D field slice with marker orbit paths overlaid. |
plot_lineout | Plot a one-dimensional profile along its one remaining coordinate. |
plot_loss_map | Which markers are lost, over their initial phase-space position, colored by when. |
plot_lost_fraction | The fraction of markers lost from the domain, against time. |
plot_marker_density | Where the markers are against what they represent: the marker density along one coordinate. |
plot_marker_paths | Paths of a few markers in a plane, with their start (circle) and end (cross). |
plot_marker_scatter | Scatter marker positions from a Dataset (an orbits product, or any per-marker data). |
plot_marker_trajectories | Plot a static 3-D trajectory overview. |
plot_measured_vs_theory | Measured values against a theory curve over a parameter, with their relative error. |
plot_orbit_classification | Scatter markers in a phase-space plane, colored as passing, trapped or lost. |
plot_orbit_grid | One small poloidal panel (R against z) per marker, sharing axes. |
plot_orbit_poloidal | Marker orbits projected onto the poloidal plane, R = √(x² + y²) against z. |
plot_orbit_quantities | Saved orbit quantities over time, one panel per quantity and one line per marker. |
plot_panels | Plot snapshots with common color limits over the entire selected sweep by default. |
plot_profiles | Several one-dimensional profiles along x in one axes, one per value of over. |
plot_scalars | Plot every scalar time series in one axes. |
plot_slice | Render one selected two-dimensional slice. |
plot_timeseries | Plot one or more time series, each on its own time grid. |
plot_vector | Render two components of a selected vector field with Matplotlib quivers. |
plot_volume_slices | Show three orthogonal midpoint slices of a selected scalar volume. |
plot_weight_histogram | The distribution of the marker weights at one or several times, with their statistics. |
prepare_compare | Align two arrays and compute their difference or ratio, without rendering it. |
prepare_continuous_spectrum | Evaluate a continuous spectrum omega(x) for each mode, as a (mode, branch, x) array. |
prepare_lineout | Check that a selected profile has one dimension left, and that it is x. |
prepare_marker_scatter | The per-marker positions and colors plot_marker_scatter() draws. |
prepare_orbit_classification | Each marker's x and y at time t together with its orbit class. |
prepare_orbits | Normalize an orbits product to its Dataset form and keep only the first max_markers. |
prepare_vector | Select and stride two components of a vector field, without rendering it. |
prepare_view | Every frame of a slice view at once: the data panels, viewers and animations draw. |
prepare_volume_slices | Three orthogonal midpoint (or chosen-index) planes through a scalar volume. |
pyvista_volume | Create a PyVista volume view from a selected scalar field with X/Y/Z coordinates. |
resolve_marker_selection | Select dimensions of a Dataset: an integer is a position, a float the nearest value. |
save_all_scalars | Write a table, scalar overview and one figure per scalar. |
save_figure | Save a figure in several formats at once, as <name>.<format>. |
save_frames | Export the configured sweep as PNGs, sharing color limits by default. |
shared_run_label | The run description shared by all arrays (attrs["run"]), or default. |
show_equilibrium | A PyVista cutaway view of a fluid equilibrium's scalar field over its domain. |
LOGICALattributemodule attribute#
LOGICAL = {name for names in LOGICAL_DIMS for name in names}ORBIT_CLASS_COLORSattributemodule attribute#
ORBIT_CLASS_COLORS = {'passing': 'C0', 'trapped': 'C1', 'lost': '0.55'}OVERLAY_KEYSattributemodule attribute#
OVERLAY_KEYS = {
'contours_of',
'contour_levels',
'contour_color',
'boundary',
'boundary_color',
'grid_lines',
'coordinate_lines',
'coordinate_line_color',
'lines',
'line_color',
'points',
'point_color'
}PLANESattributemodule attribute#
PLANES = {
'XY': ('X', 'Y', 'X', 'Y'),
'XZ': ('X', 'Z', 'X', 'Z'),
'YZ': ('Y', 'Z', 'Y', 'Z'),
'RZ': ('R', 'Z', 'R', 'Z'),
'X1X2': ('X1', 'X2', '$X^1$', '$X^2$')
}PLOT_STYLEattributemodule attribute#
REFERENCE_STYLESattributemodule attribute#
REFERENCE_STYLES = ('--', ':', '-.', (0, (5, 1, 1, 1)))loggerattributemodule attribute#
logger = logging.getLogger('plasma_plots')InteractiveSliceViewerclass#
class InteractiveSliceViewer(data: xr.DataArray, *, view=None, vmin=None, vmax=None, run_label=None, shared_clim=True, cmap=None, equal_aspect=None, title=None, symmetric=False, robust=False, levels=None, fill=True, overlays=None, xlabel=None, ylabel=None, colorbar_label=None)Slider view with the same rendering options as static and exported slices.
It draws on first display (or [draw()][draw], [show()][show]): view.x and view.y default
to the first two dimensions other than the sweep, and every other remaining dimension (the
sweep included) gets a slider over its positions, except dimensions of length one.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | The field; dimensions not drawn and not selected by view get sliders. |
view | View | None | Which dimensions to select, which two to draw and in which coordinates (see View).
Default: View(), the two remaining dimensions in logical coordinates. |
vmin | float | None | The lower color limit. Default: from the data (see symmetric and robust). |
vmax | float | None | The upper color limit. Default: from the data (see symmetric and robust). |
run_label | str | None | A run description shown as the figure’s suptitle. Default: the run shared by the
data (see shared_run_label()); "" for none. |
shared_clim | bool | True | Take the color limits once from all the selected data (every value of the sweep), so that
every slice shares them; False gives each slice its own. Default: True. |
cmap | str or matplotlib.colors.Colormap | None | The colormap. Default: "viridis". |
equal_aspect | bool | None | Draw both axes to the same scale. Default: True in physical coordinates, False in
logical ones. |
title | str | None | The axes title. Default: the array’s label, followed by the slider values. |
symmetric | bool | False | Center the color limits on zero (-v, v), as a diverging colormap for a perturbation
needs. Default: False. |
robust | bool | False | Take the color limits from the 1st and 99th percentiles instead of the extremes, so a few
outliers do not wash out the rest. Default: False. |
levels | int or sequence of float | None | Contour lines of the slice: a number of levels spaced evenly between the color limits, or
the levels themselves. Drawn in black over the colors, or in the colormap’s colors with
fill=False. Default: no contour lines. |
fill | bool | True | Fill the slice with colors; False leaves it transparent, e.g. to show only the contour
lines of levels. Default: True. |
overlays | dict | None | What to draw on top of the slice, by key (other keys raise a
Lines and points do not widen the axes and are listed in a legend. |
xlabel | str | None | The horizontal axis label. Default: the coordinate’s name and units. |
ylabel | str | None | The vertical axis label. Default: the coordinate’s name and units. |
colorbar_label | str | None | The color bar label. Default: the array’s label and units. |
Examples
>>> InteractiveSliceViewer(... phi, view=View(x="eta1", y="eta2"), symmetric=True... ).show()dataattributeinstance attribute#
data = validate_array(data)optionsattributeinstance attribute#
options = dict(
vmin=vmin,
vmax=vmax,
shared_clim=shared_clim,
cmap=cmap,
equal_aspect=equal_aspect,
title=title,
symmetric=symmetric,
robust=robust,
levels=levels,
fill=fill,
overlays=overlays,
xlabel=xlabel,
ylabel=ylabel,
colorbar_label=colorbar_label
)resultattributeinstance attribute#
result = Nonerun_labelattributeinstance attribute#
run_label = shared_run_label(data) if run_label is None else run_labelslidersattributeinstance attribute#
sliders = {}viewattributeinstance attribute#
view = view or View()drawmethod#
def draw()Draw the slice and its sliders, once; later calls return the same result.
Returns
PlotResult- The figure, the axes and the current mesh;
data["viewer"]holds this viewer, which keeps the slider callbacks alive.
Raises
ValueError- If fewer than two dimensions other than the sweep remain to draw.
showmethod#
def show()Draw the viewer if needed and show it with matplotlib.pyplot.show.
Returns
InteractiveSliceViewer- This viewer.
PlotResultclassdataclass#
class PlotResult(fig: object, ax: object = None, artists: list = list(), fit_results: list[FitResult | None] = list(), data: dict = dict())An already-drawn figure and what was drawn; saving never redraws it.
Every plotting function returns one. As the last expression of a notebook cell it displays
its figure once; there is no need to write .fig. With backend="plotly" (see
plasma_plots.plotly_backend) the figure is a Plotly figure instead, and with
backend="tikz" (see plasma_plots.tikz_backend) a TikZ/pgfplots figure, with the
same fit_results and data.
A figure made some other way (e.g. with plotly.graph_objects directly) is saved with the
same defaults as PlotResult(figure).save("page.html"). Saving and showing do nothing on
MPI ranks other than 0, so a script can call them on every rank.
Attributes
| Name | Type | Description |
|---|---|---|
fig | (matplotlib.figure.Figure, plotly.graph_objects.Figure or tikzfigure.TikzFigure) | The figure. |
ax | matplotlib.axes.Axes, array of matplotlib.axes.Axes or None | The axes drawn into; an array (or list) of axes for multi-panel plots; None for a
Plotly or TikZ figure. |
artists | list | The drawn artists (lines, meshes, scatter collections, …); for a Plotly figure its traces; empty for a TikZ figure. |
fit_results | list of FitResult or None | The growth-rate fits of plot_timeseries(), one per series (None where no fit
was made); empty for other plots. |
data | dict | Extra results of the plot, e.g. "counts" of plot_orbit_classification() or
"markers" of plot_marker_paths(). |
Examples
>>> result = plot_lineout(phi.isel(t=-1, eta2=0, eta3=0))>>> result.save("phi.png", dpi=200)>>> # a figure of your own>>> PlotResult(go.Figure(go.Scatter(x=t, y=energy))).save("energy.html")artistsattributeclass attributeinstance attribute#
artists: list = field(default_factory=list)axattributeclass attributeinstance attribute#
ax: object = Nonedataattributeclass attributeinstance attribute#
data: dict = field(default_factory=dict)figattributeinstance attribute#
fig: objectfit_resultsattributeclass attributeinstance attribute#
fit_results: list[FitResult | None] = field(default_factory=list)savemethod#
def save(path, *, close=False, frame=None, **kwargs)Save the figure to a file, as drawn.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
path | str or pathlib.Path | required | The file to write; its extension picks the format. A Plotly figure is written as a
standalone page (.html, loading Plotly’s JavaScript from its CDN, responsive, an
animation not playing until asked), as figure JSON (.json), or as an image through
kaleido (.png, .svg, .pdf, …). A TikZ figure is written as its
tikzpicture (.tikz, to \input in a document loading pgfplots) or as
a standalone document (.tex), with the images it refers to next to the file, or
compiled with pdflatex (.pdf, .png). |
close | bool | False | Close the Matplotlib figure afterwards, to free its memory. Default: False. |
frame | int | None | For an image of a Plotly animation: the frame it shows, with the slider there (e.g.
len(result.fig.frames) // 2, when the first frame is still featureless). The page
and the JSON keep the whole animation. Default: the first frame. |
**kwargs | {} | Passed to matplotlib.figure.Figure.savefig (e.g. dpi;
bbox_inches="tight" unless given), or to Plotly’s write_html, write_json
or write_image (e.g. width, height, scale; dpi sets the
scale, 100 dpi per unit), or to tikzfigure.TikzFigure.savefig (e.g. dpi
of a .png). |
Returns
str- The path written (on MPI ranks other than 0 nothing is written).
showmethod#
def show()Show the figure with matplotlib.pyplot.show, or a Plotly or TikZ figure with its show.
A TikZ figure is compiled with pdflatex to be shown.
Afterwards a notebook no longer displays the result again as a cell result.
Returns
PlotResult- This result.
to_plotlymethod#
def to_plotly(close: bool = False) -> 'PlotResult'The same result with the figure converted to an interactive Plotly figure.
For the plotting functions, whose results are Matplotlib figures; the accessor methods
take backend="plotly" instead.
Parameters
Returns
PlotResult- A new result: the Plotly figure, its traces as
artists, and this result’sfit_resultsanddata.
Examples
>>> plot_timeseries(... energy, fit=GrowthFit(window=(5.0, 20.0))... ).to_plotly().save("energy.html")to_tikzmethod#
def to_tikz(close: bool = False, **options) -> 'PlotResult'The same result with the figure converted to TikZ/pgfplots code for LaTeX.
For the plotting functions, whose results are Matplotlib figures; the accessor methods
take backend="tikz" instead.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
close | bool | False | Close the Matplotlib figure afterwards. Default: False. |
**options | {} | Passed to plasma_plots.tikz_backend.to_tikz(), e.g. raster_dpi. |
Returns
PlotResult- A new result: the
tikzfigure.TikzFigure, and this result’sfit_resultsanddata.
Examples
>>> plot_timeseries(energy, fit=GrowthFit(window=(5.0, 20.0))).to_tikz().save(... "energy.tex"... )Viewclassdataclass#
class View(x: str | None = None, y: str | None = None, sweep: str = 't', select: dict[str, float] = dict(), isel: dict[str, int] = dict(), coordinates: Literal['logical', 'physical'] = 'logical', plane: Literal['XY', 'XZ', 'YZ', 'RZ'] = 'XY')A reusable selection and rendering recipe for an N-dimensional product.
Attributes
| Name | Type | Description |
|---|---|---|
x | str or None | The dimension along the horizontal axis. Default: the first of the two dimensions left after the selection. |
y | str or None | The dimension along the vertical axis. Default: the second of the two dimensions left. |
sweep | str | The dimension that panels, animations, exported frames and sliders run over. Default:
"t". |
select | dict of str to float | Dimensions to select by coordinate value (nearest), e.g. {"eta3": 0.5}. |
isel | dict of str to int | Dimensions to select by integer position, e.g. {"eta3": 0}. A dimension cannot appear
in both select and isel. |
coordinates | {'logical', 'physical'} | Draw over the logical coordinates (eta1, …) or over the physical X, Y, Z
coordinates attached to the field. Default: "logical". |
plane | {'XY', 'XZ', 'YZ', 'RZ', 'X1X2'} | The physical plane drawn with coordinates="physical"; "RZ" uses
R = √(X² + Y²), "X1X2" GVEC’s reference coordinates X1, X2 (see
plasma_plots.gvec.from_gvec()). Default: "XY". |
Examples
>>> view = View(x="eta1", y="eta2", isel={"eta3": 0}, coordinates="physical")>>> plot_slice(phi.isel(t=-1), view=view)coordinatesattributeclass attributeinstance attribute#
coordinates: Literal['logical', 'physical'] = 'logical'iselattributeclass attributeinstance attribute#
isel: dict[str, int] = field(default_factory=dict)planeattributeclass attributeinstance attribute#
plane: Literal['XY', 'XZ', 'YZ', 'RZ'] = 'XY'selectattributeclass attributeinstance attribute#
select: dict[str, float] = field(default_factory=dict)sweepattributeclass attributeinstance attribute#
sweep: str = 't'xattributeclass attributeinstance attribute#
x: str | None = Noneyattributeclass attributeinstance attribute#
y: str | None = Noneanimate_fieldsfunction#
def animate_fields(fields, *, view=None, interval=100, step=1, max_frames=None, titles=None, **options)Animate several fields side by side, frame by frame in sync over the same sweep.
Each field keeps its own color limits and color bar. Retain the returned animation, e.g. in a variable, or it stops.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
fields | sequence of xarray.DataArray | required | Two or more arrays with the same dimensions and sweep coordinate (e.g. the vorticity and density of a Hasegawa-Wakatani run). |
view | View | None | Which dimensions to select, which two to draw, in which coordinates, and the sweep
dimension (view.sweep, default t) to run over, for every field (see
View). Default: View(). |
interval | int | 100 | The delay between frames, in milliseconds. Default: 100. |
step | int | 1 | Use every step-th value of the sweep. Default: 1. |
max_frames | int | None | Keep at most this many frames, evenly spaced over those step leaves (the first and
last included), e.g. to keep a Plotly animation small. Default: all. |
titles | sequence of str | None | One axes title per field. Default: the fields’ labels. |
**options | {} | Rendering options applied to every field as in animate_slices(): vmin,
vmax, shared_clim, cmap, equal_aspect, symmetric, robust,
levels, fill, overlays. |
Returns
matplotlib.animation.FuncAnimation- The animation, one frame per used sweep value.
Raises
ValueError- If there are fewer than two fields, or they have different numbers of sweep values.
Examples
>>> animation = animate_fields(... [vorticity.isel(eta3=0), density.isel(eta3=0)], symmetric=True... )animate_linesfunction#
def animate_lines(data: xr.DataArray, *, x: str | None = None, sweep: str = 't', reference=None, x_of=None, xlabel: str | None = None, ylim=None, step: int = 1, max_frames: int | None = None, interval: int = 100, title: str | None = None, alongside=None, alongside_logy: bool = False)Animate a one-dimensional profile over sweep, optionally with its exact profile.
The value axis is fixed over the whole animation. With alongside, further panels below it
run in sync: other profiles over the same sweep, or time series (e.g. the energy), drawn whole
with a marker at the current value of the sweep. Retain the returned animation, e.g. in a
variable, or it stops.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | The profiles, with the dimensions x and sweep (select the rest first). |
x | str | None | The dimension along the horizontal axis. Default: the one besides sweep. |
sweep | str | 't' | The dimension to animate over. Default: "t". |
reference | callable, (x, y) pair or dict | None | The exact profile of each frame, drawn dashed in black: a function of the plotted x
and of the sweep value (lambda x, t: ...; a function of x alone is fixed), an
(x, y) pair, a 1-D xarray.DataArray (drawn over its own coordinate), or a dict of
labels to these. |
x_of | callable | None | Maps the x coordinate to the plotted axis, e.g. lambda eta1: L * eta1. |
xlabel | str | None | The horizontal axis label. Default: the coordinate’s label, or "x" with x_of. |
ylim | (float, float) | None | The fixed value axis limits. Default: the range of the data and references, padded by 5 %. |
step | int | 1 | Use every step-th value of the sweep. Default: 1. |
max_frames | int | None | Keep at most this many frames, evenly spaced over those step leaves (the first and
last included), e.g. to keep a Plotly animation small. Default: all. |
interval | int | 100 | The delay between frames, in milliseconds. Default: 100. |
title | str | None | The title, followed in each frame by the sweep value. Default: the array’s label. |
alongside | sequence | None | One panel below the profile per item, in sync with it: an array over sweep and one
other dimension (another profile, animated, e.g. the density next to the velocity), or an
array over sweep alone, or a list of those (time series such as energies, drawn whole
with a marker at each frame’s value of the sweep, nearest where the times differ).
Default: none. |
alongside_logy | bool | False | Logarithmic value axes for the time-series panels. Default: False. |
Returns
matplotlib.animation.FuncAnimation- The animation, one frame per used sweep value.
Raises
ValueError- If
sweepis missing, more than one other dimension remains,stepormax_framesis not a positive integer, or analongsidearray has other dimensions thansweepand at most one more.
Examples
>>> animation = animate_lines(... phi.isel(eta2=0, eta3=0),... reference=lambda x, t: np.cos(t) * np.sin(np.pi * x),... )>>> animation = animate_lines(... u.isel(eta2=0, eta3=0),... alongside=[n.isel(eta2=0, eta3=0), [en_U, en_B]],... )animate_markersfunction#
def animate_markers(markers: xr.Dataset, *, x: str, y: str, color: str | None = None, color_at=None, background: xr.DataArray | None = None, background_options: dict | None = None, step: int = 1, max_frames: int | None = None, interval: int = 100, s: int = 8, cmap=None, trail: int | None = None, paths: bool = False)Animate marker positions over time, optionally over a field animated in sync.
Markers that have left the domain are hidden. The axes limits stay fixed over the whole animation. Retain the returned animation, e.g. in a variable, or it stops.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
markers | xarray.Dataset | required | The per-marker data over (t, marker), e.g. an orbits product. |
x | str | required | The data variable along the horizontal axis, e.g. the position "x"; "R" is
√(x² + y²) when the data has no R of its own (with y="z" the poloidal plane). |
y | str | required | The data variable along the vertical axis, e.g. the position "y". |
color | str | None | A variable to color by: per frame, or fixed at the time color_at; or
"classification", the orbit class of each marker (passing, trapped, lost; needs
v_par, see classify_orbits()), with a legend. Default: one
color. |
color_at | int or float | None | Fix the colors at this time (an integer position, e.g. 0 for the initial position,
to follow fluid parcels, or a float value). Default: the colors of each frame. |
background | xarray.DataArray | None | A field drawn behind the markers: with a t dimension (other dimensions selected) at the
nearest time of each frame, with shared color limits; without one, fixed (drawn once). On
its own x/y dimensions if it has them (a Cartesian field), in logical coordinates
if x/y are eta1/eta2/eta3, else in the physical plane of x/y
(the field then needs its X, Y, Z coordinates). |
background_options | dict | None | Rendering options for the background, as for plot_slice() (cmap,
symmetric, levels, …). |
step | int | 1 | Use every step-th time. Default: 1. |
max_frames | int | None | Keep at most this many frames, evenly spaced over those step leaves (the first and
last included), e.g. to keep a Plotly animation small. Default: all. |
interval | int | 100 | The delay between frames, in milliseconds. Default: 100. |
s | int | 8 | The marker size, in points². Default: 8. |
cmap | str or matplotlib.colors.Colormap | None | The colormap for color. Default: "viridis". |
trail | int | None | Draw each marker’s last trail samples as a faint line behind it. Default: none. |
paths | bool | False | Draw each marker’s whole path, fixed and faint, under the animation. Default: False. |
Returns
matplotlib.animation.FuncAnimation- The animation, one frame per used time.
Raises
ValueError- If
step,max_framesortrailis not a positive integer.
Examples
>>> animation = animate_markers(... out.orbits["ions"], x="x", y="y", color="x", color_at=0... )animate_slicesfunction#
def animate_slices(data: xr.DataArray, *, view=None, interval=100, step=1, max_frames=None, vmin=None, vmax=None, shared_clim=True, cmap=None, equal_aspect=None, title=None, symmetric=False, robust=False, levels=None, fill=True, overlays=None, xlabel=None, ylabel=None, colorbar_label=None)Animate slices with fixed color limits over the selected sweep by default.
Retain the returned animation, e.g. in a variable, or it stops.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | The field, with the sweep dimension; other dimensions not drawn are selected by
view. |
view | View | None | Which dimensions to select, which two to draw, in which coordinates, and the sweep
dimension (view.sweep, default t) to run over (see View). Default:
View(). |
interval | int | 100 | The delay between frames, in milliseconds. Default: 100. |
step | int | 1 | Use every step-th value of the sweep. Default: 1. |
max_frames | int | None | Keep at most this many frames, evenly spaced over those step leaves (the first and
last included), e.g. to keep a Plotly animation small. Default: all. |
vmin | float | None | The lower color limit. Default: from the data (see symmetric and robust). |
vmax | float | None | The upper color limit. Default: from the data (see symmetric and robust). |
shared_clim | bool | True | Take the color limits once from all the selected data (every value of the sweep), so that
every slice shares them; False gives each slice its own. Default: True. |
cmap | str or matplotlib.colors.Colormap | None | The colormap. Default: "viridis". |
equal_aspect | bool | None | Draw both axes to the same scale. Default: True in physical coordinates, False in
logical ones. |
title | str | None | The title, followed in each frame by the sweep value. Default: the array’s label. |
symmetric | bool | False | Center the color limits on zero (-v, v), as a diverging colormap for a perturbation
needs. Default: False. |
robust | bool | False | Take the color limits from the 1st and 99th percentiles instead of the extremes, so a few
outliers do not wash out the rest. Default: False. |
levels | int or sequence of float | None | Contour lines of the slice: a number of levels spaced evenly between the color limits, or
the levels themselves. Drawn in black over the colors, or in the colormap’s colors with
fill=False. Default: no contour lines. |
fill | bool | True | Fill the slice with colors; False leaves it transparent, e.g. to show only the contour
lines of levels. Default: True. |
overlays | dict | None | What to draw on top of the slice, by key (other keys raise a
Lines and points do not widen the axes and are listed in a legend. |
xlabel | str | None | The horizontal axis label. Default: the coordinate’s name and units. |
ylabel | str | None | The vertical axis label. Default: the coordinate’s name and units. |
colorbar_label | str | None | The color bar label. Default: the array’s label and units. |
Returns
matplotlib.animation.FuncAnimation- The animation, one frame per used sweep value; save it with
.save("phi.mp4")or show it with.to_jshtml().
Raises
ValueError- If
stepis not a positive integer, the sweep dimension is missing or empty, oroverlayshas unknown keys.
Examples
>>> animation = animate_slices(phi.isel(eta3=0), step=2, symmetric=True)>>> animation.save("phi.mp4")color_limitsfunction#
def color_limits(data, *, symmetric: bool = False, robust: bool = False) -> tuple[float, float]Color limits of the finite values of data.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | array_like or xarray.DataArray | required | The values. |
symmetric | bool | False | Center the color limits on zero (-v, v), as a diverging colormap for a perturbation
needs. Default: False. |
robust | bool | False | Take the color limits from the 1st and 99th percentiles instead of the extremes, so a few
outliers do not wash out the rest. Default: False. With symmetric, v is the
99th percentile of the absolute values. |
Raises
ValueError- If
datahas no finite values.
energy_namesfunction#
def energy_names(names) -> list[str]The energies among scalar names: en_* and *_energy, without totals and equilibria.
Struphy names a run’s energies either way, depending on the model (en_U, en_B,
en_tot or electric_energy, magnetic_energy, total_energy).
Parameters
| Name | Type | Description |
|---|---|---|
names | iterable of str | Scalar names, e.g. out.scalars.data_vars. |
Returns
list of str- The energy parts, in the order given;
en_tot,total_energyand*_eq/*_totleft out.
Examples
>>> energy_names(["en_U", "en_B", "en_tot", "growth"])['en_U', 'en_B']>>> energy_names(["electric_energy", "magnetic_energy", "total_energy"])['electric_energy', 'magnetic_energy']logical_gridsfunction#
def logical_grids(data: xr.DataArray, *, x=None, y=None)Return 2-D logical coordinate grids and their labels.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | A slice with exactly the dimensions x and y. |
x | str | None | The first dimension. Default (with y): the first dimension of a 2-D data. |
y | str | None | The second dimension. Default (with x): the second dimension of a 2-D data. |
Returns
tuple(xgrid, ygrid, xlabel, ylabel): two 2-D arrays (indexing="ij") and the axis labels.
Raises
ValueError- If
datadoes not have exactly the dimensionsxandy.
physical_gridsfunction#
def physical_grids(data: xr.DataArray, *, plane='XY')Return physical auxiliary coordinates already attached to a selected field.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | A 2-D slice with the coordinates X, Y and Z attached. |
plane | ('XY', 'XZ', 'YZ', 'RZ', 'X1X2') | "XY" | The physical plane; "RZ" uses R = √(X² + Y²), "X1X2" GVEC’s reference
coordinates X1, X2. Default: "XY". |
Returns
tuple(xgrid, ygrid, xlabel, ylabel): two 2-D arrays and the axis labels.
Raises
ValueError- If
planeis unknown, a physical coordinate is missing, or the coordinates are not 2-D.
plot_comparefunction#
def plot_compare(first: xr.DataArray, second: xr.DataArray, *, mode: Literal['difference', 'ratio'] = 'difference', ax=None)Plot a one-dimensional aligned difference or ratio of two arrays.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
first | xarray.DataArray | required | The first array, one-dimensional. |
second | xarray.DataArray | required | The second array, one-dimensional; only coordinates both share are kept. |
mode | ('difference', 'ratio') | "difference" | first - second, or first / second (NaN where second is zero). Default:
"difference". |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
Returns
PlotResult- The figure, the axes and the drawn line.
Examples
>>> plot_compare(phi.isel(t=-1, eta2=0, eta3=0), phi.isel(t=0, eta2=0, eta3=0))plot_continuous_spectrumfunction#
def plot_continuous_spectrum(spectrum, x, modes, *, frequencies: dict[str, float] | None = None, mode_label: str = '(m, n)', xlabel: str = 'x', ax=None, title: str = 'Continuous spectrum')Plot the continuum frequencies omega(x) of each mode.
One color per mode and one line style per branch (e.g. shear Alfvén solid, slow sound dashed).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
spectrum | callable | required | Called as spectrum(x, *mode); must return a mapping of branch name to omega(x),
e.g. Struphy’s MhdContinousSpectraShearedSlab or MhdContinousSpectraCylinder from
struphy.dispersion_relations.analytic, whose modes are (m, n) pairs (see
prepare_continuous_spectrum()). |
x | array_like | required | The points to evaluate at. |
modes | sequence of tuple | required | The modes, each a tuple of mode numbers (a bare number is a 1-tuple). |
frequencies | dict of str to float | None | Measured frequencies to mark as horizontal lines (a mapping of label to omega, e.g. a
peak read off plot_dispersion()), to see whether a mode lies in a continuum gap or
crosses a continuum, where it is damped. |
mode_label | str | '(m, n)' | How modes are named in the legend. Default: "(m, n)". |
xlabel | str | 'x' | The horizontal axis label. Default: "x". |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
title | str | 'Continuous spectrum' | The axes title. Default: "Continuous spectrum". |
Returns
PlotResult- The figure, the axes and the drawn lines;
data["spectrum"]holds the evaluated spectrum fromprepare_continuous_spectrum().
Raises
ValueError- If
modesis empty.
Examples
>>> plot_continuous_spectrum(... spectrum,... np.linspace(0, 1, 200),... [(1, 1), (2, 1)],... frequencies={"measured": 0.42},... )plot_convergencefunction#
def plot_convergence(sizes, errors, *, ax=None, order=None, label=None, xlabel='resolution', title='Convergence')Log-log plot of an error norm against resolution or step size, e.g. from a convergence study.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
sizes | array_like | required | The resolutions or step sizes. |
errors | array_like | required | The error norm at each size. |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
order | float | None | With None (default), fits and draws the observed order via
plasma_plots.analysis.convergence_order(). Pass an explicit order (e.g. 2
for second-order) to draw a reference slope through the first point instead of fitting
one. |
label | str | None | The legend label of the errors. Default: none. |
xlabel | str | 'resolution' | The horizontal axis label. Default: "resolution". |
title | str | 'Convergence' | The axes title. Default: "Convergence". |
Returns
PlotResult- The figure, the axes, the error line and the fitted or reference line.
Examples
>>> plot_convergence([16, 32, 64, 128], errors, order=2)plot_critical_pointsfunction#
def plot_critical_points(data: xr.DataArray, *, view=None, ax=None, levels=14, cmap=None, label_values: bool = False, **options)The flux function’s contours with its O-points (dots) and X-points (crosses).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | The flux function, e.g. flux_function() of B, with
every dimension but the plane’s two selected (view may do the selecting). |
view | View | None | The slice to draw (see View): which dimensions, logical or physical
coordinates. Default: the two logical directions left, in logical coordinates. |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
levels | int or sequence of float | 14 | Contour lines of the flux, as for plot_slice(). Default: 14. |
cmap | str or matplotlib.colors.Colormap | None | The colormap. Default: "RdBu_r". |
label_values | bool | False | Write the flux value next to each point. Default: False. |
**options | {} | Further options of plot_slice() (symmetric, overlays, …). |
Returns
PlotResult- The figure, the axes, the mesh, the contours and the two scatters;
data["points"]holds thecritical_points().
Examples
>>> plot_critical_points(flux_function(B).isel(t=-1))>>> plot_critical_points(... flux_function(B), view=View(isel={"t": -1}, coordinates="physical")... )plot_dispersionfunction#
def plot_dispersion(data: xr.DataArray, *, dim: str | None = None, detrend: bool = True, branches: dict | None = None, log: bool = True, dynamic_range: float = 6.0, kmin: float | None = None, kmax: float | None = None, omega_max: float | None = None, vmin: float | None = None, vmax: float | None = None, cmap=None, ax=None, title: str | None = None, frequencies: dict | None = None, points: dict | None = None, fits=())The space-time power spectrum of a (t, dim) field, as a dispersion-relation plot.
The spectrum may also be given directly, e.g. from power_spectrum()
(then dim and detrend are not used). Shows only non-negative frequencies (a real signal’s spectrum is symmetric under
(k, ω) → (-k, -ω), so every branch already appears on both sides of k = 0).
A dispersion relation’s power spans many orders of magnitude (the ridge against a mostly-empty
plane), so with log=True (default), color limits default to the top dynamic_range
decades below the peak, rather than the full range down to numerical noise; override with
vmin/vmax if the ridge still looks washed out or overly clipped.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | The field, with the dimensions t and dim (select the rest first), or its power
spectrum, with the dimensions omega and k. |
dim | str | None | The spatial dimension to transform. Default: the one besides t (see
plasma_plots.analysis.power_spectrum()). |
detrend | bool | True | Remove the time-mean at each point of dim first, which otherwise dominates the
spectrum as a spurious zero-frequency line. Default: True. |
branches | dict or callable | None | Theoretical curves to compare against, drawn dashed: a dict of labels to a callable
omega(k) or an explicit (k, omega) pair of arrays; or one callable that returns a
dict of branch names to frequencies, such as the dispersion relations of
plasma_plots.theory or Struphy’s struphy.dispersion_relations objects (a
callable in the dict may return such a dict too). Complex frequencies are drawn by their
real part. |
log | bool | True | Color by log10 of the power. Default: True. |
dynamic_range | float | 6.0 | With log, the number of decades below the peak that the default color limits cover.
Default: 6.0. |
kmin | float | None | Show only k >= kmin, e.g. 0 for the positive quadrant. Default: all k. |
kmax | float | None | Show only |k| <= kmax. Default: all k. |
omega_max | float | None | Show only ω <= omega_max. Default: all non-negative ω. |
vmin | float | None | The lower color limit (in log10 of the power with log). Default: the peak minus
dynamic_range with log, else the minimum. |
vmax | float | None | The upper color limit (in log10 of the power with log). Default: the peak. |
cmap | str or matplotlib.colors.Colormap | None | The colormap. Default: Matplotlib’s default. |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
title | str | None | The axes title. Default: "Dispersion relation of <label>". |
frequencies | dict of str to float | None | Labeled horizontal lines, e.g. cutoffs or resonances. |
points | dict | None | Measured points to mark: a dict of labels to a (k, omega) pair or a
trace_branch() result (an xarray.Dataset with k and
omega). |
fits | sequence of BranchFit | () | Fitted straight branches from fit_dispersion_branches(),
drawn dotted as omega = velocity * k over the shown k >= 0. Default: none. |
Returns
PlotResult- The figure, the axes, the mesh and the drawn lines and points.
Examples
>>> plot_dispersion(... e_field.isel(eta2=0, eta3=0),... branches={"Langmuir": lambda k: np.sqrt(1 + 3 * k**2)},... )plot_energy_budgetfunction#
def plot_energy_budget(scalars, *, parts=None, total: str | None = 'en_tot', groups: dict | None = None, logy: bool = False, run_label=None)An energy budget: the energy parts, the relative drift of the total, and exchanges.
The first panel shows the parts, with the total in black. The second panel is
(total - total(0)) / total(0), which should stay flat for a conservative scheme. With
groups, a third panel shows each group’s change since t = 0, and for two groups also
minus the second one’s (dashed), so that the curves overlap where energy only moves between
them.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
scalars | xarray.Dataset or mapping of str to xarray.DataArray | required | The time series (out.scalars), each with the only dimension t. |
parts | sequence of str | None | The energies drawn in the first panel. Default: the scalars energy_names()
finds (en_* and *_energy), except total. |
total | str or None | 'en_tot' | The total energy; the second panel is left out if it is None or not among the
scalars. Default: "en_tot", or "total_energy" for a run that names its
energies that way. |
groups | dict of str to list of str | None | A label to the names it sums, e.g.
{"wave": ["en_U", "en_B", "en_p"], "energetic ions": ["en_fv", "en_fB"]}. Default:
no exchange panel. |
logy | bool | False | Use a logarithmic value axis in the first panel. Default: False. |
run_label | str | None | A run description shown as the figure’s suptitle. Default: the run shared by the parts
(see shared_run_label()); "" for none. |
Returns
PlotResult- The figure, the list of axes (one per panel) and the drawn lines.
Raises
ValueError- If a used scalar is not a time series with the only dimension
t.
Examples
>>> plot_energy_budget(... out.scalars,... groups={"wave": ["en_U", "en_B", "en_p"], "ions": ["en_fv"]},... )plot_equilibrium_profilefunction#
def plot_equilibrium_profile(equil, domain, *, n_points=100, ax=None)Plot radial profiles of a fluid equilibrium along eta1 (at eta2 = eta3 = 0).
Plots p0, and n0 and T0 = p0 / n0 if equil has a density profile too,
against R = √(x² + y²).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
equil | struphy.fields_background.base.FluidEquilibrium | required | The equilibrium, e.g. from out.equil. |
domain | struphy.geometry.base.Domain | required | Its mapping (out.domain). |
n_points | int | 100 | Number of points along eta1. Default: 100. |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
Returns
PlotResult- The figure, the axes and the profile lines.
Examples
>>> plot_equilibrium_profile(out.equil, out.domain)plot_field_with_orbitsfunction#
def plot_field_with_orbits(field: xr.DataArray, view: View, orbits: xr.Dataset, *, max_markers=200, ax=None, cmap=None)A 2-D field slice with marker orbit paths overlaid.
A Poincaré-style diagnostic for checking particle confinement or orbit topology against a background field.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
field | xarray.DataArray | required | The field, drawn with plot_slice(). |
view | View | required | The slice of field (see View); view.x and view.y must be given. |
orbits | xarray.Dataset | required | An orbits product with position variables named after view.x and view.y (e.g.
its logical coordinates, to overlay directly on a logical-coordinates slice). |
max_markers | int | 200 | Draw only the first max_markers markers. Default: 200. |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
cmap | str or matplotlib.colors.Colormap | None | The colormap of the field. Default: "viridis". |
Returns
PlotResult- The figure, the axes, the mesh and the orbit paths.
Examples
>>> plot_field_with_orbits(... phi.isel(t=-1),... View(x="eta1", y="eta2", isel={"eta3": 0}),... out.orbits["ions"],... )plot_lineoutfunction#
def plot_lineout(data: xr.DataArray, *, x: str | None = None, ax=None, title=None, reference=None, x_of=None, xlabel=None, rationals: int | None = None, nfp: int | None = None)Plot a one-dimensional profile along its one remaining coordinate.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | The profile: every dimension but one already selected. |
x | str | None | The remaining dimension, as a check. Default: whichever it is. |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
title | str | None | The axes title. Default: the array’s label. |
reference | callable, array, (x, y) pair or dict | None | Exact or expected profiles, drawn dashed: a function of the plotted x (or of x
and t, taking the profile’s time), a 1-D xarray.DataArray (drawn over its own
coordinate), an (x, y) pair, or a dict of labels to these. |
x_of | callable | None | Maps the coordinate to the plotted axis, e.g. lambda eta1: L * eta1. |
xlabel | str | None | The horizontal axis label. Default: the coordinate’s label. |
rationals | int | None | Mark where a rotational transform (or safety factor) profile takes its rationals
lowest-order rational values n/m: a dotted line at each value, labeled, and a point
at each crossing (see plasma_plots.analysis.rational_surfaces()). Default: none. |
nfp | int | None | With rationals: the numerators n are multiples of it. Default: the profile’s
nfp attribute, else 1. |
Returns
PlotResult- The figure, the axes and the drawn lines.
Raises
ValueError- If more or fewer than one dimension remains, or
xis not the remaining one.
Examples
>>> plot_lineout(... phi.isel(t=-1, eta2=0, eta3=0), reference=lambda x: np.sin(np.pi * x)... )>>> # GVEC's ι(ρ) with its 4 lowest-order n/m>>> plot_lineout(ev.iota, rationals=4)plot_loss_mapfunction#
def plot_loss_map(markers: xr.Dataset, *, x: str = 'v_par', y: str | None = None, t=0, absB=None, ax=None, s: int = 10, cmap=None, title: str | None = None)Which markers are lost, over their initial phase-space position, colored by when.
Confined markers are grey; lost ones are colored by their loss time, so prompt losses (the loss cone, unconfined orbits) stand out from slow ones (transport, collisions).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
markers | xarray.Dataset | required | An orbits product over (t, marker). |
x | str | 'v_par' | The quantity along the horizontal axis: a variable, or "energy", "pitch" or
"speed" (see loss_map()). Default: "v_par". |
y | str | None | The vertical one. Default: "mu", or "v_perp" without mu. |
t | int or float | 0 | The time of the plotted positions: an integer position (default 0) or a float
nearest value. |
absB | callable | None | |B|(x, y, z), for "energy" and "pitch". |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
s | int | 10 | The marker size, in points². Default: 10. |
cmap | str or matplotlib.colors.Colormap | None | The colormap of the loss time. Default: "plasma". |
title | str | None | The title. Default: how many markers are lost. |
Returns
PlotResult- The figure, the axes and the two scatters;
data["losses"]holds theloss_map().
Examples
>>> plot_loss_map(orbits, x="energy", y="pitch", absB=absB)plot_lost_fractionfunction#
def plot_lost_fraction(markers: xr.Dataset, *, weight: str | None = None, percent: bool = True, ax=None, title: str | None = None)The fraction of markers lost from the domain, against time.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
markers | xarray.Dataset | required | A marker Dataset over (t, marker), e.g. an orbits product. |
weight | str | None | Weigh each marker by its initial value of this variable, i.e. count particles rather than markers. Default: count markers. |
percent | bool | True | Show percentages. Default: True. |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
title | str | None | The title. Default: the final fraction. |
Returns
PlotResult- The figure, the axes and the line;
data["lost_fraction"]holds the fraction.
Examples
>>> plot_lost_fraction(orbits)plot_marker_densityfunction#
def plot_marker_density(markers: xr.Dataset, *, x: str = 'eta1', weight: str | None = 'weight', against: xr.DataArray | None = None, bins: int = 32, normalize: bool = True, ax=None, title: str | None = None, **selection)Where the markers are against what they represent: the marker density along one coordinate.
Three profiles, each normalized to unit mean magnitude by default so that their shapes
compare: the
number of markers per unit length (the sampling density, where the markers were loaded),
the weighted density (what they represent: the physical density of a full-f run, the
perturbation of a δf run) and, given against, a reference field such as the density
the code computed or the equilibrium profile. Importance sampling shows as a sampling
density that differs from the physical one.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
markers | xarray.Dataset | required | A marker Dataset with the position variable x over (t, marker). |
x | str | 'eta1' | The position variable to bin over, e.g. "eta1" or "x". Default: "eta1". |
weight | str | 'weight' | The weight variable, for the weighted density; None leaves it out. Default:
"weight" (skipped when the Dataset has no such variable). |
against | xarray.DataArray | None | A reference profile over the same coordinate (every other dimension selected, or with
t matching markers), drawn dashed. Default: none. |
bins | int | 32 | The number of bins. Default: 32. |
normalize | bool | True | Divide each profile by the mean of its magnitude, so that the shapes compare (a δf perturbation sums to nearly nothing, so its plain mean would not do). Default: True. |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
title | str | None | The title. Default: "marker density". |
**selection | {} | The time: t=-1 (default, the last) or a float nearest value. |
Returns
PlotResult- The figure, the axes and the lines;
dataholds thesamplingandweighteddensities.
Examples
>>> plot_marker_density(orbits, x="eta1", against=n.isel(eta2=0, eta3=0), t=-1)plot_marker_pathsfunction#
def plot_marker_paths(orbits, *, x: str = 'x', y: str = 'y', markers=6, near=None, background: xr.DataArray | None = None, background_options: dict | None = None, t=0, ax=None, cmap='viridis')Paths of a few markers in a plane, with their start (circle) and end (cross).
Samples after a marker leaves the domain are dropped.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
orbits | xarray.Dataset or xarray.DataArray | required | An orbits product with the quantities x and y (see prepare_orbits()). |
x | str | 'x' | The quantity along the horizontal axis. Default: "x". |
y | str | 'y' | The quantity along the vertical axis. Default: "y". |
markers | int or sequence of int | 6 | A number of markers (spread evenly over the saved markers) or a list of marker indices.
Default: 6. |
near | sequence of (float, float) | None | Picks instead the marker starting closest to each of a list of (x, y) points, e.g. a
row across the domain. |
background | xarray.DataArray | None | A field drawn behind the paths at the time t: on its own x/y dimensions if
it has them (a Cartesian field), in logical coordinates if x/y are
eta1/eta2/eta3, else in the physical plane of x/y (the field then
needs its X, Y, Z coordinates). |
background_options | dict | None | Passed to plot_slice() for the background, e.g. dict(levels=12, fill=False)
for the contour lines of a stream function. |
t | int or float | 0 | The time of the background: an integer position or a float value. Default: 0, the
first. |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
cmap | str or matplotlib.colors.Colormap | 'viridis' | The colormap the path colors are taken from. Default: "viridis". |
Returns
PlotResult- The figure, the axes, the background mesh (if any), the paths and the start and end
markers;
data["markers"]lists the chosen marker indices.
Examples
>>> plot_marker_paths(... out.orbits["ions"],... near=[(0.2, 0.5), (0.5, 0.5), (0.8, 0.5)],... background=psi,... )plot_marker_scatterfunction#
def plot_marker_scatter(markers: xr.Dataset, *, x: str, y: str, color: str | None = None, ax=None, cmap=None, s: int = 8, color_at=None, background: xr.DataArray | None = None, background_options: dict | None = None, equal_aspect: bool | None = None, **selection)Scatter marker positions from a Dataset (an orbits product, or any per-marker data).
Useful for checking a marker loading scheme, or visualizing an SPH particle cloud colored by density or a tracer.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
markers | xarray.Dataset | required | The per-marker data, with a marker dimension. |
x | str | required | The data variable along the horizontal axis, e.g. the position "x". |
y | str | required | The data variable along the vertical axis, e.g. the position "y". |
color | str | None | A data variable to color the markers by, e.g. a Lagrangian tracer, weight or density, with a color bar. Default: one color. |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
cmap | str or matplotlib.colors.Colormap | None | The colormap for color. Default: "viridis". |
s | int | 8 | The marker size, in points². Default: 8. |
color_at | int or float | None | Take the colors at another time (an integer position such as 0, or a float value),
e.g. each marker’s initial position, to follow where fluid parcels go. Default: the
selected time. |
background | xarray.DataArray | None | A field drawn behind the markers at the same time (select its other dimensions first):
on its own x/y dimensions if it has them (a Cartesian field), in logical
coordinates if x/y are eta1/eta2/eta3, else in the physical plane of
x/y (x, y, z; the field then needs its X, Y, Z
coordinates). |
background_options | dict | None | Passed to plot_slice() for the background (e.g. cmap, levels,
fill=False). |
equal_aspect | bool | None | Draw both axes to the same scale. Default: when x and y have the same units
attribute (e.g. two positions), not for a phase space such as x against vx. |
**selection | {} | The remaining dimensions, such as t, exactly like [ArrayPlots.lineout()][ArrayPlots.lineout]: an
integer is a position (t=-1 the last), a float the nearest coordinate value. |
Returns
PlotResult- The figure, the axes, the background mesh (if any) and the scatter.
Raises
ValueError- If
xoryis not a data variable, or dimensions other thanmarkerremain. TypeError- If a selected name is not a dimension, or its value is neither an integer nor a float.
Examples
>>> plot_marker_scatter(... out.orbits["ions"], x="x", y="y", color="weights", t=-1... )plot_marker_trajectoriesfunction#
def plot_marker_trajectories(orbits, *, ax=None, max_markers=200, show_paths=None)Plot a static 3-D trajectory overview.
Interactive marker UI is intentionally separate. The last positions are marked with dots.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
orbits | xarray.Dataset or xarray.DataArray | required | An orbits product with the quantities x, y and z: an xarray.Dataset with
one (t, marker) variable per saved quantity, as Struphy saves them; a single
(t, marker, quantity) xarray.DataArray works too. |
ax | mpl_toolkits.mplot3d.Axes3D | None | A 3-D axes to draw into. Default: a new figure. |
max_markers | int | 200 | Draw only the first max_markers markers. Default: 200. |
show_paths | bool | None | Draw each marker’s path, not only its last position. Default: True for up to 200
markers. |
Returns
PlotResult- The figure, the axes, the paths and the scatter of last positions.
Examples
>>> plot_marker_trajectories(out.orbits["ions"], max_markers=50)plot_measured_vs_theoryfunction#
def plot_measured_vs_theory(measured, theory=None, *, show_error: bool = True, xlabel: str | None = None, ylabel: str | None = None, title: str | None = None, logx: bool = False, logy: bool = False)Measured values against a theory curve over a parameter, with their relative error.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
measured | xarray.DataArray, (x, y) pair or dict | required | A 1-D array over the parameter (e.g. trace_branch(...).omega over k, growth
rates over mode numbers), an (x, y) pair, or a dict of labels to these (e.g. several
runs or methods), drawn as markers. |
theory | callable, (x, y) pair or dict | None | A function of the parameter, an (x, y) pair, or a dict of labels to these, drawn as
lines over the measured range. Complex values (e.g. from plasma_plots.theory)
are compared by their real part; for growth or damping rates pass
lambda k: f(k).imag. |
show_error | bool | True | Add a second panel with (measured - theory) / theory against the first theory, for
every measured series. A theory given as points is interpolated linearly between them
(NaN outside them). Default: True. |
xlabel | str | None | The horizontal axis label. Default: the coordinate label of the first measured array. |
ylabel | str | None | The value axis label. Default: the value label of the first measured array. |
title | str | None | The title. Default: "Measured against theory". |
logx | bool | False | Use a logarithmic parameter axis. Default: False. |
logy | bool | False | Use a logarithmic value axis. Default: False. |
Returns
PlotResult- The figure, the axes (an array of two with the error panel), and the drawn lines and markers.
Raises
ValueError- If there are no measured values, or a measured array is not one-dimensional.
Examples
>>> plot_measured_vs_theory(... branch.omega, theory=lambda k: np.sqrt(1 + 3 * k**2), xlabel="k"... )plot_orbit_classificationfunction#
def plot_orbit_classification(orbits, *, x: str = 'v_par', y: str | None = None, v_par: str = 'v_par', t=0, ax=None, s: int = 8)Scatter markers in a phase-space plane, colored as passing, trapped or lost.
The classification is classify_orbits() (Struphy’s criteria:
v_par reversing sign means trapped, a zeroed marker means lost). The default plane, initial
v_par against mu, shows the trapped-passing boundary directly; x="p_phi" gives the
usual canonical-momentum diagram when p_phi was saved. The legend gives each class’s
marker count and fraction.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
orbits | xarray.Dataset or xarray.DataArray | required | An orbits product with v_par and the quantities x and y (see
prepare_orbits()). |
x | str | 'v_par' | The quantity along the horizontal axis. Default: "v_par". |
y | str | None | The quantity along the vertical axis. Default: the magnetic moment mu
(Particles5D), or v_perp if there is no mu (Particles5Dvperp). |
v_par | str | 'v_par' | The parallel velocity the classification uses. Default: "v_par". |
t | int or float | 0 | The time of the plotted values: an integer position (default 0, the initial
phase-space position, before any marker is lost; -1 the last), or a float nearest
value. |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
s | int | 8 | The marker size, in points². Default: 8. |
Returns
PlotResult- The figure, the axes and one scatter per class present;
data["counts"]holds the number of markers per class ("passing","trapped","lost").
Examples
>>> plot_orbit_classification(out.orbits["ions"], x="p_phi")plot_orbit_gridfunction#
def plot_orbit_grid(orbits, *, markers=8, ncols: int = 4, boundary: xr.DataArray | None = None, color_by: str | None = 'classification')One small poloidal panel (R against z) per marker, sharing axes.
Colored by orbit class, for looking at individual orbits (bananas, passing, lost) side by side. Samples where a marker is lost are dropped.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
orbits | xarray.Dataset or xarray.DataArray | required | An orbits product with the quantities x, y and z (see
prepare_orbits()). |
markers | int or sequence of int | 8 | A number of markers (spread over the classes when v_par is saved) or a list of marker
indices. Default: 8. |
ncols | int | 4 | The number of panels per row. Default: 4. |
boundary | xarray.DataArray | None | A field with physical coordinates whose outer (last eta1) surface is drawn in every
panel, at its first eta3. |
color_by | str or None | 'classification' | "classification" colors by orbit class (when v_par is saved); "t" or the name
of a (t, marker) variable (e.g. "v_par") colors each orbit along its path, with
one color bar for all panels; None draws every orbit in one color. The panel titles
name the class whenever v_par is saved. Default: "classification". |
Returns
PlotResult- The figure, the 2-D array of axes and the drawn lines;
data["markers"]lists the marker indices shown.
Examples
>>> plot_orbit_grid(out.orbits["ions"], markers=12, boundary=phi)plot_orbit_poloidalfunction#
def plot_orbit_poloidal(orbits, *, color_by: str | None = 'classification', max_markers: int = 200, boundary: xr.DataArray | None = None, ax=None)Marker orbits projected onto the poloidal plane, R = √(x² + y²) against z.
Passing orbits circle the magnetic axis, trapped ones trace bananas. Samples where a marker is lost are dropped.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
orbits | xarray.Dataset or xarray.DataArray | required | An orbits product with the quantities x, y and z (see
prepare_orbits()). |
color_by | str or None | 'classification' | "classification" colors by orbit class (needs v_par, see
classify_orbits()); "t" or the name of a
(t, marker) variable (e.g. "v_par") colors each orbit along its path, with a
color bar; None gives one color per marker. Default: "classification". |
max_markers | int | 200 | Draw only the first max_markers markers. Default: 200. |
boundary | xarray.DataArray | None | Any field with physical coordinates, whose outer (last eta1) surface is drawn at its
first eta3 as the domain boundary. |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
Returns
PlotResult- The figure, the axes and the drawn lines.
Examples
>>> plot_orbit_poloidal(out.orbits["ions"], boundary=phi)plot_orbit_quantitiesfunction#
def plot_orbit_quantities(orbits, *, quantities=('v_par', 'mu'), markers=6, drift_of: bool | tuple = ('mu'))Saved orbit quantities over time, one panel per quantity and one line per marker.
Samples where a marker is lost are dropped.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
orbits | xarray.Dataset or xarray.DataArray | required | An orbits product with the quantities (see prepare_orbits()). |
quantities | sequence of str | ('v_par', 'mu') | The quantities, one panel each. Default: ("v_par", "mu"). |
markers | int or sequence of int | 6 | A number of markers (spread over the classes if v_par is saved, so passing and
trapped ones both show) or a list of marker indices. Default: 6. |
drift_of | bool or sequence of str | ('mu') | The quantities shown as their change since t = 0 (default ("mu",), an invariant
of guiding-center motion, so its drift measures the pusher’s accuracy); True for
all, False for none. |
Returns
PlotResult- The figure, the array of axes (one per quantity) and the drawn lines.
Examples
>>> plot_orbit_quantities(... out.orbits["ions"],... quantities=("v_par", "mu", "p_phi"),... markers=[0, 5, 9],... )plot_panelsfunction#
def plot_panels(data: xr.DataArray, *, view=None, nrows=3, ncols=4, shared_clim=True, title=None, run_label=None, vmin=None, vmax=None, cmap=None, equal_aspect=None, symmetric=False, robust=False, levels=None, fill=True, overlays=None, xlabel=None, ylabel=None, colorbar_label=None)Plot snapshots with common color limits over the entire selected sweep by default.
The nrows * ncols panels show evenly spaced values of the sweep dimension, from its
first to its last value.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | The field, with the sweep dimension; other dimensions not drawn are selected by
view. |
view | View | None | Which dimensions to select, which two to draw, in which coordinates, and the sweep
dimension (view.sweep, default t) to run over (see View). Default:
View(). |
nrows | int | 3 | The number of rows of panels. Default: 3. |
ncols | int | 4 | The number of columns of panels. Default: 4. |
shared_clim | bool | True | Take the color limits once from all the selected data (every value of the sweep), so that
every slice shares them; False gives each slice its own. Default: True. |
title | str | None | The figure title, above the panels. Default: the array’s label. |
run_label | str | None | A run description shown after the title. Default: the run shared by the data (see
shared_run_label()); "" for none. |
vmin | float | None | The lower color limit. Default: from the data (see symmetric and robust). |
vmax | float | None | The upper color limit. Default: from the data (see symmetric and robust). |
cmap | str or matplotlib.colors.Colormap | None | The colormap. Default: "viridis". |
equal_aspect | bool | None | Draw both axes to the same scale. Default: True in physical coordinates, False in
logical ones. |
symmetric | bool | False | Center the color limits on zero (-v, v), as a diverging colormap for a perturbation
needs. Default: False. |
robust | bool | False | Take the color limits from the 1st and 99th percentiles instead of the extremes, so a few
outliers do not wash out the rest. Default: False. |
levels | int or sequence of float | None | Contour lines of the slice: a number of levels spaced evenly between the color limits, or
the levels themselves. Drawn in black over the colors, or in the colormap’s colors with
fill=False. Default: no contour lines. |
fill | bool | True | Fill the slice with colors; False leaves it transparent, e.g. to show only the contour
lines of levels. Default: True. |
overlays | dict | None | What to draw on top of the slice, by key (other keys raise a
Lines and points do not widen the axes and are listed in a legend. |
xlabel | str | None | The horizontal axis label. Default: the coordinate’s name and units. |
ylabel | str | None | The vertical axis label. Default: the coordinate’s name and units. |
colorbar_label | str | None | The color bar label. Default: the array’s label and units. |
Returns
PlotResult- The figure, the 2-D array of axes and the meshes.
Raises
ValueError- If the sweep dimension is missing or empty,
nrowsorncolsis not positive, oroverlayshas unknown keys.
Examples
>>> plot_panels(phi.isel(eta3=0), nrows=2, ncols=3, symmetric=True)plot_profilesfunction#
def plot_profiles(data: xr.DataArray, *, x: str, over: str = 't', at=None, x_of=None, xlabel: str | None = None, ax=None, title: str | None = None, reference=None)Several one-dimensional profiles along x in one axes, one per value of over.
The profiles are colored from dark to light along the viridis colormap.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | The profiles, with exactly the dimensions x and over (select the rest first). |
x | str | required | The dimension along the horizontal axis. |
over | str | 't' | The dimension to draw one profile per value of. Default: "t". |
at | int, float or sequence of these | None | The values of over: integers are positions, floats nearest values. Default: four
evenly spaced positions. |
x_of | callable | None | Maps the x coordinate to the plotted axis, e.g. lambda eta1: 0.1 + 0.9 * eta1
for the minor radius of a hollow torus. |
xlabel | str | None | The horizontal axis label. Default: the coordinate’s label, or "r" with x_of. |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
title | str | None | The axes title. Default: the array’s label. |
reference | callable, array, (x, y) pair or dict | None | Exact or expected profiles, drawn in each profile’s color in dashed styles: a function
of the plotted x (or of x and the value of over), a 1-D xarray.DataArray
(drawn over its own coordinate), an (x, y) pair, or a dict of labels to these. |
Returns
PlotResult- The figure, the axes and the drawn lines.
Raises
ValueError- If
datahas dimensions other thanxandover.
Examples
>>> plot_profiles(phi.isel(eta2=0, eta3=0), x="eta1", at=[0, 0.5, -1])plot_scalarsfunction#
def plot_scalars(scalars, *, names=None, exclude=SCALARS_EXCLUDE, relative_to=None, logy=False, run_label=None)Plot every scalar time series in one axes.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
scalars | xarray.Dataset or mapping of str to xarray.DataArray | required | The time series (e.g. out.scalars), each with the dimension t. |
names | sequence of str | None | The scalars to plot. Default: all but exclude. |
exclude | sequence of str | SCALARS_EXCLUDE | Scalars left out when names is not given. Default: ("time",). |
relative_to | str | None | The name of a scalar to divide every series by. Default: none. |
logy | bool | False | Use a logarithmic value axis. Default: False. |
run_label | str | None | A run description shown as the figure’s suptitle. Default: the run shared by the
scalars (see shared_run_label()); "" for none. |
Returns
PlotResult- The figure, the axes and one line per scalar.
Raises
ValueError- If there are no scalars to plot.
KeyError- If a name in
namesis not a scalar.
Examples
>>> plot_scalars(out.scalars, names=["en_E", "en_B"], logy=True)plot_slicefunction#
def plot_slice(data: xr.DataArray, *, view=None, ax=None, vmin=None, vmax=None, equal_aspect=None, title=None, run_label=None, cmap=None, shared_clim=True, symmetric=False, robust=False, levels=None, fill=True, overlays=None, xlabel=None, ylabel=None, colorbar_label=None)Render one selected two-dimensional slice.
Every dimension but the two drawn must be selected, by the data itself or by view; a
sweep dimension (t) left over must be selected too, or be drawn as x or y.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | The field; dimensions not drawn are selected by view. |
view | View | None | Which dimensions to select, which two to draw and in which coordinates (see View).
Default: View(), the two remaining dimensions in logical coordinates. |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
vmin | float | None | The lower color limit. Default: from the data (see symmetric and robust). |
vmax | float | None | The upper color limit. Default: from the data (see symmetric and robust). |
equal_aspect | bool | None | Draw both axes to the same scale. Default: True in physical coordinates, False in
logical ones. |
title | str | None | The axes title. Default: the array’s label. |
run_label | str | None | A run description shown as the figure’s suptitle (only for a new figure). Default: the
run shared by the data (see shared_run_label()); "" for none. |
cmap | str or matplotlib.colors.Colormap | None | The colormap. Default: "viridis". |
shared_clim | bool | True | Take the color limits once from all the selected data (every value of the sweep), so that
every slice shares them; False gives each slice its own. Default: True. |
symmetric | bool | False | Center the color limits on zero (-v, v), as a diverging colormap for a perturbation
needs. Default: False. |
robust | bool | False | Take the color limits from the 1st and 99th percentiles instead of the extremes, so a few
outliers do not wash out the rest. Default: False. |
levels | int or sequence of float | None | Contour lines of the slice: a number of levels spaced evenly between the color limits, or
the levels themselves. Drawn in black over the colors, or in the colormap’s colors with
fill=False. Default: no contour lines. |
fill | bool | True | Fill the slice with colors; False leaves it transparent, e.g. to show only the contour
lines of levels. Default: True. |
overlays | dict | None | What to draw on top of the slice, by key (other keys raise a
Lines and points do not widen the axes and are listed in a legend. |
xlabel | str | None | The horizontal axis label. Default: the coordinate’s name and units. |
ylabel | str | None | The vertical axis label. Default: the coordinate’s name and units. |
colorbar_label | str | None | The color bar label. Default: the array’s label and units. |
Returns
PlotResult- The figure, the axes and the mesh.
Raises
ValueError- If more or other dimensions than the two drawn remain, or
overlayshas unknown keys.
Examples
>>> plot_slice(phi.isel(t=-1, eta3=0), symmetric=True, cmap="RdBu_r")>>> plot_slice(... phi.isel(t=0),... view=View(isel={"eta3": 0}, coordinates="physical"),... levels=10,... )plot_timeseriesfunction#
def plot_timeseries(data, *, ax=None, logy=True, fit: GrowthFit | None = None, title=None, run_label=None, reference=None)Plot one or more time series, each on its own time grid.
Series of different runs (attrs["run_name"]) are labeled by run.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray or sequence of xarray.DataArray | required | The time series, each with the only dimension t. |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
logy | bool | True | Use a logarithmic value axis. Default: True. |
fit | GrowthFit | None | Fit an exponential growth rate to each series (see
plasma_plots.analysis.growth_rate()) and draw it dashed, with the fit window shaded.
Default: no fit. |
title | str | None | The axes title. Default: the first series’ label. |
run_label | str | None | A run description shown as the figure’s suptitle (only for a new figure). Default: the run
shared by all series (see shared_run_label()); "" for none. |
reference | callable, array, (t, values) pair or dict | None | Exact or expected curves, drawn dashed in black: a function of t, a 1-D
xarray.DataArray over t, a (t, values) pair, or a dict of labels to these, e.g.
{"exact": lambda t: A * np.exp(-gamma * t)} or an envelope
{"+e^(-γt)": ..., "−e^(-γt)": ...}. |
Returns
PlotResult- The figure, the axes, the drawn lines, and in
fit_resultsoneFitResult(orNone) per series.
Raises
ValueError- If there is no series, or a series has dimensions other than
t.
Examples
>>> plot_timeseries(out.scalars.en_E, fit=GrowthFit(window=(5.0, 20.0)))plot_vectorfunction#
def plot_vector(data: xr.DataArray, *, x: str, y: str, components: tuple[int, int] = (0, 1), component_dim: str = 'component', ax=None, stride: int = 1, coordinates: Literal['logical', 'physical'] = 'logical')Render two components of a selected vector field with Matplotlib quivers.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | The vector field, with exactly the dimensions component_dim, x and y. |
x | str | required | The dimension along the horizontal axis. |
y | str | required | The dimension along the vertical axis. |
components | (int, int) | (0, 1) | The positions along component_dim of the two components drawn. Default: (0, 1). |
component_dim | str | 'component' | The dimension holding the components. Default: "component". |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
stride | int | 1 | Draw every stride-th arrow along x and y. Default: 1. |
coordinates | ('logical', 'physical') | "logical" | Place the arrows at the logical coordinates, or at the attached physical X, Y,
Z (then x and y must be two of eta1, eta2, eta3, and the axes
have equal scales). Default: "logical". |
Returns
PlotResult- The figure, the axes and the quiver.
Raises
ValueError- If other dimensions remain, or physical coordinates are requested for non-spatial
xandy.
Examples
>>> plot_vector(b_field.isel(t=-1, eta3=0), x="eta1", y="eta2", stride=4)plot_volume_slicesfunction#
def plot_volume_slices(data: xr.DataArray, *, indices: dict[str, int] | None = None, cmap=None)Show three orthogonal midpoint slices of a selected scalar volume.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | The volume, with exactly the dimensions eta1, eta2 and eta3. |
indices | dict of str to int | None | The index at which each dimension is held fixed, e.g. {"eta3": 0}. Default: the
middle index of every dimension. |
cmap | str or matplotlib.colors.Colormap | None | The colormap. Default: Matplotlib’s default. |
Returns
PlotResult- The figure, the three axes and their meshes.
Examples
>>> plot_volume_slices(phi.isel(t=-1), indices={"eta3": 0})plot_weight_histogramfunction#
def plot_weight_histogram(markers: xr.Dataset, *, weight: str = 'weight', t=-1, bins: int = 50, log: bool = True, density: bool = True, ax=None, title: str | None = None)The distribution of the marker weights at one or several times, with their statistics.
A δf scheme starts with weights near zero that spread as the perturbation grows; a growing
tail of large weights is where the noise of the estimate comes from. The legend gives the
mean and the standard deviation at each time, the title the relative noise of the total
(see weight_statistics()).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
markers | xarray.Dataset | required | A marker Dataset with the weights over (t, marker), e.g. an orbits product. |
weight | str | 'weight' | The weight variable. Default: "weight". |
t | (int, float or sequence) | -1 | The time(s): integer positions (-1 the last) or float nearest values, one or
several. Default: -1. |
bins | int | 50 | The number of bins, shared by all times. Default: 50. |
log | bool | True | A logarithmic count axis. Default: True. |
density | bool | True | Normalize each histogram to unit area. Default: True. |
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
title | str | None | The title. Default: the noise estimate at the last time shown. |
Returns
PlotResult- The figure, the axes and one outline per time;
data["statistics"]holds the weight statistics at the times shown.
Raises
ValueError- If
markershas no variableweight.
Examples
>>> plot_weight_histogram(orbits, t=[0, 0.5, -1])prepare_comparefunction#
def prepare_compare(first: xr.DataArray, second: xr.DataArray, *, mode: Literal['difference', 'ratio'] = 'difference') -> xr.DataArrayAlign two arrays and compute their difference or ratio, without rendering it.
Used by plot_compare().
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
first | xarray.DataArray | required | The first array. |
second | xarray.DataArray | required | The second array; only coordinates both share are kept. |
mode | ('difference', 'ratio') | "difference" | first - second, or first / second (NaN where second is zero). Default:
"difference". |
Returns
xarray.DataArray- The difference or ratio, named after the first array’s label and
mode.
prepare_continuous_spectrumfunction#
def prepare_continuous_spectrum(spectrum, x, modes) -> xr.DataArrayEvaluate a continuous spectrum omega(x) for each mode, as a (mode, branch, x) array.
Used by plot_continuous_spectrum().
Parameters
| Name | Type | Description |
|---|---|---|
spectrum | callable | Called as spectrum(x, *mode); must return a mapping of branch name to omega(x),
e.g. Struphy’s MhdContinousSpectraShearedSlab or MhdContinousSpectraCylinder from
struphy.dispersion_relations.analytic, whose modes are (m, n) pairs. |
x | array_like | The points to evaluate at. |
modes | sequence of tuple | The modes, each a tuple of mode numbers (a bare number is a 1-tuple). |
Returns
xarray.DataArrayomega, over(mode, branch, x); themodelabels are the mode numbers joined by commas ("1, 2").
Raises
ValueError- If
modesis empty.
prepare_lineoutfunction#
def prepare_lineout(data: xr.DataArray, *, x: str | None = None) -> xr.DataArrayCheck that a selected profile has one dimension left, and that it is x.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | The profile: every dimension but one already selected. |
x | str | None | The dimension that should remain. Default: whichever it is. |
Returns
xarray.DataArraydataitself, asplot_lineout()draws it.
Raises
ValueError- If more or fewer than one dimension remains, or
xis not the remaining one.
prepare_marker_scatterfunction#
def prepare_marker_scatter(markers: xr.Dataset, *, x: str, y: str, color: str | None = None, color_at=None, **selection) -> xr.DatasetThe per-marker positions and colors plot_marker_scatter() draws.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
markers | xarray.Dataset | required | Per-marker variables with a marker dimension (and usually t). |
x | str | required | The variables for the horizontal and vertical axes. |
y | str | required | The variables for the horizontal and vertical axes. |
color | str | None | The variable to color by. Default: none. |
color_at | int or float | None | Take the colors at another time (an integer position such as 0, or a float value).
Default: at the selected time. |
**selection | {} | The other dimensions, e.g. t: an integer is a position (t=-1 the last), a float the
nearest coordinate value. |
Returns
xarray.Datasetx,yandcolorovermarker. The colors are named after their variable, or"color"when that isxoryitself (e.g. colored by the initial position).
Raises
ValueError- If
x,yorcoloris not a variable, or dimensions other thanmarkerremain.
prepare_orbit_classificationfunction#
def prepare_orbit_classification(orbits, *, x: str = 'v_par', y: str | None = None, v_par: str = 'v_par', t=0) -> xr.DatasetEach marker’s x and y at time t together with its orbit class.
Used by plot_orbit_classification().
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
orbits | xarray.Dataset or xarray.DataArray | required | An orbits product (see prepare_orbits()). |
x | str | 'v_par' | The first quantity. Default: "v_par". |
y | str | None | The second quantity. Default: the magnetic moment mu (Particles5D), or v_perp if
there is no mu (Particles5Dvperp). |
v_par | str | 'v_par' | The parallel velocity the classification uses. Default: "v_par". |
t | int or float | 0 | The time, selected like any other dimension: an integer position (default 0, the
initial phase-space position, before any marker is lost; -1 the last), or a float
nearest value. |
Returns
xarray.Datasetxandyovermarker, andclassificationfromplasma_plots.analysis.classify_orbits()(0 passing, 1 trapped, -1 lost).
Raises
ValueError- If
xoryis not a data variable.
prepare_orbitsfunction#
def prepare_orbits(orbits, *, max_markers: int = 200, required=()) -> xr.DatasetNormalize an orbits product to its Dataset form and keep only the first max_markers.
orbits is an xarray.Dataset with one (t, marker) variable per saved quantity, as
Struphy saves them; a single (t, marker, quantity) xarray.DataArray works too. Used by plot_marker_trajectories() and
plot_field_with_orbits(); also available directly to get the same data without a plot.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
orbits | xarray.Dataset or xarray.DataArray | required | The orbits product. |
max_markers | int | 200 | Keep only the first max_markers markers. Default: 200. |
required | sequence of str | () | Quantities that must be present, e.g. ("x", "y", "z"). Default: none. |
Returns
xarray.Dataset- The orbits, one variable per quantity, with at most
max_markersmarkers.
Raises
ValueError- If a required quantity or the
markerdimension is missing.
prepare_vectorfunction#
def prepare_vector(data: xr.DataArray, *, x: str, y: str, components: tuple[int, int] = (0, 1), component_dim: str = 'component', stride: int = 1) -> xr.DataArraySelect and stride two components of a vector field, without rendering it.
Used by plot_vector(); also available directly, e.g. to hand the same
strided data to a different plotting library.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | The vector field, with exactly the dimensions component_dim, x and y. |
x | str | required | The first spatial dimension. |
y | str | required | The second spatial dimension. |
components | (int, int) | (0, 1) | The positions along component_dim of the two components. Default: (0, 1). |
component_dim | str | 'component' | The dimension holding the components. Default: "component". |
stride | int | 1 | Keep every stride-th point along x and y. Default: 1. |
Returns
xarray.DataArray- The two components, with dimensions
(component_dim, x, y).
Raises
ValueError- If other dimensions remain, or
strideis not positive.
prepare_viewfunction#
def prepare_view(data: xr.DataArray, view: View) -> xr.DataArrayEvery frame of a slice view at once: the data panels, viewers and animations draw.
Parameters
| Name | Type | Description |
|---|---|---|
data | xarray.DataArray | The labeled array. |
view | View | The selection and presentation (x, y, sweep, coordinates, plane). |
Returns
xarray.DataArray- The selection ordered
(sweep, x, y)(withoutsweepif it was selected). In physical coordinates, the periodic seam of a cell-centered grid is closed, as in every drawn frame.
Raises
ValueError- If other dimensions than
sweep,xandyremain, or the physical coordinates the plane needs are missing.
prepare_volume_slicesfunction#
def prepare_volume_slices(data: xr.DataArray, *, indices: dict[str, int] | None = None) -> dict[str, xr.DataArray]Three orthogonal midpoint (or chosen-index) planes through a scalar volume.
Used by plot_volume_slices().
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | The volume, with exactly the dimensions eta1, eta2 and eta3. |
indices | dict of str to int | None | The index at which each dimension is held fixed, e.g. {"eta3": 0}. Default: the
middle index of every dimension. |
Returns
dict of str to xarray.DataArray- One 2-D plane per dimension held fixed, keyed by that dimension (
"eta3","eta2","eta1"); each has the fixed index inattrs["fixed_index"].
Raises
ValueError- If
datahas other dimensions.
pyvista_volumefunction#
def pyvista_volume(data: xr.DataArray, *, name: str | None = None, cmap='viridis', opacity='linear')Create a PyVista volume view from a selected scalar field with X/Y/Z coordinates.
The returned plotter is not shown automatically; call plotter.show() in an
interactive session or use PyVista’s off-screen rendering options in batch jobs.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | The field, with exactly the dimensions eta1, eta2 and eta3 and the mapped
coordinates X, Y and Z. |
name | str | None | The name of the scalars in the PyVista grid. Default: the array’s label, else
"value". |
cmap | str | 'viridis' | The colormap. Default: "viridis". |
opacity | str or sequence of float | 'linear' | PyVista’s opacity transfer function. Default: "linear". |
Returns
pyvista.Plotter- The plotter with the volume and axes added, not yet shown.
Raises
ValueError- If
datahas other dimensions or lacksX,YorZ.
Examples
>>> pyvista_volume(phi.isel(t=-1)).show()resolve_marker_selectionfunction#
def resolve_marker_selection(dataset: xr.Dataset, selection: dict) -> xr.DatasetSelect dimensions of a Dataset: an integer is a position, a float the nearest value.
Parameters
| Name | Type | Description |
|---|---|---|
dataset | xarray.Dataset | The data, e.g. an orbits product. |
selection | dict | Dimension names to an integer position (t=-1 the last) or a float coordinate value. |
Returns
xarray.Dataset- The selected data.
Raises
TypeError- If a name is not a dimension of
dataset, or a value is neither an integer nor a float.
save_all_scalarsfunction#
def save_all_scalars(scalars, directory, *, names=None, exclude=SCALARS_EXCLUDE, logy=False, run_label=None, table='csv', file_format='png', dpi=110)Write a table, scalar overview and one figure per scalar.
Writes scalars.<table>, the overview scalars.<file_format> of plot_scalars()
and <name>.<file_format> from plot_timeseries() for each scalar into
directory, which is created if needed.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
scalars | xarray.Dataset or mapping of str to xarray.DataArray | required | The time series (e.g. out.scalars), each with the only dimension t. |
directory | str or pathlib.Path | required | The directory to write into. |
names | sequence of str | None | The scalars to write. Default: all but exclude. |
exclude | sequence of str | SCALARS_EXCLUDE | Scalars left out when names is not given. Default: ("time",). |
logy | bool | False | Use logarithmic value axes. Default: False. |
run_label | str | None | A run description shown as each figure’s suptitle. Default: the run shared by the
scalars (see shared_run_label()); "" for none. |
table | str | 'csv' | The table format, "csv" or "npz"; None or "" writes no table. Default:
"csv". |
file_format | str | 'png' | The figure format. Default: "png". |
dpi | int | 110 | The figure resolution. Default: 110. |
Returns
list of str- The written paths; empty if there are no scalars.
Examples
>>> save_all_scalars(out.scalars, "scalars", logy=True)save_figurefunction#
def save_figure(figure, name, *, formats=('html', 'png', 'plotly.json'), show: bool = False, frame: int | None = None, still=None, width: int = 1100, height: int = 650, scale: float = 2.0) -> list[str]Save a figure in several formats at once, as <name>.<format>.
The defaults write an interactive page, an image and the figure JSON of a Plotly figure: the
three files a web page needs. Like PlotResult.save(), this does nothing on MPI ranks
other than 0.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
figure | (PlotResult, Figure, plotly.graph_objects.Figure or matplotlib.figure.Figure) | required | What to save: the result of a plot (e.g. with backend="plotly"), a figure of
plasma_plots.figure(), or a figure made some other way. |
name | str or pathlib.Path | required | The files’ path without the format, e.g. "maxwell-wave" or "figures/energy". |
formats | sequence of str | ('html', 'png', 'plotly.json') | The formats, each appended to name after a dot; the last extension picks how it is
written, as in PlotResult.save(). Default: ("html", "png", "plotly.json"). |
show | bool | False | Show the figure first. Default: False. |
frame | int | None | For the image of a Plotly animation: the frame it shows (e.g. -1 for the last). The
page and the JSON keep the whole animation. Default: the first frame. |
still | plotly.graph_objects.Figure | None | A figure that the image shows instead, e.g. a view of an animation that is none of its
frames. The page and the JSON keep figure. |
width | int | 1100 | Width of an image of a Plotly figure, in layout pixels. Default: 1100. |
height | int | 650 | Height of an image of a Plotly figure, in layout pixels. Default: 650. |
scale | float | 2.0 | Resolution factor of an image of a Plotly figure. Default: 2. |
Returns
list of str- The paths written; empty on MPI ranks other than 0.
Examples
>>> dispersion = spectrum.plasma.plot.dispersion(kmin=0, backend="plotly")>>> # maxwell-wave.html, .png, .plotly.json>>> save_figure(dispersion, "maxwell-wave", show=True)>>> save_figure(movie, "phase-space", frame=len(movie.fig.frames) // 2)>>> save_figure(... go.Figure(go.Scatter(x=t, y=energy)), "energy", formats=("html",)... )save_framesfunction#
def save_frames(data: xr.DataArray, directory, *, view=None, step=1, prefix='frame', dpi=110, vmin=None, vmax=None, shared_clim=True, cmap=None, equal_aspect=None, title=None, symmetric=False, robust=False, levels=None, fill=True, overlays=None, xlabel=None, ylabel=None, colorbar_label=None)Export the configured sweep as PNGs, sharing color limits by default.
The files are named {prefix}_0000.png, {prefix}_0001.png, … in directory,
which is created if needed.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray | required | The field, with the sweep dimension; other dimensions not drawn are selected by
view. |
directory | str or pathlib.Path | required | The directory to write into. |
view | View | None | Which dimensions to select, which two to draw, in which coordinates, and the sweep
dimension (view.sweep, default t) to run over (see View). Default:
View(). |
step | int | 1 | Use every step-th value of the sweep. Default: 1. |
prefix | str | 'frame' | The start of each file name. Default: "frame". |
dpi | int | 110 | The resolution of the PNGs. Default: 110. |
vmin | float | None | The lower color limit. Default: from the data (see symmetric and robust). |
vmax | float | None | The upper color limit. Default: from the data (see symmetric and robust). |
shared_clim | bool | True | Take the color limits once from all the selected data (every value of the sweep), so that
every slice shares them; False gives each slice its own. Default: True. |
cmap | str or matplotlib.colors.Colormap | None | The colormap. Default: "viridis". |
equal_aspect | bool | None | Draw both axes to the same scale. Default: True in physical coordinates, False in
logical ones. |
title | str | None | The title, followed in each frame by the sweep value. Default: the array’s label. |
symmetric | bool | False | Center the color limits on zero (-v, v), as a diverging colormap for a perturbation
needs. Default: False. |
robust | bool | False | Take the color limits from the 1st and 99th percentiles instead of the extremes, so a few
outliers do not wash out the rest. Default: False. |
levels | int or sequence of float | None | Contour lines of the slice: a number of levels spaced evenly between the color limits, or
the levels themselves. Drawn in black over the colors, or in the colormap’s colors with
fill=False. Default: no contour lines. |
fill | bool | True | Fill the slice with colors; False leaves it transparent, e.g. to show only the contour
lines of levels. Default: True. |
overlays | dict | None | What to draw on top of the slice, by key (other keys raise a
Lines and points do not widen the axes and are listed in a legend. |
xlabel | str | None | The horizontal axis label. Default: the coordinate’s name and units. |
ylabel | str | None | The vertical axis label. Default: the coordinate’s name and units. |
colorbar_label | str | None | The color bar label. Default: the array’s label and units. |
Returns
list of str- The paths of the written files, in order.
Raises
ValueError- If
stepis not a positive integer, the sweep dimension is missing or empty, oroverlayshas unknown keys.
Examples
>>> save_frames(phi.isel(eta3=0), "frames", step=5, symmetric=True)shared_run_labelfunction#
def shared_run_label(data, default='') -> strThe run description shared by all arrays (attrs["run"]), or default.
Arrays loaded from a [Output][struphy.Output] carry it; arrays from different runs share none.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data | xarray.DataArray, xarray.Dataset or sequence of these | required | The arrays. |
default | str | '' | Returned when no array has a run description. Default: "". |
Returns
str- The shared run description;
""if the arrays come from different runs,defaultif none has one.
show_equilibriumfunction#
def show_equilibrium(equil, domain, *, scalars: str = 'p0', cmap='viridis', n1=40, n2=48, n3=10, clip=True)A PyVista cutaway view of a fluid equilibrium’s scalar field over its domain.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
equil | struphy.fields_background.base.FluidEquilibrium | required | The equilibrium, e.g. from out.equil. |
domain | struphy.geometry.base.Domain | required | Its mapping (out.domain), called as domain(eta1, eta2, eta3, squeeze_out=False). |
scalars | str | 'p0' | One of equil’s profile methods ("p0", "n0", …). Default: "p0". |
cmap | str | 'viridis' | The colormap. Default: "viridis". |
n1 | int | 40 | Number of evaluation points along eta1. Default: 40. |
n2 | int | 48 | Number of evaluation points along eta2. Default: 48. |
n3 | int | 10 | Number of evaluation points along eta3. Default: 10. |
clip | bool | True | Cut away half the domain (normal to the physical X axis) to reveal the profile’s
interior, since the outer surface alone is often close to uniform (e.g. the plasma
edge). Default: True. |
Returns
pyvista.Plotter- The plotter with the mesh and axes added, not yet shown; call
plotter.show().
Examples
>>> show_equilibrium(out.equil, out.domain, scalars="n0").show()