Intro to our Holoviz apps¶
import numpy as np
import xarray as xr
import panel as pn
pn.extension()
from labcore.testing.dispersive_qubit_readout_data import chevron_dataset
from labcore.data.datadict import datadict_to_meshgrid, dd2xr
from labcore.analysis import split_complex
from labcore.analysis.hvplotting import Node
Nodes¶
let's have a look at what Node
s are.
To work with them, we create some dummy data.
# generate some generic Rabi-like data
raw_data = chevron_dataset(
Omega_0=1e6,
Delta_vals=np.linspace(-1e6, 1e6, 20),
t_vals=np.linspace(0, 3e-6, 20),
n=100, # number of shots
)
# convert directly to xarray.
# also: with the holoviz (or all pydata) tools, complex data isn't always the most convenient, so we split it immediately.
xrdata = split_complex(dd2xr(datadict_to_meshgrid(raw_data.expand())))
A trivial example¶
By default, nodes don't do anything but pass data around between them if they're connected correctly. In this example we just create a node and display it. Nothing is seen...
n = Node()
n
Note: there is no input data, so we have also no output data:
n.data_out
Now, let's set some data:
n.data_in = xrdata
n.data_out
<xarray.Dataset> Dimensions: (repetition: 100, detuning: 20, time: 20) Coordinates: * repetition (repetition) int64 1 2 3 4 5 6 7 8 ... 93 94 95 96 97 98 99 100 * detuning (detuning) float64 -1e+06 -8.947e+05 ... 8.947e+05 1e+06 * time (time) float64 0.0 1.579e-07 3.158e-07 ... 2.842e-06 3e-06 Data variables: signal_Re (repetition, detuning, time) float64 2.394 2.416 ... 1.473 2.239 signal_Im (repetition, detuning, time) float64 0.6124 0.5184 ... 0.7653
OK, not very exciting yet. But internally stuff has happened -- the data went through the processing routine, and the output of that routine is now available as output data.
Note: we always look at the data and plot it; that holds for every node.
When we embed the .plot
object into a viewable (like a panel layout) we get our custom plot app we can use to slice our data.
pn.Column(
n.plot
)
A basic loader node¶
Loaders are specific nodes that load data.
That means, they do not have any input data, only output data.
Every loader node must have a method load_data
that returns a DataDict
.
The base class for loaders already comes with a set of preprocessing options: averaging over dimension that can be specified (you have to type in the name, and it'll average over it if it's there), auto-gridding, and auto-refresh.
In the example below, you can either load a freshly generated set of data by pressing the Load Data button, or repeatedly by setting Auto-refresh to some value (disabling will stop it).
TODO Stuff that's been set on the dimension sliders is currently being reset everytime the data is reloaded.
from labcore.data.datadict import DataDict
from labcore.analysis.hvplotting import LoaderNodeBase
class RabiSimulation(LoaderNodeBase):
def load_data(self) -> DataDict:
Omega_0 = 1
Delta_vals = np.linspace(-2, 2, 20)
t_vals = np.linspace(0, 3, 20)
nreps = 10
dd = chevron_dataset(Omega_0, Delta_vals, t_vals, nreps).expand()
return dd
s = RabiSimulation(name='sim')
app = pn.Column(
s,
s.plot,
)
app