Matplotlib helpers (call_qt_aware)
When attempting to use matplotlib UI functions directly in a plan, and running matplotlib using a Qt
backend (e.g. in a standalone shell outside IBEX), you may see a hang or an error of the form:
UserWarning: Starting a Matplotlib GUI outside of the main thread will likely fail.
fig, ax = plt.subplots()
This is because the bluesky run engine runs plans in a worker thread, not in the main thread, which then requires special handling when calling functions that will update a UI.
The call_qt_aware plan stub can call matplotlib functions in a
Qt-aware context, which allows them to be run directly from a plan. It allows the same arguments and
keyword-arguments as the underlying matplotlib function it is passed.
Note
Callbacks such as LivePlot and LiveFitPlot already route UI calls to the appropriate UI thread by default.
The call_qt_aware plan stub is only necessary if you need to call functions which will create or update a matplotlib
plot from a plan directly - for example to create or close a set of axes before passing them to callbacks.
Usage example:
import matplotlib.pyplot as plt
from ibex_bluesky_core.plan_stubs import call_qt_aware
from ibex_bluesky_core.callbacks.plotting import LivePlot
from bluesky.callbacks import LiveFitPlot
from bluesky.preprocessors import subs_decorator
def my_plan():
# BAD - likely to either crash or hang the plan.
# plt.close("all")
# fig, ax = plt.subplots()
# GOOD
yield from call_qt_aware(plt.close, "all")
fig, ax = yield from call_qt_aware(plt.subplots)
# Pass the matplotlib ax object to other callbacks
@subs_decorator([
LiveFitPlot(..., ax=ax),
LivePlot(..., ax=ax),
])
def inner_plan():
...