# Using Pylbo

Using Pylbo is quite straightforward, for a detailed guide on the API we refer to the Pylbo documentation. This page will provide a basic guide on how to use the package . In what follows we assume that Pylbo has been installed (see installing Pylbo) and has been imported.

You can either load a single datfile or multiple datfiles at the same time. Both loaders accept either strings or PathLike objects for the datfile paths.

ds = pylbo.load("path_to_datfile")


The variable ds will be a LegolasDataSet instance, which has a lot of convenient methods and attributes that you can use during analysis.

series = pylbo.load_series(["path1", "path2", "path3"])


The variable series will be a LegolasDataSeries instance. This is an iterable object, meaning you can do something like this:

# iterate over the various datasets
for ds in series:
....
# get a specific dataset or slice multiple datasets
ds = series[3]
series_slice = series[3:9]


## Analysing a single file

In what follows we assume that your single datfile has been loaded in ds as explained above.

### Plotting the spectrum

Pylbo has a built-in method to visualise the spectrum of a dataset:

p = pylbo.plot_spectrum(ds)
p.show()


This will create a new figure on which the spectrum is plotted. You can specify a custom figure size through the extra argument figsize=(12, 8), just as in matplotlib. You can also specify your own figure (so no new window will be created):

import matplotlib.pyplot as plt
fig, ax = plt.subplots(1)
p = pylbo.plot_spectrum(ds, custom_figure=(fig, ax))
p.show()


Changing the markersize, color etc. can be done by supplying the usual matplotlib kwargs to plot_spectrum. You can fully customise the figure by accessing the figure and axes objects through p.fig and p.ax. The detailed API can be found here.

#### Interactive continua & eigenfunctions

Pylbo can interactively plot the various continua regions and eigenfunctions. The example below first plots the spectrum, and then attaches the continua and eigenfunctions to the plot:

p = pylbo.plot_spectrum(ds)


This is interactive by default, to toggle the continua on or off you can click on their respective legend items. You can supply p.add_continua(interactive=False) to disable interactivity.

When you attach the eigenfunctions through p.add_eigenfunctions() Pylbo will modify the geometry of the currently supplied axis and split it in two. The spectrum will be drawn on the left, the eigenfunctions on the right; simply click on a spectrum point (or multiple) for which you want to see eigenfunctions. Selected points will be annotated on the plot, clicking left will deselect them. Pressing Enter draws the eigenfunctions for the selected points, you can cycle through the various eigenfunctions as well.

If derived eigenfunction quantities were saved as well, you can create an additional spectrum plot and attach those instead:

p2 = pylbo.plot_spectrum(ds)


Usage and interactivity is exactly the same as for the regular eigenfunctions.

Note that every point you select will have a different color, the colors between the eigenfunctions and the selected spectrum points are consistent. The legend on the eigenfunction panel will contain the index of the selected point in the ds.eigenvalues array, with the value printed as well. Below is a detailed overview of the various commands:

Key / mouse Description
left click Select a spectrum point. You can select multiple points at once.
right click Remove point from selection. Picker-based, so you may have to zoom in a bit if two selected points are close together.
enter Plots the eigenfunctions of the currently selected points.
i Swaps between the real and imaginary parts of the eigenfunctions.
up arrow Cycles to the next variable in the list.
down arrow Cycles to the previous variable in the list.
d Clears current selection.
t Retransforms the eigenfunctions using the scale factor, hence has no effect if geometry = "Cartesian". You can use this to cycle between the $rv_r$ and $v_r$ eigenfunctions in cylindrical geometry, for example.
w prints out the currently selected eigenvalues to the console. This may come in handy if you want to copy the exact values somewhere, to extract eigenfunctions for example.
e toggles a visualisation of the subset of eigenvalues that have their eigenfunctions saved, has no effect if write_eigenfunction_subset was set to .false..

#### Retrieving eigenvalues & eigenfunctions

You can manually retrieve the eigenfunctions from the dataset as well. You can either supply the eigenvalue indices (based on the interactive legend on the eigenfunction panel), or eigenvalue “guesses”. In case of the latter Pylbo will select the eigenvalue closest near your guess, and return its eigenfunctions.

# based on indices
eigenfuncs = ds.get_eigenfunctions(ev_idxs=[20, 123, 451, 613])
# based on guesses
eigenfuncs = ds.get_eigenfunctions(ev_guesses=[3.0, 4.5 + 1j, 5 - 3j])


Now, eigenfuncs will be a Numpy-array of size 3 (since 3 eigenvalue guesses were provided), and every index corresponds to the index of your guess. Meaning, eigenfuncs[1] corresponds to the eigenfunctions of 4.5 + i, and so on. Every element of the eigenfuncs array is a dictionary, containing all eigenfunctions as well as the eigenvalues. To retrieve what you need, simply do

# for the first eigenvalue:
rho_ef1 = eigenfuncs[0].get("rho")
# for the second eigenvalue:
rho_ef2 = eigenfuncs[1].get("rho")
# to see which keys are in there:
print(eigenfuncs[0].keys())
>> "rho", "v1", "v2", "v3", "T", "a1", "a2", "a3", "eigenvalue"


The names of the keys are self-explanatory.

To retrieve derived eigenfunction quantities use ds.get_derived_eigenfunctions instead.

You can also retrieve eigenvalues near guesses, this will return both the indices and corresponding eigenvalues:

idxs, eigenvals = ds.get_nearest_eigenvalues(ev_guesses=[3.0, 4.5 + 1j, 5 - 3j])


### Plotting the equilibrium profiles

Pylbo allows for a visual inspection of the equilibrium profiles as well:

p = pylbo.plot_equilibrium(ds)
p.show()


See the API here for more information. The profiles will be drawn interactively, similar to the continua. Pass the additional kwarg interactive=False to disable this. All equilibrium profiles can be accessed directly through the ds.equilibria attribute.

### Plotting the continuum profiles

Analogous to the equilibrium profiles, the continuum profiles can be drawn as well:

p = pylbo.plot_continua(ds)
p.show()


See the API here for more information. The continua can be accessed directly through the ds.continua attribute.

### Plotting the matrices

Pylbo can also plot the matrices as calculated by Legolas, note that this requires the matrices to be saved to the datfile.

p = pylbo.plot_matrices(ds)
p.show()


See the API here for more information. Note that this method is only for inspection purposes on low resolution datasets (10, maybe 20 gridpoints). This method should not be used for “regular” datasets, since thousands of points will be drawn in that case.

### Plotting the equilibrium balance

In case you are setting up an equilibrium by yourself and Legolas is complaining that the equilibrium balance equations are not satisfied, you can do a quick inspection of these equations like so:

p = pylbo.plot_equilibrium_balance(ds)
p.show()


See the API here for more information. The resulting curves should be as close to zero as possible. Note that for the non-adiabatic equilibrium equation Pylbo does a crude 2nd order numerical differentation (Numpy’s gradient method), so the results may be off by about 1e-7 - 1e-8.

## Analysing multiple files

In what follows we assume that all datfiles have been loaded in series as explained above.

### Plotting a multispectrum

Plotting the spectrum of multiple datfiles is done in a similar way as for a single datfile. The main difference here is that we have to provide an additional variable, xdata. This should be of the same length as the number of datasets in the series, since every point of xdata will have a dataset associated with it. 

Say you have loaded 10 datasets and you specify xdata = "k3". This means that you will have 10 columns of datapoints, plotting the real or imaginary part of the eigenvalues versus the k3 value for each dataset. xdata can be anything, as long as the array sizes are consistent.

In the example below we plot the real part of the eigenvalues versus the wavenumber squared for each dataset, and divide the eigenvalues with the maximum Alfvén speed in each setup:

xdata = series.get_k0_squared()
p = pylbo.plot_spectrum_multi(series, xdata=xdata)
p.set_y_scaling(1 / series.get_alfven_speed(which_values="maximum"))
p.show()


See the API here for more information. You can plot the imaginary part of the eigenvalues instead by supplying use_real_parts=False, or plot the squared eigenvalues through use_squared_omega=True.

#### Interactive continua & eigenfunctions

Multispectra can have associated continua and eigenfunctions as well, and these will be automatically scaled to whatever scaling is supplied to the eigenvalues. Adding these is done in exactly the same way as for the single datfile case:

xdata = series.get_k0_squared()
p = pylbo.plot_spectrum_multi(series, xdata=xdata)
p.show()


Interactive controls are the same as before, except for one addition. When multiple datfiles are loaded it is not necessarily the case that all of them have eigenfunctions as well, making it difficult to know which spectrum points can be selected and which ones cannot. This can be made clear by pressing the M key, which will reduce the opacity for points without eigenfunctions. This is a toggle, so pressing M again turns this feature off. Note that this is only relevant for multispectra, and that this will have no effect if all datasets have eigenfunctions present.

Key / mouse Description
m Toggles the opacity for spectrum points that have no eigenfunctions, making them less visible.

### Plotting a merged spectrum

In some cases it may be useful to merge all datasets of a series into a single 2D figure, for examply when probing the spectrum using multiple $\sigma$-values with the shift-invert solver. Pylbo supplies a method to do this, and even draw eigenfunctions at the same time:

p = pylbo.plot_merged_spectrum(series)
p.show()


See the API here for more information. This will create a scatterplot where the points of every dataset in the series will be assigned a different color, and a legend will be created saying which color corresponds to which dataset. The legend is interactive by default, meaning that similar as to the interactive continua regions you can click on the legend and show/hide the corresponding dataset. To disable this, supply interactive=False as an additional keyword argument.

If a great many datasets are loaded it may be useful to disable the legend alltogether. This can be done by giving the kwarg legend=False to plot_merged_spectrum. Furthermore, if you simply want to look at the spectrum in a single color, supply the argument color="blue" (or your favourite color), which will also disable the legend and plot all points in that color.

The eigenfunctions are interactive in exactly the same way as for the other types of plots, but note that it’s possible that points from different datasets may overlap, for example when the same eigenvalue is picked up by multiple datasets. Selecting that point will therefore plot multiple eigenfunctions (equal to the amount of overlapping points), however, you can circumvent this by hiding the points of the datasets you’re not interesting in by clicking on their legend entries. Similar as to the multispectrum case you can highlight datasets that have eigenfunctions present by pressing the “M” key.

Drawing continua is not supported for this type of figure.

### Comparing two spectra

Sometimes it may be convenient to plot two similar spectra next to each other and do a direct visual comparison of both. This can be done as follows:

p = pylbo.plot_spectrum_comparison(ds1, ds2)
p.show()


See the API here for more information. This will create a 2x1 figure with the spectrum of ds1 on the left and the one from ds2 on the right. Note that you can add continua and eigenfunctions to this as well through p.add_continua() (with an optional interactive=False flag) and p.add_eigenfunctions(). In the case of eigenfunctions, the figure will be transformed to a 2x2 plot, where the panel below each spectrum corresponds to the eigenfunctions.

The additional keyword argument lock_zoom=True can be supplied to plot_spectrum_comparison()`, which will lock the zoom on both spectra (and is off by default). Turning this on means that if you zoom in on one of the two spectra, the zoom of the other plot is automatically adjusted to match.