# plasma_plots.spectral_plots

*module*

Plots of the spectral diagnostics in [`plasma_plots.spectral`][plasma_plots.spectral].

Each returns a [`PlotResult`][plasma_plots.plotting.PlotResult], whose ``data`` holds what was drawn.

[View source](https://github.com/max-models/plasma-plots/blob/devel/src/plasma_plots/spectral_plots.py#L1-L1)

## plasma_plots.spectral_plots.OMEGA

*attribute* · *module attribute*

```python
OMEGA = '$\\omega$'
```

[View source](https://github.com/max-models/plasma-plots/blob/devel/src/plasma_plots/spectral_plots.py#L26-L26)

## plasma_plots.spectral_plots.plot_boozer_spectrum

*function*

```python
def plot_boozer_spectrum(data: xr.DataArray, *, top: int = 8, helicity=None, log: bool = True, angles: str = 'boozer', x_of=None, xlabel: str | None = None, title: str | None = None)
```

The strongest Boozer harmonics of ``|B|`` over the radius, and the quasi-symmetry error.

One line per harmonic ``(m, n)`` (``n`` the full-torus mode number, in the convention of
[`boozer_spectrum()`][plasma_plots.analysis.boozer_spectrum]). With ``helicity`` the symmetry-breaking
harmonics are dashed, and a second panel shows the quasi-symmetry error
[`quasisymmetry_error()`][plasma_plots.analysis.quasisymmetry_error] over the radius.

**Parameters**

- `data` (`xarray.DataArray`) — ``|B|`` on a Boozer grid, over ``(rho, theta_B, zeta_B)``.
- `top` (`int`) (default: `8`) — The number of harmonics drawn, strongest first. Default: 8.
- `helicity` (`('QA', 'QP', 'QH')`) (default: `"QA"`) — The symmetry to judge against (see [`quasisymmetry_error()`][plasma_plots.analysis.quasisymmetry_error]). Default: none.
- `log` (`bool`) (default: `True`) — A logarithmic amplitude axis. Default: True.
- `angles` (`('boozer', 'any')`) (default: `"boozer"`) — As for [`boozer_spectrum()`][plasma_plots.analysis.boozer_spectrum].
- `x_of` (`callable`) (default: `None`) — Maps the radial coordinate to the plotted axis, e.g. ``lambda rho: a * rho``.
- `xlabel` (`str`) (default: `None`) — The horizontal axis label. Default: the coordinate's.
- `title` (`str`) (default: `None`) — The title. Default: the harmonics' label.

**Returns**

- (`PlotResult`) — The figure, the axes (one, or two with ``helicity``) and the lines; ``data`` holds the ``amplitudes`` and, with ``helicity``, the ``error``.

> **See Also**
>
> [`plasma_plots.analysis.boozer_spectrum()`][plasma_plots.analysis.boozer_spectrum] : The harmonics.
> [`plot_mode_profiles()`][plasma_plots.spectral_plots.plot_mode_profiles] : The same for the harmonics of a mode at one frequency.

**Examples**

```pycon
>>> plot_boozer_spectrum(boozer.mod_B, top=8, helicity="QA")
```

[View source](https://github.com/max-models/plasma-plots/blob/devel/src/plasma_plots/spectral_plots.py#L956-L1072)

## plasma_plots.spectral_plots.plot_cross_spectrum

*function*

```python
def plot_cross_spectrum(cross: xr.Dataset, *, omega_max: float | None = None, title: str | None = None)
```

Plot the magnitude (and coherence, if present) and phase of a cross-spectrum.

The top panel shows the magnitude on a log axis spanning 6 decades, with the coherence on a
second axis; the bottom panel the phase in degrees at bins with at least 1e-3 of the peak
magnitude (elsewhere the phase is noise), with the phase at the peak marked.

**Parameters**

- `cross` (`xarray.Dataset`) — A [`cross_spectrum()`][plasma_plots.spectral.cross_spectrum] result reduced to ``omega`` only (e.g. summed over ``dims``).
- `omega_max` (`float`) (default: `None`) — The highest frequency shown. Default: all.
- `title` (`str`) (default: `None`) — The title. Default: the phase's label.

**Returns**

- (`PlotResult`) — The figure, the two axes and the drawn lines; ``data`` holds ``peak_omega`` and ``peak_phase_deg``, the frequency and phase (in degrees) of the strongest bin.

**Raises**

- `ValueError` — If dimensions other than ``omega`` remain.

**Examples**

```pycon
>>> plot_cross_spectrum(
...     cross_spectrum(phi, density, dims=["eta1", "eta2", "eta3"]),
...     omega_max=3.0,
... )
```

[View source](https://github.com/max-models/plasma-plots/blob/devel/src/plasma_plots/spectral_plots.py#L763-L866)

## plasma_plots.spectral_plots.plot_filtered

*function*

```python
def plot_filtered(data: xr.DataArray, result, *, ax=None, **selection)
```

Plot a probe of the signal (minus its mean) against its filtered reconstruction.

**Parameters**

- `data` (`xarray.DataArray`) — The original signal, with a ``t`` dimension.
- `result` (`TimeFilterResult or xarray.DataArray`) — A [`TimeFilterResult`][plasma_plots.spectral.TimeFilterResult] or a filtered array (e.g. from [`band_filter()`][plasma_plots.spectral.band_filter]) on the grid of ``data``.
- `ax` (`matplotlib.axes.Axes`) (default: `None`) — The axes to draw into. Default: a new figure.
- `**selection` (default: `{}`) — Every dimension but ``t``, selected by keyword: an integer is a position (``-1`` the last), a float the nearest coordinate value.

**Returns**

- (`PlotResult`) — The figure, the axes and the two lines (signal minus mean, filtered).

**Raises**

- `ValueError` — If a dimension other than ``t`` remains after the selection.

> **See Also**
>
> [`plasma_plots.spectral.filter_time()`][plasma_plots.spectral.filter_time] : The dominant-band filter.

**Examples**

```pycon
>>> result = filter_time(phi)
>>> plot_filtered(phi, result, eta1=0.5, eta2=0, eta3=0)
```

[View source](https://github.com/max-models/plasma-plots/blob/devel/src/plasma_plots/spectral_plots.py#L202-L266)

## plasma_plots.spectral_plots.plot_mode_amplitudes

*function*

```python
def plot_mode_amplitudes(modes: xr.DataArray, *, top: int = 6, fit=None, logy: bool = True, ax=None, title: str = 'Mode amplitudes')
```

Plot the amplitude of the strongest ``(m, n)`` modes over time, optionally with growth fits.

**Parameters**

- `modes` (`xarray.DataArray`) — [`mode_spectrum()`][plasma_plots.spectral.mode_spectrum] output (complex, turned into real amplitudes by [`mode_amplitudes()`][plasma_plots.spectral.mode_amplitudes]) or ``mode_amplitudes`` output, reduced to ``(t, m, n)`` or ``(t, mode)``: average or select other dimensions (e.g. ``eta1``) first.
- `top` (`int`) (default: `6`) — The number of modes drawn, those with the largest peak amplitude. Default: 6.
- `fit` (`(float, float) or bool`) (default: `None`) — Fit an exponential growth rate γ to each mode: a time window ``(t0, t1)``, or ``True`` for the whole record. Default: no fit.
- `logy` (`bool`) (default: `True`) — Logarithmic amplitude axis. Default: True.
- `ax` (`matplotlib.axes.Axes`) (default: `None`) — The axes to draw into. Default: a new figure.
- `title` (`str`) (default: `'Mode amplitudes'`) — The axes title. Default: ``"Mode amplitudes"``.

**Returns**

- (`PlotResult`) — The figure, the axes and the drawn lines. ``fit_results`` holds one growth fit per drawn mode (``None`` without ``fit``); ``data`` holds the plotted ``amplitudes``.

**Raises**

- `ValueError` — If dimensions other than ``t`` and the mode numbers remain.

**Examples**

```pycon
>>> modes = mode_spectrum(phi).max("eta1")
>>> plot_mode_amplitudes(modes, top=4, fit=(0.0, 20.0)).fit_results[0].rate
```

[View source](https://github.com/max-models/plasma-plots/blob/devel/src/plasma_plots/spectral_plots.py#L347-L436)

## plasma_plots.spectral_plots.plot_mode_map

*function*

```python
def plot_mode_map(modes: xr.DataArray, *, m_range: tuple[int, int] | None = None, n_range: tuple[int, int] | None = None, log: bool = True, cmap='viridis', ax=None, title: str | None = None)
```

Plot ``|amplitude|`` over the ``(m, n)`` plane of a mode spectrum.

**Parameters**

- `modes` (`xarray.DataArray`) — [`mode_spectrum()`][plasma_plots.spectral.mode_spectrum] output reduced to ``(m, n)``: select a time and average or select everything else first.
- `m_range` (`(int, int)`) (default: `None`) — The range of ``m`` shown, both ends included. Default: all.
- `n_range` (`(int, int)`) (default: `None`) — The range of ``n`` shown, both ends included. Default: all.
- `log` (`bool`) (default: `True`) — Color by ``log10(|amplitude|)``, clipped at 4 decades below the maximum. Default: True.
- `cmap` (`str or matplotlib.colors.Colormap`) (default: `'viridis'`) — The colormap. Default: ``"viridis"``.
- `ax` (`matplotlib.axes.Axes`) (default: `None`) — The axes to draw into. Default: a new figure.
- `title` (`str`) (default: `None`) — The axes title. Default: the spectrum's label.

**Returns**

- (`PlotResult`) — The figure, the axes and the mesh; ``data`` holds the plotted ``amplitude``.

**Raises**

- `ValueError` — If ``modes`` has dimensions other than ``m`` and ``n``.

**Examples**

```pycon
>>> plot_mode_map(
...     mode_spectrum(phi).isel(t=-1).sel(eta1=0.5, method="nearest"),
...     m_range=(-8, 8),
... )
```

[View source](https://github.com/max-models/plasma-plots/blob/devel/src/plasma_plots/spectral_plots.py#L439-L507)

## plasma_plots.spectral_plots.plot_mode_profiles

*function*

```python
def plot_mode_profiles(structure: xr.DataArray, *, x: str | None = None, x_of=None, xlabel: str | None = None, top: int = 4, phase: bool = True, title: str | None = None)
```

Plot the radial eigenfunction of each harmonic: ``|amplitude|`` (and phase) against ``x``.

The phase panel (unwrapped, in radians) shows whether the harmonics oscillate together, as
the coupled harmonics of a global eigenmode do. Phases are drawn only where a harmonic has
at least 5% of its peak amplitude.

**Parameters**

- `structure` (`xarray.DataArray`) — Complex over ``(x, m, n)``: typically ``mode_spectrum(mode_structure(field, omega))``, the complex amplitude of each poloidal harmonic at one frequency. Or real over ``(x, mode)``, e.g. ``mode_amplitudes`` of one snapshot's mode spectrum, which has no phase panel.
- `x` (`str`) (default: `None`) — The radial dimension. Default: the radial logical one (``eta1``, or GVEC's ``rho``).
- `x_of` (`callable`) (default: `None`) — Maps the ``x`` coordinate to the plotted axis, e.g. ``lambda eta1: 0.1 + 0.9 * eta1``. The axis is then labeled ``r``.
- `xlabel` (`str`) (default: `None`) — The horizontal axis label. Default: the coordinate's label, or ``r`` with ``x_of``.
- `top` (`int`) (default: `4`) — The number of strongest harmonics drawn; ``(m, n)`` and ``(-m, -n)`` count as one (the stronger is drawn, labeled by the half whose first nonzero number is positive). Default: 4.
- `phase` (`bool`) (default: `True`) — Add the phase panel (only for complex ``structure``). Default: True.
- `title` (`str`) (default: `None`) — The title. Default: the structure's label.

**Returns**

- (`PlotResult`) — The figure, the array of axes (amplitude, then phase) and the drawn lines; ``data`` holds the plotted ``profiles``.

**Raises**

- `ValueError` — If ``structure`` has dimensions other than ``x`` and the mode numbers.

> **See Also**
>
> [`plasma_plots.spectral.mode_structure()`][plasma_plots.spectral.mode_structure] : The complex amplitude at one frequency.

**Examples**

```pycon
>>> plot_mode_profiles(
...     mode_spectrum(mode_structure(phi, 0.42)).isel(n=0), top=3
... )
```

[View source](https://github.com/max-models/plasma-plots/blob/devel/src/plasma_plots/spectral_plots.py#L631-L760)

## plasma_plots.spectral_plots.plot_pencil_fit

*function*

```python
def plot_pencil_fit(data: xr.DataArray, fit: xr.Dataset, *, title: str | None = None)
```

Plot a [`matrix_pencil()`][plasma_plots.spectral.matrix_pencil] fit and its complex frequencies.

The left panel shows the signal against its reconstruction; the right panel the fitted
modes in the complex-frequency plane (ω against γ; above zero grows, below is damped),
sized by amplitude.

**Parameters**

- `data` (`xarray.DataArray`) — The real ``(t,)`` series that was fitted.
- `fit` (`xarray.Dataset`) — Its [`matrix_pencil()`][plasma_plots.spectral.matrix_pencil] fit.
- `title` (`str`) (default: `None`) — The title of the signal panel. Default: the array's label.

**Returns**

- (`PlotResult`) — The figure, the two axes and the drawn artists; ``data`` holds the ``fit`` and the reconstructed ``model``.

**Examples**

```pycon
>>> series = energy.sel(t=slice(0.0, 5.0))
>>> plot_pencil_fit(series, matrix_pencil(series, n_modes=2))
```

[View source](https://github.com/max-models/plasma-plots/blob/devel/src/plasma_plots/spectral_plots.py#L869-L953)

## plasma_plots.spectral_plots.plot_power_spectrum

*function*

```python
def plot_power_spectrum(data, *, dims=None, detrend: bool = True, window: str | None = None, peaks: int | None = None, band=None, frequencies: dict | None = None, logy: bool = True, dynamic_range: float | None = 8.0, omega_max: float | None = None, ax=None, title: str | None = None)
```

Plot the power per frequency bin, averaged over ``dims``, one line per remaining coordinate.

**Parameters**

- `data` (`xarray.DataArray or xarray.Dataset`) — A real signal with a ``t`` dimension (transformed by [`time_fft()`][plasma_plots.spectral.time_fft] with ``detrend`` and ``window``), a ``time_fft`` Dataset (its ``power`` is drawn), or an array over ``omega``: power, or complex coefficients (e.g. a two-sided [`fft()`][plasma_plots.spectral.fft]), drawn as their squared magnitude.
- `dims` (`str or sequence of str`) (default: `None`) — Dimensions to average the power over. At most one other dimension may remain, which gives one line per coordinate value. Default: every dimension but ``omega`` and ``component``.
- `detrend` (`bool`) (default: `True`) — Subtract the signal's mean before transforming. Default: True.
- `window` (`(None, 'hann')`) (default: `None`) — Window applied before transforming a signal. Default: None.
- `peaks` (`int`) (default: `None`) — Mark and label this many of the strongest peaks of a single line, with sub-bin frequencies (see [`spectral_peaks()`][plasma_plots.spectral.spectral_peaks]). Default: none.
- `band` (`(TimeFilterResult, xarray.Dataset or (float, float))`) (default: `None`) — A frequency band to shade: a [`filter_time()`][plasma_plots.spectral.filter_time] result or its ``spectrum`` (with one band selected), or an ``(omega_lo, omega_hi)`` pair.
- `frequencies` (`dict`) (default: `None`) — Named reference frequencies drawn as vertical dotted lines, e.g. ``{"gap": 0.8}`` for a continuum-gap estimate.
- `logy` (`bool`) (default: `True`) — Logarithmic power axis. Default: True.
- `dynamic_range` (`float`) (default: `8.0`) — With ``logy``, the number of decades shown below the peak (a removed mean leaves a near-zero DC bin). ``None`` for Matplotlib's limits. Default: 8.0.
- `omega_max` (`float`) (default: `None`) — The highest frequency shown. Default: all.
- `ax` (`matplotlib.axes.Axes`) (default: `None`) — The axes to draw into. Default: a new figure.
- `title` (`str`) (default: `None`) — The axes title. Default: the power's label.

**Returns**

- (`PlotResult`) — The figure, the axes and the drawn artists; ``data`` holds the plotted ``power`` and the ``peaks`` Dataset (``None`` without ``peaks``).

**Raises**

- `ValueError` — If more than one dimension besides ``omega`` remains, or ``peaks`` is given for several
lines.

> **See Also**
>
> [`plasma_plots.spectral.time_fft()`][plasma_plots.spectral.time_fft] : The transform behind the plot.

**Examples**

```pycon
>>> plot_power_spectrum(
...     phi.isel(eta2=0, eta3=0), peaks=2, frequencies={"theory": 1.2}
... )
```

[View source](https://github.com/max-models/plasma-plots/blob/devel/src/plasma_plots/spectral_plots.py#L55-L199)

## plasma_plots.spectral_plots.plot_radial_power

*function*

```python
def plot_radial_power(power: xr.DataArray, *, x: str | None = None, x_of=None, xlabel: str | None = None, continuum=None, log: bool = True, dynamic_range: float = 3.0, omega_max: float | None = None, cmap='magma', ax=None, title: str | None = None)
```

Plot where each frequency lives: power over ``(omega, x)``, e.g. radius, with continua.

A global eigenmode shows as a horizontal ridge in a continuum gap; a continuum-damped
oscillation follows the continuum curves.

**Parameters**

- `power` (`xarray.DataArray or xarray.Dataset`) — A [`time_fft()`][plasma_plots.spectral.time_fft] Dataset or power array reduced to ``(omega, x)``: average the angles away first.
- `x` (`str`) (default: `None`) — The spatial dimension. Default: the radial logical one (``eta1``, or GVEC's ``rho``).
- `x_of` (`callable`) (default: `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. The axis is then labeled ``r``.
- `xlabel` (`str`) (default: `None`) — The horizontal axis label. Default: the coordinate's label, or ``r`` with ``x_of``.
- `continuum` (`tuple or xarray.DataArray`) (default: `None`) — Continuous spectra overlaid as curves: a ``(spectrum, modes)`` pair as for [`plot_continuous_spectrum()`][plasma_plots.plotting.plot_continuous_spectrum], evaluated on the plotted axis, or a ``(mode, branch, x)`` array from [`prepare_continuous_spectrum()`][plasma_plots.plotting.prepare_continuous_spectrum].
- `log` (`bool`) (default: `True`) — Color by ``log10(power)``, clipped at ``dynamic_range`` decades below the maximum. Default: True.
- `dynamic_range` (`float`) (default: `3.0`) — With ``log``, the number of decades shown. Default: 3.0.
- `omega_max` (`float`) (default: `None`) — The highest frequency shown. Default: all.
- `cmap` (`str or matplotlib.colors.Colormap`) (default: `'magma'`) — The colormap. Default: ``"magma"``.
- `ax` (`matplotlib.axes.Axes`) (default: `None`) — The axes to draw into. Default: a new figure.
- `title` (`str`) (default: `None`) — The axes title. Default: ``"Radial power"``.

**Returns**

- (`PlotResult`) — The figure, the axes, the mesh and the continuum curves; ``data`` holds the plotted ``power``.

**Raises**

- `ValueError` — If ``power`` has dimensions other than ``omega`` and ``x``.

**Examples**

```pycon
>>> power = time_fft(phi, detrend=True).power.mean(["eta2", "eta3"])
>>> plot_radial_power(power, x_of=lambda eta1: 0.1 + 0.9 * eta1, omega_max=2.0)
```

[View source](https://github.com/max-models/plasma-plots/blob/devel/src/plasma_plots/spectral_plots.py#L519-L628)

## plasma_plots.spectral_plots.plot_spectrogram

*function*

```python
def plot_spectrogram(power: xr.DataArray, *, log: bool = True, dynamic_range: float = 4.0, omega_max: float | None = None, frequencies: dict | None = None, cmap='magma', ax=None, title: str | None = None)
```

Plot a ``(t, omega)`` spectrogram from [`spectrogram()`][plasma_plots.spectral.spectrogram].

**Parameters**

- `power` (`xarray.DataArray`) — The spectrogram, reduced to ``(t, omega)``: average any further dimensions away first.
- `log` (`bool`) (default: `True`) — Color by ``log10(power)``. Default: True.
- `dynamic_range` (`float`) (default: `4.0`) — With ``log``, the number of decades the colors span below the maximum. Default: 4.0.
- `omega_max` (`float`) (default: `None`) — The highest frequency shown. Default: all.
- `frequencies` (`dict`) (default: `None`) — Named reference frequencies drawn as horizontal dotted lines.
- `cmap` (`str or matplotlib.colors.Colormap`) (default: `'magma'`) — The colormap. Default: ``"magma"``.
- `ax` (`matplotlib.axes.Axes`) (default: `None`) — The axes to draw into. Default: a new figure.
- `title` (`str`) (default: `None`) — The axes title. Default: the spectrogram's label.

**Returns**

- (`PlotResult`) — The figure, the axes, the mesh and the reference lines; ``data`` holds the plotted ``spectrogram``.

**Raises**

- `ValueError` — If ``power`` has dimensions other than ``t`` and ``omega``.

**Examples**

```pycon
>>> plot_spectrogram(
...     spectrogram(phi.isel(eta1=8, eta2=0, eta3=0), length=10.0)
... )
```

[View source](https://github.com/max-models/plasma-plots/blob/devel/src/plasma_plots/spectral_plots.py#L269-L344)
