Separate logic for on_scan_segment
The nested logic used in extreme.py
and BECMonitor
has to be split into smaller validation functions, which could be reused also for other applications.
@pyqtSlot(dict, dict)
def on_scan_segment(self, msg, metadata):
"""
Handle new scan segments and saves data to a dictionary. Linked through bec_dispatcher.
Args:
msg (dict): Message received with scan data.
metadata (dict): Metadata of the scan.
"""
# TODO logic can be separated into different methods or there could be separate class for scan data handling
# TODO for scan mode, if there are same names for different plots, the data are assigned multiple times
current_scanID = msg.get("scanID", None)
if current_scanID is None:
return
if current_scanID != self.scanID:
if self.scan_types is False:
self.plot_data = self.plot_data_config
elif self.scan_types is True:
currentName = metadata.get("scan_name")
if currentName is None:
raise ValueError(
f"Scan name not found in metadata. Please check the scan_name in the YAML config or in bec "
f"configuration."
)
self.plot_data = self.plot_data_config.get(currentName, [])
if self.plot_data == []:
raise ValueError(
f"Scan name {currentName} not found in the YAML config. Please check the scan_name in the "
f"YAML config or in bec configuration."
)
# Init UI
self._init_ui(self.plot_settings["num_columns"])
self.scanID = current_scanID
self.data = {}
self.init_curves()
for plot_config in self.plot_data:
plot_name = plot_config.get("plot_name", "Unnamed Plot")
x_config = plot_config["x"]
x_signal_config = x_config["signals"][0] # Assuming there's at least one signal for x
x_name = x_signal_config.get("name", "")
if not x_name:
raise ValueError(f"Name for x signal must be specified in plot: {plot_name}.")
x_entry_list = x_signal_config.get("entry", [])
if not x_entry_list:
x_entry_list = (
self.dev[x_name]._hints if hasattr(self.dev[x_name], "_hints") else [x_name]
)
if not isinstance(x_entry_list, list):
x_entry_list = [x_entry_list]
y_configs = plot_config["y"]["signals"]
for x_entry in x_entry_list:
for y_config in y_configs:
y_name = y_config.get("name", "")
if not y_name:
raise ValueError(
f"Name for y signal must be specified in plot: {plot_name}."
)
y_entry_list = y_config.get("entry", [])
if not y_entry_list:
y_entry_list = (
self.dev[y_name]._hints
if hasattr(self.dev[y_name], "_hints")
else [y_name]
)
if not isinstance(y_entry_list, list):
y_entry_list = [y_entry_list]
for y_entry in y_entry_list:
key = (x_name, x_entry, y_name, y_entry)
data_x = msg["data"].get(x_name, {}).get(x_entry, {}).get("value", None)
data_y = msg["data"].get(y_name, {}).get(y_entry, {}).get("value", None)
if data_x is None:
raise ValueError(
f"Incorrect entry '{x_entry}' specified for x in plot: {plot_name}, x name: {x_name}"
)
if data_y is None:
if hasattr(self.dev[y_name], "_hints"):
raise ValueError(
f"Incorrect entry '{y_entry}' specified for y in plot: {plot_name}, y name: {y_name}"
)
else:
raise ValueError(
f"No hints available for y in plot: {plot_name}, and name '{y_name}' did not work as entry"
)
if data_x is not None:
self.data.setdefault(key, {}).setdefault("x", []).append(data_x)
if data_y is not None:
self.data.setdefault(key, {}).setdefault("y", []).append(data_y)
self.update_signal.emit()
Edited by wyzula_j