Interactive BlueAPI Session#
The BlueAPISession class provides a rich, interactive IPython environment on top of the standard BlueapiClient. It comes pre-configured with automatic data collection callbacks, live plotting, and convenient shortcuts for dispatching plans.
Launching the Session#
You can launch an interactive session either through the command-line interface or programmatically in Python.
CLI#
Use the sm-bluesky client command to start a session. You can specify a remote beamline configuration or provide a local YAML config file.
# Connect to a remote beamline server (e.g., p99) with a specific session ID
sm-bluesky client -b p99 -s my_session
# Connect using a local configuration file
sm-bluesky client -c ./src/yaml_config/blueapi_config.yaml -s my_session
Tip
If you omit the -s flag, the client will automatically restore your last used session (if cached). Otherwise, set bc.instrument_session = '<session_id>' in the shell before dispatching plans, or use -d to start a dummy session.
Programmatically#
You can also embed the session directly into your own Python scripts or Jupyter Notebooks:
from sm_bluesky.common.clients.blueapi_session import BlueAPISession
from sm_bluesky.common.cli import load_config
# Load configuration for a specific beamline
config = load_config(beamline="p99")
# Initialise the session
session = BlueAPISession(config=config, instrument_session="my_session")
# Start the interactive IPython shell
session.start_shell()
The Interactive Shell Environment#
Once the interactive IPython shell is running, you have access to:
bc: The underlyingBlueapiClientinstance.pl: A shortcut to access available plans (e.g.,pl.step_scan(...)).dev: A shortcut to access available devices (e.g.,dev.dcm).show_plan(): Prints a list of all plans available on the server.show_devices(): Prints a list of all devices available on the server.scan_data: A dictionary containing all collected event data from your scans.plot(scan_id=None, cmap="viridis"): Opens an interactive visualisation window.run(script): Executes a Python script inside the active session namespace (a shortcut for%run -i <script>).
Writing & Running Scan Scripts#
To automate sequences of scans, loops, or custom logic, you can write a standard Python script that directly uses session objects (pl, dev, bc, scan_data, plot) and run it inside the session.
Creating a Script#
Create a .py file (for example, my_scans.py) containing the plans and Python logic you want to execute:
# my_scans.py
from time import sleep
for num_points in range(2, 5):
print(f"Running count scan with {num_points} points...")
pl.count([dev.pgm.energy], num_points, 0.5)
sleep(1.0)
# Stack a step scan afterwards
pl.step_scan([dev.idd_gap], [[dev.pgm.energy, [200, 300, 10]]])
Running the Script#
From inside the interactive BlueAPISession shell, pass the script path to run():
run("my_scans.py")
# Or using IPython's built-in magic with the -i flag:
%run -i my_scans.py
Note
run("my_scans.py") validates the script’s Python syntax and Ctrl+C interruption continue to work automatically during each scan.
Data Collection & Live Plotting#
When you initialise a BlueAPISession, it automatically subscribes to data events from the BlueAPI server. As you run plans, data points are collected and stored in memory.
Accessing Data#
Live data is stored in the scan_data dictionary, which is keyed first by the scan_id and then by the device name.
# Run a simple count on the DCM device
pl.count(dev.dcm)
# Run a step scan
# - Detectors: [dev.idd_gap]
# - Axes & Ranges: [[dev.pgm.energy, [start=200, stop=300, step=1]]]
pl.step_scan([dev.idd_gap], [[dev.pgm.energy, [200, 300, 1]]])
# Access the collected data for a specific scan ID
print(scan_data["1"])
# Or access data from the most recent scan
last_scan_id = next(reversed(scan_data))
print(scan_data[last_scan_id])
Interactive Plotting#
You can visualise this data in near real-time using the built-in interactive plot window. By default, the window will attempt to open automatically, but you can also summon it manually:
# Open the plotting window for the current data
plot()
# Open the plotting window for a specific scan with a custom 2D colormap
plot(scan_id="123", cmap="plasma")
The interactive plot window polls for new data in the background as a scan progresses and provides controls in the side panel for:
Scan Selection: Toggle recent scans or add a specific scan by ID.
Channel Selection: Choose the X axis and toggle multiple Y channels (in 1D Line mode), or choose X, Y, and colour Z channels (in 2D modes).
- Plot Mode:
1D Line: Plot one or more Y channels against a selected X axis (or
Point number) across all active scans.2D Grid: Rebin 2D step or fast grid scans into a 2D heatmap (
X,Y, and colourZ) with a colorbar, automatically falling back to a scatter plot for ungridded points.2D Contour: Render filled triangulated contours of
(X, Y, Z)data with a colorbar (falling back to a scatter plot when points are collinear or fewer than three).
Log Scale: Toggle logarithmic scaling on the Y axis (in 1D Line mode) or on the colour normalisation (in 2D Grid and 2D Contour modes).
Session Caching & Variable Persistence#
The interactive client automatically caches your active session ID and collected scan data so you can seamlessly resume your work after closing the terminal.
Automatic Caching#
Session ID: When you launch the client with the
-sflag (e.g.,sm-bluesky client -b i10 -s my_session), your session ID is remembered. The next time you launch the client without the-sflag, it will automatically reconnect tomy_session.Scan Data: Every time a hardware scan completes, the collected data is automatically saved to a local cache (
~/.sm-bluesky/cache/). When you restart your client and reconnect to the same session, your previousscan_datais automatically loaded back into memory, allowing you to instantly runplot()on older scans.
User Variables#
There is no easy way to restore the whole namespace as we have active network connections and thread locking is used by the client. Therefore while raw scan_data is cached automatically, any custom variables or processed data arrays you create must be manually set to be persistent.
You can save these across sessions using IPython’s built-in %store magic command:
Tip
Saving a variable:
# Create a variable
my_custom_data = scan_data["123"] * 2.5
# Store it to the local IPython cache
%store my_custom_data
Restoring a variable (after restarting the client):
# Retrieve the variable from the local IPython cache
%store -r my_custom_data
print(my_custom_data)
To view all currently stored variables, simply run %store without any arguments. You can also restore previously saved variables into your current namespace with %store -r.