Skip to content

Commit 679e3fd

Browse files
committed
Test setting plot title
1 parent 60b1fb9 commit 679e3fd

File tree

4 files changed

+54
-28
lines changed

4 files changed

+54
-28
lines changed

src/ibex_bluesky_core/callbacks/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,10 @@ def start(self, doc: RunStart) -> None:
229229
# where a fit result can be returned before
230230
# the QtAwareCallback has had a chance to process it.
231231
self._subs.append(self._live_fit)
232+
233+
# Sample 5000 points as this strikes a reasonable balance between displaying
234+
# 'enough' points for almost any scan (even after zooming in on a peak), while
235+
# not taking 'excessive' compute time to generate these samples.
232236
self._subs.append(LiveFitPlot(livefit=self._live_fit, ax=ax, num_points=5000))
233237
else:
234238
self._subs.append(self._live_fit)

src/ibex_bluesky_core/callbacks/_plotting.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ def __init__(
206206
y: str,
207207
ax: Axes,
208208
postfix: str,
209-
output_dir: str | os.PathLike[str] | None,
209+
output_dir: str | os.PathLike[str] | None = None,
210210
) -> None:
211211
"""Initialise the PlotPNGSaver callback.
212212

src/ibex_bluesky_core/plans/reflectometry/_det_map_align.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Reflectometry detector-mapping alignment plans."""
22

3+
import functools
34
import logging
45
from collections.abc import Generator
56
from typing import Any, TypedDict
@@ -40,6 +41,19 @@
4041
logger = logging.getLogger(__name__)
4142

4243

44+
def _set_title_to_fit_result(
45+
name: str, doc: dict[str, Any], *, fit_callback: LiveFit, ax: Axes
46+
) -> None:
47+
fit_result = fit_callback.result
48+
if fit_result is not None:
49+
ax.set_title(
50+
f"Best x0: {fit_result.params['x0'].value:.4f} +/- {fit_result.params['x0'].stderr:.4f}"
51+
)
52+
else:
53+
ax.set_title("Fit failed")
54+
plt.draw()
55+
56+
4357
def _height_scan_callback_and_fit(
4458
reducer: PeriodSpecIntegralsReducer,
4559
height: NamedMovable[float],
@@ -68,18 +82,12 @@ def _height_scan_callback_and_fit(
6882
for cb in height_scan_callbacks.subs:
6983
height_scan_ld.subscribe(cb)
7084

71-
def set_title_to_height_fit_result(name: str, doc: dict[str, Any]) -> None:
72-
fit_result = height_scan_callbacks.live_fit.result
73-
if fit_result is not None:
74-
ax.set_title(
75-
f"Best x0: {fit_result.params['x0'].value:.4f} "
76-
f"+/- {fit_result.params['x0'].stderr:.4f}"
77-
)
78-
else:
79-
ax.set_title("Fit failed") # pragma: no cover
80-
plt.draw()
81-
82-
height_scan_ld.subscribe(set_title_to_height_fit_result, "stop")
85+
height_scan_ld.subscribe(
86+
functools.partial(
87+
_set_title_to_fit_result, fit_callback=height_scan_callbacks.live_fit, ax=ax
88+
),
89+
"stop",
90+
)
8391

8492
return height_scan_ld, height_scan_callbacks.live_fit
8593

@@ -135,24 +143,16 @@ def gaussian_max_y_guess(
135143
for cb in angle_scan_callbacks.subs:
136144
angle_scan_ld.subscribe(cb)
137145

138-
def set_title_to_angle_fit_result(name: str, doc: dict[str, Any]) -> None:
139-
fit_result = angle_scan_callbacks.live_fit.result
140-
if fit_result is not None:
141-
ax.set_title(
142-
f"Best x0: {fit_result.params['x0'].value:.4f} "
143-
f"+/- {fit_result.params['x0'].stderr:.4f}"
144-
)
145-
else:
146-
ax.set_title("Fit failed") # pragma: no cover
147-
plt.draw()
148-
149-
angle_scan_ld.subscribe(set_title_to_angle_fit_result, "stop")
150-
151-
# Make sure the Plot PNG saving happens *after* setting plot title to fit result...
152146
angle_scan_ld.subscribe(
153-
PlotPNGSaver(x=angle_name, y=counts_name, ax=ax, postfix="", output_dir=None)
147+
functools.partial(
148+
_set_title_to_fit_result, fit_callback=angle_scan_callbacks.live_fit, ax=ax
149+
),
150+
"stop",
154151
)
155152

153+
# Make sure the Plot PNG saving happens *after* setting plot title to fit result...
154+
angle_scan_ld.subscribe(PlotPNGSaver(x=angle_name, y=counts_name, ax=ax, postfix=""))
155+
156156
return angle_scan_ld, angle_scan_callbacks.live_fit
157157

158158

tests/plans/test_det_map_align.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
angle_scan_plan,
1717
height_and_angle_scan_plan,
1818
)
19+
from ibex_bluesky_core.plans.reflectometry._det_map_align import _set_title_to_fit_result
1920

2021

2122
@pytest.fixture
@@ -122,3 +123,24 @@ def test_det_map_align_bad_angle_map_shape(RE, dae, height):
122123
angle_map=np.array([21, 22, 23, 24]),
123124
)
124125
)
126+
127+
128+
def test_set_title_to_fit_result_failed_fit():
129+
ax = MagicMock()
130+
live_fit = MagicMock()
131+
live_fit.result = None
132+
133+
_set_title_to_fit_result(fit_callback=live_fit, ax=ax, name="stop", doc={})
134+
135+
ax.set_title.assert_called_once_with("Fit failed")
136+
137+
138+
def test_set_title_to_fit_result_good_fit():
139+
ax = MagicMock()
140+
live_fit = MagicMock()
141+
live_fit.result.params["x0"].value = 1.23456789
142+
live_fit.result.params["x0"].stderr = 9.87654321
143+
144+
_set_title_to_fit_result(fit_callback=live_fit, ax=ax, name="stop", doc={})
145+
146+
ax.set_title.assert_called_once_with("Best x0: 1.2346 +/- 9.8765")

0 commit comments

Comments
 (0)