Skip to content

Commit 9370013

Browse files
committed
wip - this doesnt work because fig is None?
1 parent df075a1 commit 9370013

File tree

6 files changed

+55
-17
lines changed

6 files changed

+55
-17
lines changed

src/ibex_bluesky_core/callbacks/__init__.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from ibex_bluesky_core.callbacks.fitting.livefit_logger import (
2525
LiveFitLogger,
2626
)
27-
from ibex_bluesky_core.callbacks.plotting import LivePlot
27+
from ibex_bluesky_core.callbacks.plotting import LivePlot, PlotPNGSaver
2828

2929
logger = logging.getLogger(__name__)
3030

@@ -55,6 +55,9 @@ def __init__(
5555
live_fit_logger_output_dir: str | PathLike[str] | None = None,
5656
live_fit_logger_postfix: str = "",
5757
human_readable_file_postfix: str = "",
58+
save_plot_to_png: bool = True,
59+
plot_png_output_dir : str | PathLike[str] | None = None,
60+
plot_png_postfix: str = ""
5861
) -> None:
5962
"""A collection of ISIS standard callbacks for use within plans.
6063
@@ -114,6 +117,7 @@ def _inner():
114117
live_fit_logger_postfix: the postfix to add to live fit logger.
115118
human_readable_file_postfix: optional postfix to add to human-readable file logger.
116119
""" # noqa
120+
fig = None
117121
self._subs = []
118122
self._peak_stats = None
119123
self._live_fit = None
@@ -202,6 +206,9 @@ def start(self, doc: RunStart) -> None:
202206
yerr=yerr,
203207
)
204208
)
209+
if save_plot_to_png:
210+
self._subs.append(PlotPNGSaver(plot=fig, output_dir=plot_png_output_dir, postfix=plot_png_postfix
211+
))
205212

206213
@property
207214
def live_fit(self) -> LiveFit:

src/ibex_bluesky_core/callbacks/_utils.py

+11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import os
2+
from datetime import datetime
23
from pathlib import Path
34
from platform import node
5+
from typing import Union
6+
from zoneinfo import ZoneInfo
7+
8+
from event_model import Event, RunStart, RunStop
49

510
OUTPUT_DIR_ENV_VAR = "IBEX_BLUESKY_CORE_OUTPUT"
611

@@ -31,3 +36,9 @@ def get_default_output_path() -> Path:
3136
if output_dir_env is None
3237
else Path(output_dir_env)
3338
)
39+
40+
41+
def format_time(doc: Union[Event, RunStart, RunStop]):
42+
datetime_obj = datetime.fromtimestamp(doc[TIME])
43+
title_format_datetime = datetime_obj.astimezone(ZoneInfo("UTC")).strftime("%Y-%m-%d_%H-%M-%S")
44+
return title_format_datetime

src/ibex_bluesky_core/callbacks/file_logger.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
UNITS,
3131
UNKNOWN_RB,
3232
get_instrument,
33+
format_time,
3334
)
3435

3536
logger = logging.getLogger(__name__)
@@ -67,19 +68,18 @@ def start(self, doc: RunStart) -> None:
6768
self.current_start_document = doc[UID]
6869

6970
datetime_obj = datetime.fromtimestamp(doc[TIME])
70-
title_format_datetime = datetime_obj.astimezone(ZoneInfo("UTC")).strftime(
71-
"%Y-%m-%d_%H-%M-%S"
72-
)
7371
rb_num = doc.get(RB, UNKNOWN_RB)
7472

7573
# motors is a tuple, we need to convert to a list to join the two below
7674
motors = list(doc.get(MOTORS, []))
7775

76+
formatted_time = format_time(doc)
77+
7878
self.filename = (
7979
self.output_dir
8080
/ f"{rb_num}"
8181
/ f"{get_instrument()}{'_' + '_'.join(motors) if motors else ''}_"
82-
f"{title_format_datetime}Z{self.postfix}.txt"
82+
f"{formatted_time}Z{self.postfix}.txt"
8383
)
8484
if rb_num == UNKNOWN_RB:
8585
logger.warning('No RB number found, saving to "%s"', UNKNOWN_RB)
@@ -91,7 +91,6 @@ def start(self, doc: RunStart) -> None:
9191
]
9292
header_data = {k: v for k, v in doc.items() if k not in exclude_list}
9393

94-
formatted_time = datetime_obj.astimezone(ZoneInfo("UTC")).strftime("%Y-%m-%d %H:%M:%S")
9594
header_data[START_TIME] = formatted_time
9695

9796
# make sure the parent directory exists, create it if not

src/ibex_bluesky_core/callbacks/fitting/livefit_logger.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@
33
import csv
44
import logging
55
import os
6-
from datetime import datetime
76
from pathlib import Path
87
from typing import Optional
9-
from zoneinfo import ZoneInfo
108

119
import numpy as np
1210
from bluesky.callbacks import CallbackBase
@@ -17,11 +15,11 @@
1715
from ibex_bluesky_core.callbacks._utils import (
1816
DATA,
1917
RB,
20-
TIME,
2118
UID,
2219
UNKNOWN_RB,
2320
get_default_output_path,
2421
get_instrument,
22+
format_time,
2523
)
2624
from ibex_bluesky_core.callbacks.fitting import LiveFit
2725

@@ -74,10 +72,7 @@ def start(self, doc: RunStart) -> None:
7472
doc (RunStart): The start bluesky document.
7573
7674
"""
77-
datetime_obj = datetime.fromtimestamp(doc[TIME])
78-
title_format_datetime = datetime_obj.astimezone(ZoneInfo("UTC")).strftime(
79-
"%Y-%m-%d_%H-%M-%S"
80-
)
75+
title_format_datetime = format_time(doc)
8176
self.output_dir.mkdir(parents=True, exist_ok=True)
8277
self.current_start_document = doc[UID]
8378
file = f"{get_instrument()}_{self.x}_{self.y}_{title_format_datetime}Z{self.postfix}.txt"

src/ibex_bluesky_core/callbacks/plotting.py

+27-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
"""IBEX plotting callbacks."""
22

33
import logging
4+
import os
5+
from pathlib import Path
46
from typing import Any
57

68
import matplotlib
79
import matplotlib.pyplot as plt
810
from bluesky.callbacks import LivePlot as _DefaultLivePlot
9-
from bluesky.callbacks.core import get_obj_fields, make_class_safe
11+
from bluesky.callbacks.core import get_obj_fields, make_class_safe, CallbackBase
12+
from event_model import RunStop
1013
from event_model.documents import Event, RunStart
1114

15+
from ibex_bluesky_core.callbacks._utils import get_instrument, get_default_output_path, format_time
16+
1217
logger = logging.getLogger(__name__)
1318

1419

@@ -74,3 +79,24 @@ def start(self, doc: RunStart) -> None:
7479
"""Process an start document (delegate to superclass, then show the plot)."""
7580
super().start(doc)
7681
show_plot()
82+
83+
84+
class PlotPNGSaver(CallbackBase):
85+
"""Save plots to PNG files on a run end."""
86+
87+
def __init__(
88+
self,
89+
plot: plt.Figure | None,
90+
postfix: str,
91+
output_dir: str | os.PathLike[str] | None,
92+
):
93+
if plot is None:
94+
raise ValueError("Plot does not exist - cannot save a PNG of it.")
95+
self.plot = plot
96+
self.postfix = postfix
97+
self.output_dir = Path(output_dir or get_default_output_path())
98+
super().__init__()
99+
100+
def stop(self, doc: RunStop):
101+
filename = f"{get_instrument()}_{self.x}_{self.y}_{format_time(doc)}Z{self.postfix}.png"
102+
self.plot.savefig(fname=self.output_dir / filename)

tests/callbacks/test_write_log_callback.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def test_header_data_all_available_on_start(cb):
3939
mock_file.assert_called_with(result, "a", newline="\n", encoding="utf-8")
4040
writelines_call_args = mock_file().writelines.call_args[0][0]
4141
# time should have been renamed to start_time and converted to human readable
42-
assert "start_time: 2024-10-04 13:43:43\n" in writelines_call_args
42+
assert "start_time: 2024-10-04_13-43-43\n" in writelines_call_args
4343
assert f"uid: {uid}\n" in writelines_call_args
4444

4545

@@ -60,7 +60,7 @@ def test_no_rb_number_folder(cb):
6060
mock_file.assert_called_with(result, "a", newline="\n", encoding="utf-8")
6161
# time should have been renamed to start_time and converted to human readable
6262
writelines_call_args = mock_file().writelines.call_args[0][0]
63-
assert "start_time: 2024-10-04 13:43:43\n" in writelines_call_args
63+
assert "start_time: 2024-10-04_13-43-43\n" in writelines_call_args
6464
assert f"uid: {uid}\n" in writelines_call_args
6565

6666

@@ -81,7 +81,7 @@ def test_no_motors_doesnt_append_to_filename(cb):
8181
mock_file.assert_called_with(result, "a", newline="\n", encoding="utf-8")
8282
# time should have been renamed to start_time and converted to human readable
8383
writelines_call_args = mock_file().writelines.call_args[0][0]
84-
assert "start_time: 2024-10-04 13:43:43\n" in writelines_call_args
84+
assert "start_time: 2024-10-04_13-43-43\n" in writelines_call_args
8585
assert f"uid: {uid}\n" in writelines_call_args
8686

8787

0 commit comments

Comments
 (0)