Skip to content

Instantly share code, notes, and snippets.

@AbbyGi
Last active January 12, 2021 15:46
Show Gist options
  • Save AbbyGi/38b44e89ccd55f392be0dc9921820894 to your computer and use it in GitHub Desktop.
Save AbbyGi/38b44e89ccd55f392be0dc9921820894 to your computer and use it in GitHub Desktop.
APS 4-ID POLAR bluesky-widgets example

APS 4-ID POLAR bluesky-widgets example

Setup

Install bluesky-widgets, an experimental new package.

pip install bluesky-widgets

Download the example and enter the directory.

git clone https://gist.github.com/AbbyGi/38b44e89ccd55f392be0dc9921820894 aps_polar_example
cd aps_polar_example

Usage

View saved data at the beamline

Start IPython with a Qt GUI

ipython --gui=qt
from aps_polar_example import AutoXanesPlot
from bluesky_widgets.qt.figures import QtFigures
import databroker

# Use the new, experimental "v2" interface to databroker.
catalog = databroker.Broker.named('mongodb_config').v2

# Create our "auto plot builder" and a view for it.
model = AutoXanesPlot()
view = QtFigures(model.figures)
view.show()  # An empty GUI window should appear.

# View some scans. (These are the ones you shared as example data back on 4 Dec.)
model.add_run(catalog[75])
model.add_run(catalog[91])
model.add_run(catalog[153])

Try adding any other scans you like. Let us know what happens!

View live data at the beamline

Start IPython with a Qt GUI

ipython --gui=qt

This assumes that you have already defined a RunEngine instance, RE.

from aps_polar_example import AutoXanesPlot
from bluesky_widgets.qt.figures import QtFigures
from bluesky_widgets.utils.streaming import stream_documents_into_runs

model = AutoXanesPlot()
view = QtFigures(model.figures)
view.show()  # An empty GUI window should appear.

RE.subscribe(stream_documents_into_runs(model.add_run))

# Now take data with RE.
RE(...)

For applicable scans, plots should appear in the GUI window, and they should update in real time during data acquisition.

Use Jupyter instead of Qt

A key feature of bluesky-widgets in that this all works in Jupyter (and soon, in other GUI and visualization frameworks) with very minor changes.

First, you'll need to make your have ipympl installed to support interactive matplotlib plotting in Jupyter.

Then, referring to the examples above, replace:

from bluesky_widgets.qt.figures import QtFigures

...

view = QtFigures(model.figures)
view.show()  # An empty GUI window should appear.

with

from bluesky_widgets.jupyter.figures import JupyterFigures

...

view = JupyterFigures(model.figures)
view  # Place this at the bottom of a cell in the notebook.

An interactive plot should appear in the output.

Appendix: Use with example data

For the record, this is how we tested it with example data.

pip install databroker-unpack
databroker-unpack inplace exported_scans POLAR-example

ipython --gui=qt
from aps_polar_example import view_example_data
catalog, model = view_example_data("POLAR-example")
from bluesky_widgets.models.auto_plot_builders import AutoPlotter
from bluesky_widgets.models.plot_builders import Lines
from bluesky_widgets.models.plot_specs import AxesSpec, FigureSpec
from bluesky_widgets.qt.figures import QtFigures
import databroker
import numpy as np
def xanes(monitor, detector):
absorption = np.log(np.array(monitor) / np.array(detector)).reshape(-1, 4)
return absorption.mean(axis=1)
def xmcd(monitor, detector):
absorption = np.log(np.array(monitor) / np.array(detector)).reshape(-1, 4)
return absorption[:, [0, 3]].mean(axis=1) - absorption[:, [1, 2]].mean(axis=1)
def downsampled(x):
return np.array(x).reshape(-1, 4).mean(axis=1)
class AutoXanesPlot(AutoPlotter):
def __init__(self, monitor="Ion Ch 4", detector="Ion Ch 5"):
super().__init__()
self._x_to_lines = {} # map x variable to (xanes_lines, xmcd_lines)
self._monitor = monitor
self._detector = detector
@property
def monitor(self):
return self._monitor
@property
def detector(self):
return self._detector
def handle_new_stream(self, run, stream_name):
if stream_name != "primary":
# Nothing to do for this stream.
return
# Detect x variable from hints in metadata.
first_scanning_dimension = run.metadata["start"]["hints"]["dimensions"][0]
scanning_fields, _ = first_scanning_dimension
x = scanning_fields[0]
# If we already have a figure for this x, reuse it (over-plot).
try:
(xanes_lines, xmcd_lines) = self._x_to_lines[x]
except KeyError:
# We don't have a figure for this x. Make one.
xanes_axes = AxesSpec(x_label=x, title="XANES")
xmcd_axes = AxesSpec(x_label=x, title="XMCD")
figure = FigureSpec((xanes_axes, xmcd_axes), title="XANES and XMCD")
# Set up objects that will select the approriate data and do the
# desired transformation for plotting.
xanes_lines = Lines(
x=lambda primary: downsampled(primary[x]),
ys=[lambda primary: xanes(primary[self._monitor], primary[self._detector])],
axes=xanes_axes,
)
xmcd_lines = Lines(
x=lambda primary: downsampled(primary[x]),
ys=[lambda primary: xmcd(primary[self._monitor], primary[self._detector])],
axes=xmcd_axes,
)
self._x_to_lines[x] = (xanes_lines, xmcd_lines)
# Keep track of these plot builders to enable *removing* runs from them.
self.plot_builders.append(xanes_lines)
self.plot_builders.append(xmcd_lines)
# Appending this figures list will trigger to view to show our new figure.
self.figures.append(figure)
# Add this Run to the figure.
xanes_lines.add_run(run)
xmcd_lines.add_run(run)
def view_example_data(catalog_name):
catalog = databroker.catalog[catalog_name]
model = AutoXanesPlot()
model.add_run(catalog[-3])
view = QtFigures(model.figures)
view.show()
return catalog, model
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment