Interactive plots with Plotly
Every plot that plasma-plots draws with Matplotlib can also be an interactive
Plotly figure: pass backend="plotly". You get hover values,
zoom and pan, legend entries you can click to hide or show a trace, and for animations a
slider with Play and Pause buttons. The figure works in a notebook, or saved as a
standalone HTML page.
pip install "plasma-plots[plotly]" # plotly, and kaleido for PNG/SVG/PDFOne keyword
Section titled “One keyword”n.plasma.plot.slice( coords="physical", plane="XY", t=-1, eta3=0, levels=[0.2], backend="plotly")Loading interactive chart…
The Plotly version is the Matplotlib plot converted, not a second implementation. The plot is drawn with Matplotlib as usual, off screen, and the finished figure is translated into Plotly: the same data, color limits, contour lines, overlays, fits, reference curves, labels and layout. So both backends always show the same thing. On a mapped grid like this annulus, the colors are an image of the Matplotlib mesh, and hovering shows the value of the cell under the cursor.
Nothing else changes: the selection by keyword, the options, fit_results and data all stay
the same.
result = energy.plasma.plot.timeseries(fit=(0.0, 2.0), backend="plotly")result.fit_results[0].rate # the same fit as with Matplotlibresult.fig # a plotly.graph_objects.Figureresult.fig.update_layout(height=600)result.save("energy.html") # a standalone pageresult.save("energy.png") # through kaleido; also .svg, .pdfresult.save("energy.json") # the figure JSON, e.g. for a websiteUnder MPI, other ranks than 0 get a SkippedPlot, whose save writes nothing, so a script
that saves its figures runs unchanged on several ranks. A figure you built yourself with plotly.graph_objects
saves the same way, with the same defaults and only on rank 0: PlotResult(figure).save("page.html")
(from plasma_plots.plotting import PlotResult).
To write the page, the image and the figure JSON at once, as a website needs them, use
save_figure. It takes a plot’s result or a figure of your own, and saves nothing on other ranks:
from plasma_plots import save_figure
# energy.html, energy.png, energy.plotly.jsonsave_figure(result, "energy", show=True)save_figure(movie, "phase-space", frame=-1) # the image shows the last frame# a plotly.graph_objects.Figure, only the pagesave_figure(my_figure, "orbits", formats=("html",))A space-time map of a (t, z) field is
a slice with time as one of its axes:
e_x.plasma.plot.slice(x="z", y="t", symmetric=True, cmap="RdBu_r", backend="plotly").
Loading interactive chart…
For every plot at once
Section titled “For every plot at once”import plasma_plots
# every plot from now on, e.g. in a notebookplasma_plots.set_backend("plotly")phi.plasma.plot.dispersion(dim="eta1")out.plot.energies()phi.plasma.plot.slice(t=-1, eta3=0, backend="matplotlib") # one exceptionAnimations and viewers
Section titled “Animations and viewers”An animation becomes a figure with a slider over the sweep and Play/Pause buttons. The
frames are drawn by the Matplotlib animation itself, so they match it frame by frame.
plot.viewer(...) becomes a figure with a slider and no buttons. A Matplotlib viewer has one
slider per remaining dimension; a Plotly figure has only one, so select all but one of them
first.
n.plasma.plot.animation( coords="physical", plane="XY", eta3=0, levels=[0.2], step=4, backend="plotly",)Loading interactive chart…
Every frame stores only what changes: parts that are the same in every frame (static contour
lines, the domain’s boundary, a fixed background, a mesh’s grid) are stored once. A contour level
the field reaches only in some frames is hidden in the others. On a mapped grid, each frame is an
image of the mesh; plasma_plots.plotly_backend.IMAGE_PIXELS = 600 (default 1200 along the
longer side) makes those images, and the page, smaller.
Still, a long, finely resolved sweep makes a large page. Use
step to keep every n-th frame, or max_frames for at most that many, evenly spaced (the first
and the last included). If the first frame is still featureless, the image of an animation can
show a later one; the page and the JSON keep the whole animation:
movie = f.plasma.plot.animation( x="eta1", y="v1", max_frames=150, backend="plotly")movie.save("phase-space.html")movie.save( "phase-space.png", frame=len(movie.fig.frames) // 2, width=1100, height=650, scale=2,)Spectra, particles, whole runs
Section titled “Spectra, particles, whole runs”The option works on every Matplotlib plot: time series, profiles, slices, panels, vectors,
spectra, dispersion relations, mode diagnostics, marker scatters, orbits, and out.plot.*.
phi.plasma.plot.power_spectrum( peaks=2, band=band, frequencies={"TAE gap-centre estimate": omega}, backend="plotly",)Loading interactive chart…
The guides show many of the plots with Plotly, folded under each Matplotlib figure.
What stays Matplotlib or PyVista
Section titled “What stays Matplotlib or PyVista”- The PyVista 3-D views (
isosurface,slices_3d,glyphs,streamlines,volume,movie,orbits_3d) are already interactive; see 3-D views. framesandsave_frameswrite PNG files for a movie.ax=, which draws into a Matplotlib axes you made, cannot be combined withbackend="plotly"(that raisesTypeError). To compose several plots into one Plotly figure, useplasma_plots.figure(..., backend="plotly")(see Several plots in one figure).out.plot.profile.*has its ownbackend="plotly", from scope-profiler (see Profiling).
The plotting functions (plasma_plots.plotting.plot_slice, …) return Matplotlib results,
which convert with .to_plotly():
from plasma_plots.plotting import plot_slice
plot_slice(phi.isel(t=-1, eta3=0)).to_plotly().save("phi.html")plasma_plots.plotly_backend.to_plotly(fig) and animation_to_plotly(animation) convert any
figure or animation of these functions. If you draw something they don’t know (e.g. a
histogram you added to a plot’s axes), it is left out with a ConversionWarning.