This page was generated from docs/examples/DataSet/Pedestrian example of subscribing to a DataSet.ipynb. Interactive online version: .
Pedestrian example of subscribing to a DataSet¶
It is possible to subscribe to a dataset. Subscribing means adding a function to the dataset and having the dataset call that function every time a result is added to the dataset (or more rarely, see below).
Call signature¶
The subscribing function must have the following call signature:
fun(results: List[Tuple[Value]], length: int,
state: Union[MutableSequence, MutableMapping]) -> None:
"""
Args:
results: A list of tuples where each tuple holds the results inserted into the dataset.
For two scalar parameters, X and Y, results might look like [(x1, y1), (x2, y2), ...]
length: The current length of the dataset.
state: Any mutable sequence/mapping that can be used to hold information from call to call.
In practice a list or a dict.
"""
Below we provide an example function that counts the number of times a voltage has exceeded a certain limit.
Frequency¶
Since calling the function every time an insertion is made may be too frequent, a min_wait
and a min_count
argument may be provided when subscribing. The dataset will then only call the function upon inserting a result if min_wait
seconds have elapsed since the last call (or the start of the subscription, in the time before the first call) and min_count
results have been added to the dataset since the last call (or the start of the subscription). All the results added in the
meantime are queued and passed to the function in one go.
Order¶
The subscription must be set up after all parameters have been added to the dataset.
[1]:
from pathlib import Path
from time import sleep
import numpy as np
from qcodes.dataset import (
ParamSpec,
initialise_or_create_database_at,
load_or_create_experiment,
new_data_set,
)
Logging hadn't been started.
Activating auto-logging. Current session state plus future input saved.
Filename : /home/runner/.qcodes/logs/command_history.log
Mode : append
Output logging : True
Raw input log : False
Timestamping : True
State : active
Qcodes Logfile : /home/runner/.qcodes/logs/241008-16727-qcodes.log
Example 1: A notification¶
We imagine scanning a frequency and reading out a noisy voltage. When the voltage has exceeded a threshold 5 times, we want to receive a warning. Let us initialise our database and create an experiment.
[2]:
initialise_or_create_database_at(Path.cwd() / "subscription_tutorial.db")
exp = load_or_create_experiment(
experiment_name="subscription_tutorial", sample_name="no_sample"
)
[3]:
dataSet = new_data_set(
"test",
exp_id=exp.exp_id,
specs=[ParamSpec("x", "numeric", unit="Hz"), ParamSpec("y", "numeric", unit="V")],
)
dataSet.mark_started()
[4]:
def threshold_notifier(results, length, state):
if len(state) > 4:
print(f"At step {length}: The voltage exceeded the limit 5 times! ")
state.clear()
for result in results:
if result[1] > 0.8:
state.append(result[1])
[5]:
# now perform the subscription
# since this is important safety info, we want our callback function called
# on EVERY insertion
sub_id = dataSet.subscribe(threshold_notifier, min_wait=0, min_count=1, state=[])
[6]:
for x in np.linspace(100, 200, 150):
y = np.random.randn()
dataSet.add_results([{"x": x, "y": y}])
At step 6: The voltage exceeded the limit 5 times!
At step 11: The voltage exceeded the limit 5 times!
At step 16: The voltage exceeded the limit 5 times!
At step 21: The voltage exceeded the limit 5 times!
At step 26: The voltage exceeded the limit 5 times!
At step 31: The voltage exceeded the limit 5 times!
At step 36: The voltage exceeded the limit 5 times!
At step 41: The voltage exceeded the limit 5 times!
At step 46: The voltage exceeded the limit 5 times!
At step 51: The voltage exceeded the limit 5 times!
At step 56: The voltage exceeded the limit 5 times!
At step 61: The voltage exceeded the limit 5 times!
At step 66: The voltage exceeded the limit 5 times!
At step 71: The voltage exceeded the limit 5 times!
At step 76: The voltage exceeded the limit 5 times!
At step 81: The voltage exceeded the limit 5 times!
At step 86: The voltage exceeded the limit 5 times!
At step 91: The voltage exceeded the limit 5 times!
At step 96: The voltage exceeded the limit 5 times!
At step 101: The voltage exceeded the limit 5 times!
At step 106: The voltage exceeded the limit 5 times!
At step 111: The voltage exceeded the limit 5 times!
At step 116: The voltage exceeded the limit 5 times!
At step 121: The voltage exceeded the limit 5 times!
At step 126: The voltage exceeded the limit 5 times!
At step 131: The voltage exceeded the limit 5 times!
At step 136: The voltage exceeded the limit 5 times!
At step 141: The voltage exceeded the limit 5 times!
At step 146: The voltage exceeded the limit 5 times!
[7]:
dataSet.unsubscribe_all()
Example 2: ASCII Plotter¶
While this example does not represent a data acqusition that one may deal with in a real experiment, it is a fun practice of subscribing to a dataset.
[8]:
dataSet = new_data_set(
"test",
exp_id=exp.exp_id,
specs=[
ParamSpec("blip", "numeric", unit="bit"),
ParamSpec("blop", "numeric", unit="bit"),
],
)
dataSet.mark_started()
[9]:
def ASCII_plotter_5bit(results, length, state):
"""
Glorious 5-bit signal plotter
Digitises the range (-1, 1) with 4 bits and plots it
in stdout. Crashes and burns if given data outside that
interval.
"""
for result in results:
plotline = ["."] * 32
yvalue = result[1]
yvalue += 1
yvalue /= 2
yvalue = int(yvalue * 31)
plotline[yvalue] = "O"
print("".join(plotline))
[10]:
sub_id = dataSet.subscribe(ASCII_plotter_5bit, min_wait=0, min_count=3, state=[])
[11]:
for x in np.linspace(0, 3 * np.pi, 100):
yvalue = 0.9 * np.sin(x) + np.random.randn() * 0.05
dataSet.add_results([{"blip": x, "blop": yvalue}])
sleep(0.1)
...............O................
................O...............
..................O.............
...................O............
.....................O..........
......................O.........
........................O.......
.........................O......
...........................O....
............................O...
..............................O.
...............................O
Exception in thread Thread-7:
Traceback (most recent call last):
File "/opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/threading.py", line 1045, in _bootstrap_inner
self.run()
File "/opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/site-packages/qcodes/dataset/subscriber.py", line 90, in run
self._loop()
File "/opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/site-packages/qcodes/dataset/subscriber.py", line 113, in _loop
self._call_callback_on_queue_data()
File "/opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/site-packages/qcodes/dataset/subscriber.py", line 104, in _call_callback_on_queue_data
self.callback(result_list, self._data_set_len, self.state)
File "/tmp/ipykernel_16727/2136402629.py", line 15, in ASCII_plotter_5bit
IndexError: list assignment index out of range
[ ]: