From aaef4c4b64d580fa0a0c0bdb93c05a15406b71b6 Mon Sep 17 00:00:00 2001 From: wyzula-jan Date: Mon, 2 Feb 2026 15:29:32 +0100 Subject: [PATCH] refactor: global refactoring to use device-signal pair names --- .../upload_redis_dialog.py | 2 +- bec_widgets/applications/views/view.py | 18 +- bec_widgets/cli/client.py | 182 +++++----- .../containers/auto_update/auto_updates.py | 21 +- .../base_classes/device_signal_input_base.py | 1 + bec_widgets/widgets/plots/heatmap/heatmap.py | 342 +++++++++--------- .../plots/heatmap/settings/heatmap_setting.py | 98 ++--- .../settings/heatmap_settings_horizontal.ui | 48 +-- .../settings/heatmap_settings_vertical.ui | 48 +-- bec_widgets/widgets/plots/image/image.py | 234 ++++++------ .../toolbar_components/device_selection.py | 42 +-- .../widgets/plots/motor_map/motor_map.py | 138 +++---- .../plots/scatter_waveform/scatter_curve.py | 10 +- .../scatter_waveform/scatter_waveform.py | 288 +++++++-------- .../settings/scatter_curve_setting.py | 96 ++--- .../scatter_curve_settings_horizontal.ui | 48 +-- .../scatter_curve_settings_vertical.ui | 24 +- bec_widgets/widgets/plots/waveform/curve.py | 4 +- .../settings/curve_settings/curve_setting.py | 2 +- .../settings/curve_settings/curve_tree.py | 36 +- .../widgets/plots/waveform/waveform.py | 162 ++++----- docs/user/customisation.md | 4 +- docs/user/getting_started/quick_start.md | 4 +- docs/user/widgets/heatmap/heatmap_widget.md | 18 +- docs/user/widgets/image/image_widget.md | 8 +- docs/user/widgets/motor_map/motor_map.md | 6 +- .../scatter_waveform/scatter_waveform.md | 2 +- docs/user/widgets/waveform/waveform_widget.md | 8 +- tests/end-2-end/test_bec_dock_rpc_e2e.py | 4 +- .../end-2-end/test_plotting_framework_e2e.py | 30 +- tests/end-2-end/test_rpc_register_e2e.py | 10 +- .../test_user_interaction_e2e.py | 4 +- tests/unit_tests/test_curve_settings.py | 36 +- tests/unit_tests/test_heatmap_widget.py | 332 ++++++++--------- tests/unit_tests/test_image_view_next_gen.py | 59 ++- tests/unit_tests/test_motor_map_next_gen.py | 58 +-- tests/unit_tests/test_scatter_waveform.py | 280 +++++++------- tests/unit_tests/test_waveform.py | 52 +-- 38 files changed, 1369 insertions(+), 1390 deletions(-) diff --git a/bec_widgets/applications/views/device_manager_view/device_manager_dialogs/upload_redis_dialog.py b/bec_widgets/applications/views/device_manager_view/device_manager_dialogs/upload_redis_dialog.py index ec4e7f014..a192a7482 100644 --- a/bec_widgets/applications/views/device_manager_view/device_manager_dialogs/upload_redis_dialog.py +++ b/bec_widgets/applications/views/device_manager_view/device_manager_dialogs/upload_redis_dialog.py @@ -4,7 +4,7 @@ from enum import IntEnum from functools import partial -from typing import TYPE_CHECKING, List, Tuple +from typing import TYPE_CHECKING, Any, List, Tuple from bec_lib.logger import bec_logger from bec_qthemes import apply_theme, material_icon diff --git a/bec_widgets/applications/views/view.py b/bec_widgets/applications/views/view.py index 3b98f7568..c1351aa60 100644 --- a/bec_widgets/applications/views/view.py +++ b/bec_widgets/applications/views/view.py @@ -102,17 +102,17 @@ def on_enter(self) -> None: self.device_edit.insertItem(0, "") self.device_edit.setEditable(True) self.device_edit.setCurrentIndex(0) - self.entry_edit = SignalComboBox(parent=self) - self.entry_edit.include_config_signals = False - self.entry_edit.insertItem(0, "") - self.entry_edit.setEditable(True) - self.device_edit.currentTextChanged.connect(self.entry_edit.set_device) - self.device_edit.device_reset.connect(self.entry_edit.reset_selection) + self.signal_edit = SignalComboBox(parent=self) + self.signal_edit.include_config_signals = False + self.signal_edit.insertItem(0, "") + self.signal_edit.setEditable(True) + self.device_edit.currentTextChanged.connect(self.signal_edit.set_device) + self.device_edit.device_reset.connect(self.signal_edit.reset_selection) form = QFormLayout() form.addRow(label) form.addRow("Device", self.device_edit) - form.addRow("Signal", self.entry_edit) + form.addRow("Signal", self.signal_edit) buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, parent=dialog) buttons.accepted.connect(dialog.accept) @@ -124,7 +124,7 @@ def on_enter(self) -> None: if dialog.exec_() == QDialog.Accepted: self.waveform.plot( - y_name=self.device_edit.currentText(), y_entry=self.entry_edit.currentText() + device_y=self.device_edit.currentText(), signal_y=self.signal_edit.currentText() ) @SafeSlot() @@ -249,7 +249,7 @@ def _apply_settings_and_show_waveform(self): dev = self.device_edit.currentText() sig = self.entry_edit.currentText() if dev and sig: - self.waveform.plot(y_name=dev, y_entry=sig) + self.waveform.plot(device_y=dev, signal_y=sig) self.stack.setCurrentIndex(1) def _show_waveform_without_changes(self): diff --git a/bec_widgets/cli/client.py b/bec_widgets/cli/client.py index cf6eb1726..e9e157630 100644 --- a/bec_widgets/cli/client.py +++ b/bec_widgets/cli/client.py @@ -1965,12 +1965,12 @@ def rois(self) -> "list[BaseROI]": @rpc_call def plot( self, - x_name: "str", - y_name: "str", - z_name: "str", - x_entry: "None | str" = None, - y_entry: "None | str" = None, - z_entry: "None | str" = None, + device_x: "str", + device_y: "str", + device_z: "str", + signal_x: "None | str" = None, + signal_y: "None | str" = None, + signal_z: "None | str" = None, color_map: "str | None" = "plasma", validate_bec: "bool" = True, interpolation: "Literal['linear', 'nearest'] | None" = None, @@ -1984,12 +1984,12 @@ def plot( Plot the heatmap with the given x, y, and z data. Args: - x_name (str): The name of the x-axis signal. - y_name (str): The name of the y-axis signal. - z_name (str): The name of the z-axis signal. - x_entry (str | None): The entry for the x-axis signal. - y_entry (str | None): The entry for the y-axis signal. - z_entry (str | None): The entry for the z-axis signal. + device_x (str): The name of the x-axis device signal. + device_y (str): The name of the y-axis device signal. + device_z (str): The name of the z-axis device signal. + signal_x (str | None): The entry for the x-axis device signal. + signal_y (str | None): The entry for the y-axis device signal. + signal_z (str | None): The entry for the z-axis device signal. color_map (str | None): The color map to use for the heatmap. validate_bec (bool): Whether to validate the entries against BEC signals. interpolation (Literal["linear", "nearest"] | None): The interpolation method to use. @@ -2002,84 +2002,84 @@ def plot( @property @rpc_call - def x_device_name(self) -> "str": + def device_x(self) -> "str": """ Device name for the X axis. """ - @x_device_name.setter + @device_x.setter @rpc_call - def x_device_name(self) -> "str": + def device_x(self) -> "str": """ Device name for the X axis. """ @property @rpc_call - def x_device_entry(self) -> "str": + def signal_x(self) -> "str": """ Signal entry for the X axis device. """ - @x_device_entry.setter + @signal_x.setter @rpc_call - def x_device_entry(self) -> "str": + def signal_x(self) -> "str": """ Signal entry for the X axis device. """ @property @rpc_call - def y_device_name(self) -> "str": + def device_y(self) -> "str": """ Device name for the Y axis. """ - @y_device_name.setter + @device_y.setter @rpc_call - def y_device_name(self) -> "str": + def device_y(self) -> "str": """ Device name for the Y axis. """ @property @rpc_call - def y_device_entry(self) -> "str": + def signal_y(self) -> "str": """ Signal entry for the Y axis device. """ - @y_device_entry.setter + @signal_y.setter @rpc_call - def y_device_entry(self) -> "str": + def signal_y(self) -> "str": """ Signal entry for the Y axis device. """ @property @rpc_call - def z_device_name(self) -> "str": + def device_z(self) -> "str": """ Device name for the Z (color) axis. """ - @z_device_name.setter + @device_z.setter @rpc_call - def z_device_name(self) -> "str": + def device_z(self) -> "str": """ Device name for the Z (color) axis. """ @property @rpc_call - def z_device_entry(self) -> "str": + def signal_z(self) -> "str": """ Signal entry for the Z (color) axis device. """ - @z_device_entry.setter + @signal_z.setter @rpc_call - def z_device_entry(self) -> "str": + def signal_z(self) -> "str": """ Signal entry for the Z (color) axis device. """ @@ -2501,28 +2501,28 @@ def autorange_mode(self) -> "str": @property @rpc_call - def device_name(self) -> "str": + def device(self) -> "str": """ The name of the device to monitor for image data. """ - @device_name.setter + @device.setter @rpc_call - def device_name(self) -> "str": + def device(self) -> "str": """ The name of the device to monitor for image data. """ @property @rpc_call - def device_entry(self) -> "str": + def signal(self) -> "str": """ The signal/entry name to monitor on the device. """ - @device_entry.setter + @signal.setter @rpc_call - def device_entry(self) -> "str": + def signal(self) -> "str": """ The signal/entry name to monitor on the device. """ @@ -2630,8 +2630,8 @@ def transpose(self) -> "bool": @rpc_call def image( self, - device_name: "str | None" = None, - device_entry: "str | None" = None, + device: "str | None" = None, + signal: "str | None" = None, color_map: "str | None" = None, color_bar: "Literal['simple', 'full'] | None" = None, vrange: "tuple[int, int] | None" = None, @@ -2640,8 +2640,8 @@ def image( Set the image source and update the image. Args: - device_name(str|None): The name of the device to monitor. If None or empty string, the current monitor will be disconnected. - device_entry(str|None): The signal/entry name to monitor on the device. + device(str|None): The name of the device to monitor. If None or empty string, the current monitor will be disconnected. + signal(str|None): The signal/entry name to monitor on the device. color_map(str): The color map to use for the image. color_bar(str): The type of color bar to use. Options are "simple" or "full". vrange(tuple): The range of values to use for the color map. @@ -3653,14 +3653,14 @@ def scatter_size(self) -> "int": @rpc_call def map( - self, x_name: "str", y_name: "str", validate_bec: "bool" = True, suppress_errors=False + self, device_x: "str", device_y: "str", validate_bec: "bool" = True, suppress_errors=False ) -> "None": """ Set the x and y motor names. Args: - x_name(str): The name of the x motor. - y_name(str): The name of the y motor. + device_x(str): The name of the x motor. + device_y(str): The name of the y motor. validate_bec(bool, optional): If True, validate the signal with BEC. Defaults to True. suppress_errors(bool, optional): If True, suppress errors during validation. Defaults to False. Used for properties setting. If the validation fails, the changes are not applied. """ @@ -3682,28 +3682,28 @@ def get_data(self) -> "dict": @property @rpc_call - def x_motor(self) -> "str": + def device_x(self) -> "str": """ Name of the motor shown on the X axis. """ - @x_motor.setter + @device_x.setter @rpc_call - def x_motor(self) -> "str": + def device_x(self) -> "str": """ Name of the motor shown on the X axis. """ @property @rpc_call - def y_motor(self) -> "str": + def device_y(self) -> "str": """ Name of the motor shown on the Y axis. """ - @y_motor.setter + @device_y.setter @rpc_call - def y_motor(self) -> "str": + def device_y(self) -> "str": """ Name of the motor shown on the Y axis. """ @@ -5248,12 +5248,12 @@ def color_map(self) -> "str": @rpc_call def plot( self, - x_name: "str", - y_name: "str", - z_name: "str", - x_entry: "None | str" = None, - y_entry: "None | str" = None, - z_entry: "None | str" = None, + device_x: "str", + device_y: "str", + device_z: "str", + signal_x: "None | str" = None, + signal_y: "None | str" = None, + signal_z: "None | str" = None, color_map: "str | None" = "plasma", label: "str | None" = None, validate_bec: "bool" = True, @@ -5262,12 +5262,12 @@ def plot( Plot the data from the device signals. Args: - x_name (str): The name of the x device signal. - y_name (str): The name of the y device signal. - z_name (str): The name of the z device signal. - x_entry (None | str): The x entry of the device signal. - y_entry (None | str): The y entry of the device signal. - z_entry (None | str): The z entry of the device signal. + device_x (str): The name of the x device signal. + device_y (str): The name of the y device signal. + device_z (str): The name of the z device signal. + signal_x (None | str): The x entry of the device signal. + signal_y (None | str): The y entry of the device signal. + signal_z (None | str): The z entry of the device signal. color_map (str | None): The color map of the scatter waveform. label (str | None): The label of the curve. validate_bec (bool): Whether to validate the device signals with current BEC instance. @@ -5295,84 +5295,84 @@ def clear_all(self): @property @rpc_call - def x_device_name(self) -> "str": + def device_x(self) -> "str": """ Device name for the X axis. """ - @x_device_name.setter + @device_x.setter @rpc_call - def x_device_name(self) -> "str": + def device_x(self) -> "str": """ Device name for the X axis. """ @property @rpc_call - def x_device_entry(self) -> "str": + def signal_x(self) -> "str": """ Signal entry for the X axis device. """ - @x_device_entry.setter + @signal_x.setter @rpc_call - def x_device_entry(self) -> "str": + def signal_x(self) -> "str": """ Signal entry for the X axis device. """ @property @rpc_call - def y_device_name(self) -> "str": + def device_y(self) -> "str": """ Device name for the Y axis. """ - @y_device_name.setter + @device_y.setter @rpc_call - def y_device_name(self) -> "str": + def device_y(self) -> "str": """ Device name for the Y axis. """ @property @rpc_call - def y_device_entry(self) -> "str": + def signal_y(self) -> "str": """ Signal entry for the Y axis device. """ - @y_device_entry.setter + @signal_y.setter @rpc_call - def y_device_entry(self) -> "str": + def signal_y(self) -> "str": """ Signal entry for the Y axis device. """ @property @rpc_call - def z_device_name(self) -> "str": + def device_z(self) -> "str": """ Device name for the Z (color) axis. """ - @z_device_name.setter + @device_z.setter @rpc_call - def z_device_name(self) -> "str": + def device_z(self) -> "str": """ Device name for the Z (color) axis. """ @property @rpc_call - def z_device_entry(self) -> "str": + def signal_z(self) -> "str": """ Signal entry for the Z (color) axis device. """ - @z_device_entry.setter + @signal_z.setter @rpc_call - def z_device_entry(self) -> "str": + def signal_z(self) -> "str": """ Signal entry for the Z (color) axis device. """ @@ -5900,14 +5900,14 @@ def x_mode(self) -> "str": @property @rpc_call - def x_entry(self) -> "str | None": + def signal_x(self) -> "str | None": """ The x signal name. """ - @x_entry.setter + @signal_x.setter @rpc_call - def x_entry(self) -> "str | None": + def signal_x(self) -> "str | None": """ The x signal name. """ @@ -5974,10 +5974,10 @@ def plot( arg1: "list | np.ndarray | str | None" = None, y: "list | np.ndarray | None" = None, x: "list | np.ndarray | None" = None, - x_name: "str | None" = None, - y_name: "str | None" = None, - x_entry: "str | None" = None, - y_entry: "str | None" = None, + device_x: "str | None" = None, + device_y: "str | None" = None, + signal_x: "str | None" = None, + signal_y: "str | None" = None, color: "str | None" = None, label: "str | None" = None, dap: "str | None" = None, @@ -5989,17 +5989,17 @@ def plot( Plot a curve to the plot widget. Args: - arg1(list | np.ndarray | str | None): First argument, which can be x data, y data, or y_name. + arg1(list | np.ndarray | str | None): First argument, which can be x data, y data, or device_y. y(list | np.ndarray): Custom y data to plot. x(list | np.ndarray): Custom y data to plot. - x_name(str): Name of the x signal. + device_x(str): Name of the x signal. - "auto": Use the best effort signal. - "timestamp": Use the timestamp signal. - "index": Use the index signal. - Custom signal name of a device from BEC. - y_name(str): The name of the device for the y-axis. - x_entry(str): The name of the entry for the x-axis. - y_entry(str): The name of the entry for the y-axis. + device_y(str): The name of the device for the y-axis. + signal_x(str): The name of the entry for the x-axis. + signal_y(str): The name of the entry for the y-axis. color(str): The color of the curve. label(str): The label of the curve. dap(str): The dap model to use for the curve. When provided, a DAP curve is diff --git a/bec_widgets/widgets/containers/auto_update/auto_updates.py b/bec_widgets/widgets/containers/auto_update/auto_updates.py index e3c7a7092..856de98ed 100644 --- a/bec_widgets/widgets/containers/auto_update/auto_updates.py +++ b/bec_widgets/widgets/containers/auto_update/auto_updates.py @@ -256,8 +256,8 @@ def simple_line_scan(self, info: ScanStatusMessage) -> None: # as the label and title wf.clear_all() wf.plot( - x_name=dev_x, - y_name=dev_y, + device_x=dev_x, + device_y=dev_y, label=f"Scan {info.scan_number} - {dev_y}", title=f"Scan {info.scan_number}", x_label=dev_x, @@ -265,7 +265,7 @@ def simple_line_scan(self, info: ScanStatusMessage) -> None: ) logger.info( - f"Auto Update [simple_line_scan]: Started plot with: x_name={dev_x}, y_name={dev_y}" + f"Auto Update [simple_line_scan]: Started plot with: device_x={dev_x}, device_y={dev_y}" ) def simple_grid_scan(self, info: ScanStatusMessage) -> None: @@ -288,11 +288,14 @@ def simple_grid_scan(self, info: ScanStatusMessage) -> None: # Clear the scatter waveform widget and plot the data scatter.clear_all() scatter.plot( - x_name=dev_x, y_name=dev_y, z_name=dev_z, label=f"Scan {info.scan_number} - {dev_z}" + device_x=dev_x, + device_y=dev_y, + device_z=dev_z, + label=f"Scan {info.scan_number} - {dev_z}", ) logger.info( - f"Auto Update [simple_grid_scan]: Started plot with: x_name={dev_x}, y_name={dev_y}, z_name={dev_z}" + f"Auto Update [simple_grid_scan]: Started plot with: device_x={dev_x}, device_y={dev_y}, device_z={dev_z}" ) def best_effort(self, info: ScanStatusMessage) -> None: @@ -317,15 +320,17 @@ def best_effort(self, info: ScanStatusMessage) -> None: # Clear the waveform widget and plot the data wf.clear_all() wf.plot( - x_name=dev_x, - y_name=dev_y, + device_x=dev_x, + device_y=dev_y, label=f"Scan {info.scan_number} - {dev_y}", title=f"Scan {info.scan_number}", x_label=dev_x, y_label=dev_y, ) - logger.info(f"Auto Update [best_effort]: Started plot with: x_name={dev_x}, y_name={dev_y}") + logger.info( + f"Auto Update [best_effort]: Started plot with: device_x={dev_x}, device_y={dev_y}" + ) ####################################################################### ################# GUI Callbacks ####################################### diff --git a/bec_widgets/widgets/control/device_input/base_classes/device_signal_input_base.py b/bec_widgets/widgets/control/device_input/base_classes/device_signal_input_base.py index 07e993e3d..cc03c9a31 100644 --- a/bec_widgets/widgets/control/device_input/base_classes/device_signal_input_base.py +++ b/bec_widgets/widgets/control/device_input/base_classes/device_signal_input_base.py @@ -266,6 +266,7 @@ def validate_device(self, device: str | None, raise_on_false: bool = False) -> b Args: device(str): Device to validate. + raise_on_false(bool): Raise ValueError if device is not found. """ if device in self.dev: return True diff --git a/bec_widgets/widgets/plots/heatmap/heatmap.py b/bec_widgets/widgets/plots/heatmap/heatmap.py index 3266d9b74..22287ca3f 100644 --- a/bec_widgets/widgets/plots/heatmap/heatmap.py +++ b/bec_widgets/widgets/plots/heatmap/heatmap.py @@ -35,8 +35,8 @@ class HeatmapDeviceSignal(BaseModel): """The configuration of a signal in the scatter waveform widget.""" - name: str - entry: str + device: str + signal: str model_config: dict = {"validate_assignment": True} @@ -65,13 +65,13 @@ class HeatmapConfig(ConnectionConfig): lock_aspect_ratio: bool = Field( False, description="Whether to lock the aspect ratio of the image." ) - x_device: HeatmapDeviceSignal | None = Field( + device_x: HeatmapDeviceSignal | None = Field( None, description="The x device signal of the heatmap." ) - y_device: HeatmapDeviceSignal | None = Field( + device_y: HeatmapDeviceSignal | None = Field( None, description="The y device signal of the heatmap." ) - z_device: HeatmapDeviceSignal | None = Field( + device_z: HeatmapDeviceSignal | None = Field( None, description="The z device signal of the heatmap." ) @@ -204,18 +204,18 @@ class Heatmap(ImageBase): "rois", "plot", # Device properties - "x_device_name", - "x_device_name.setter", - "x_device_entry", - "x_device_entry.setter", - "y_device_name", - "y_device_name.setter", - "y_device_entry", - "y_device_entry.setter", - "z_device_name", - "z_device_name.setter", - "z_device_entry", - "z_device_entry.setter", + "device_x", + "device_x.setter", + "signal_x", + "signal_x.setter", + "device_y", + "device_y.setter", + "signal_y", + "signal_y.setter", + "device_z", + "device_z.setter", + "signal_z", + "signal_z.setter", ] PLUGIN = True @@ -238,9 +238,9 @@ def __init__(self, parent=None, config: HeatmapConfig | None = None, **kwargs): interpolation="linear", oversampling_factor=1.0, lock_aspect_ratio=False, - x_device=None, - y_device=None, - z_device=None, + device_x=None, + device_y=None, + device_z=None, ) super().__init__(parent=parent, config=config, theme_update=True, **kwargs) self._image_config = config @@ -314,12 +314,12 @@ def apply_theme(self, theme: str): @SafeSlot(popup_error=True) def plot( self, - x_name: str, - y_name: str, - z_name: str, - x_entry: None | str = None, - y_entry: None | str = None, - z_entry: None | str = None, + device_x: str, + device_y: str, + device_z: str, + signal_x: None | str = None, + signal_y: None | str = None, + signal_z: None | str = None, color_map: str | None = "plasma", validate_bec: bool = True, interpolation: Literal["linear", "nearest"] | None = None, @@ -333,12 +333,12 @@ def plot( Plot the heatmap with the given x, y, and z data. Args: - x_name (str): The name of the x-axis signal. - y_name (str): The name of the y-axis signal. - z_name (str): The name of the z-axis signal. - x_entry (str | None): The entry for the x-axis signal. - y_entry (str | None): The entry for the y-axis signal. - z_entry (str | None): The entry for the z-axis signal. + device_x (str): The name of the x-axis device signal. + device_y (str): The name of the y-axis device signal. + device_z (str): The name of the z-axis device signal. + signal_x (str | None): The entry for the x-axis device signal. + signal_y (str | None): The entry for the y-axis device signal. + signal_z (str | None): The entry for the z-axis device signal. color_map (str | None): The color map to use for the heatmap. validate_bec (bool): Whether to validate the entries against BEC signals. interpolation (Literal["linear", "nearest"] | None): The interpolation method to use. @@ -349,13 +349,13 @@ def plot( reload (bool): Whether to reload the heatmap with new data. """ if validate_bec: - x_entry = self.entry_validator.validate_signal(x_name, x_entry) - y_entry = self.entry_validator.validate_signal(y_name, y_entry) - z_entry = self.entry_validator.validate_signal(z_name, z_entry) + signal_x = self.entry_validator.validate_signal(device_x, signal_x) + signal_y = self.entry_validator.validate_signal(device_y, signal_y) + signal_z = self.entry_validator.validate_signal(device_z, signal_z) - if x_entry is None or y_entry is None or z_entry is None: + if signal_x is None or signal_y is None or signal_z is None: raise ValueError("x, y, and z entries must be provided.") - if x_name is None or y_name is None or z_name is None: + if device_x is None or device_y is None or device_z is None: raise ValueError("x, y, and z names must be provided.") if interpolation is None: @@ -374,24 +374,24 @@ def plot( show_config_label = self._image_config.show_config_label def _device_key(device: HeatmapDeviceSignal | None) -> tuple[str | None, str | None]: - return (device.name if device else None, device.entry if device else None) + return (device.device if device else None, device.signal if device else None) prev_cfg = getattr(self, "_image_config", None) config_changed = False - if prev_cfg and prev_cfg.x_device and prev_cfg.y_device and prev_cfg.z_device: + if prev_cfg and prev_cfg.device_x and prev_cfg.device_y and prev_cfg.device_z: config_changed = any( ( - _device_key(prev_cfg.x_device) != (x_name, x_entry), - _device_key(prev_cfg.y_device) != (y_name, y_entry), - _device_key(prev_cfg.z_device) != (z_name, z_entry), + _device_key(prev_cfg.device_x) != (device_x, signal_x), + _device_key(prev_cfg.device_y) != (device_y, signal_y), + _device_key(prev_cfg.device_z) != (device_z, signal_z), ) ) self._image_config = HeatmapConfig( parent_id=self.gui_id, - x_device=HeatmapDeviceSignal(name=x_name, entry=x_entry), - y_device=HeatmapDeviceSignal(name=y_name, entry=y_entry), - z_device=HeatmapDeviceSignal(name=z_name, entry=z_entry), + device_x=HeatmapDeviceSignal(device=device_x, signal=signal_x), + device_y=HeatmapDeviceSignal(device=device_y, signal=signal_y), + device_z=HeatmapDeviceSignal(device=device_z, signal=signal_z), color_map=color_map, color_bar=None, interpolation=interpolation, @@ -428,26 +428,26 @@ def update_labels(self): return # Safely get device names (might be None if not yet configured) - x_device = self._image_config.x_device - y_device = self._image_config.y_device - z_device = self._image_config.z_device + device_x = self._image_config.device_x + device_y = self._image_config.device_y + device_z = self._image_config.device_z - x_name = x_device.name if x_device else None - y_name = y_device.name if y_device else None - z_name = z_device.name if z_device else None + device_x_name = device_x.device if device_x else None + device_y_name = device_y.device if device_y else None + device_z_name = device_z.device if device_z else None - if x_name is not None: - self.x_label = x_name # type: ignore - x_dev = self.dev.get(x_name) + if device_x_name is not None: + self.x_label = device_x_name # type: ignore + x_dev = self.dev.get(device_x_name) if x_dev and hasattr(x_dev, "egu"): self.x_label_units = x_dev.egu() - if y_name is not None: - self.y_label = y_name # type: ignore - y_dev = self.dev.get(y_name) + if device_y_name is not None: + self.y_label = device_y_name # type: ignore + y_dev = self.dev.get(device_y_name) if y_dev and hasattr(y_dev, "egu"): self.y_label_units = y_dev.egu() - if z_name is not None: - self.title = z_name + if device_z_name is not None: + self.title = device_z_name def _init_toolbar_heatmap(self): """ @@ -572,23 +572,23 @@ def update_plot(self, _=None) -> None: if self._image_config is None: return try: - x_name = self._image_config.x_device.name - x_entry = self._image_config.x_device.entry - y_name = self._image_config.y_device.name - y_entry = self._image_config.y_device.entry - z_name = self._image_config.z_device.name - z_entry = self._image_config.z_device.entry + device_x = self._image_config.device_x.device + signal_x = self._image_config.device_x.signal + device_y = self._image_config.device_y.device + signal_y = self._image_config.device_y.signal + device_z = self._image_config.device_z.device + signal_z = self._image_config.device_z.signal except AttributeError: return if access_key == "val": - x_data = data.get(x_name, {}).get(x_entry, {}).get(access_key, None) - y_data = data.get(y_name, {}).get(y_entry, {}).get(access_key, None) - z_data = data.get(z_name, {}).get(z_entry, {}).get(access_key, None) + x_data = data.get(device_x, {}).get(signal_x, {}).get(access_key, None) + y_data = data.get(device_y, {}).get(signal_y, {}).get(access_key, None) + z_data = data.get(device_z, {}).get(signal_z, {}).get(access_key, None) else: - x_data = data.get(x_name, {}).get(x_entry, {}).read().get("value", None) - y_data = data.get(y_name, {}).get(y_entry, {}).read().get("value", None) - z_data = data.get(z_name, {}).get(z_entry, {}).read().get("value", None) + x_data = data.get(device_x, {}).get(signal_x, {}).read().get("value", None) + y_data = data.get(device_y, {}).get(signal_y, {}).read().get("value", None) + z_data = data.get(device_z, {}).get(signal_z, {}).read().get("value", None) if not isinstance(x_data, list): x_data = x_data.tolist() if isinstance(x_data, np.ndarray) else None @@ -839,7 +839,6 @@ def get_image_data( x_data (np.ndarray): The x data. y_data (np.ndarray): The y data. z_data (np.ndarray): The z data. - msg (messages.ScanStatusMessage): The scan status message. Returns: tuple[np.ndarray, QTransform]: The image data and the QTransform. @@ -854,7 +853,7 @@ def get_image_data( if len(z_data) < 4: # LinearNDInterpolator requires at least 4 points to interpolate return None, None - return self.get_step_scan_image(x_data, y_data, z_data, msg) + return self.get_step_scan_image(x_data, y_data, z_data) def _is_grid_scan_supported(self, msg: messages.ScanStatusMessage) -> bool: """Check if the scan can use optimized grid_scan rendering. @@ -871,11 +870,11 @@ def _is_grid_scan_supported(self, msg: messages.ScanStatusMessage) -> bool: if msg.scan_name != "grid_scan" or self._image_config.enforce_interpolation: return False - device_x = self._image_config.x_device.entry - device_y = self._image_config.y_device.entry + signal_x = self._image_config.device_x.signal + signal_y = self._image_config.device_y.signal return ( - device_x in msg.request_inputs["arg_bundle"] - and device_y in msg.request_inputs["arg_bundle"] + signal_x in msg.request_inputs["arg_bundle"] + and signal_y in msg.request_inputs["arg_bundle"] ) def get_grid_scan_image( @@ -893,9 +892,9 @@ def get_grid_scan_image( args = self.arg_bundle_to_dict(4, msg.request_inputs["arg_bundle"]) - x_entry = self._image_config.x_device.entry - y_entry = self._image_config.y_device.entry - shape = (args[x_entry][-1], args[y_entry][-1]) + signal_x = self._image_config.device_x.signal + signal_y = self._image_config.device_y.signal + shape = (args[signal_x][-1], args[signal_y][-1]) data = self.main_image.raw_data @@ -925,8 +924,8 @@ def _axis_levels(entry: str, npts: int) -> np.ndarray: return origin + np.linspace(start, stop, npts) return np.linspace(start, stop, npts) - x_levels = _axis_levels(x_entry, shape[0]) - y_levels = _axis_levels(y_entry, shape[1]) + x_levels = _axis_levels(signal_x, shape[0]) + y_levels = _axis_levels(signal_y, shape[1]) pixel_size_x = ( float(x_levels[-1] - x_levels[0]) / max(shape[0] - 1, 1) if shape[0] > 1 else 1.0 @@ -949,7 +948,7 @@ def _axis_levels(entry: str, npts: int) -> np.ndarray: if snaked and (slow_i % 2 == 1): fast_i = args[fast_entry][-1] - 1 - fast_i - if x_entry == fast_entry: + if signal_x == fast_entry: x_i, y_i = fast_i, slow_i else: x_i, y_i = slow_i, fast_i @@ -959,11 +958,7 @@ def _axis_levels(entry: str, npts: int) -> np.ndarray: return data, transform def get_step_scan_image( - self, - x_data: list[float], - y_data: list[float], - z_data: list[float], - msg: messages.ScanStatusMessage, + self, x_data: list[float], y_data: list[float], z_data: list[float] ) -> tuple[np.ndarray, QTransform]: """ Get the image data for an arbitrary step scan. @@ -972,7 +967,6 @@ def get_step_scan_image( x_data (list[float]): The x data. y_data (list[float]): The y data. z_data (list[float]): The z data. - msg (messages.ScanStatusMessage): The scan status message. Returns: tuple[np.ndarray, QTransform]: The image data and the QTransform. @@ -1033,7 +1027,7 @@ def get_image_grid(self, positions) -> tuple[np.ndarray, np.ndarray, QTransform] to avoid recalculating the grid for the same scan. Args: - _scan_id (str): The scan ID. Needed for caching but not used in the function. + positions: positions of the data points. Returns: tuple[np.ndarray, np.ndarray, QTransform]: The grid x and y coordinates and the QTransform. @@ -1108,11 +1102,13 @@ def estimate_image_resolution(coords: np.ndarray) -> tuple[int, int]: return max(1, width_pixels), max(1, height_pixels) - def arg_bundle_to_dict(self, bundle_size: int, args: list) -> dict: + @staticmethod + def arg_bundle_to_dict(bundle_size: int, args: list) -> dict: """ Convert the argument bundle to a dictionary. Args: + bundle_size (int): The size of each argument bundle. args (list): The argument bundle. Returns: @@ -1160,14 +1156,14 @@ def reset(self): ################################################################################ @SafeProperty(str) - def x_device_name(self) -> str: + def device_x(self) -> str: """Device name for the X axis.""" - if self._image_config.x_device is None: + if self._image_config.device_x is None: return "" - return self._image_config.x_device.name or "" + return self._image_config.device_x.device or "" - @x_device_name.setter - def x_device_name(self, device_name: str) -> None: + @device_x.setter + def device_x(self, device_name: str) -> None: """ Set the X device name. @@ -1179,27 +1175,27 @@ def x_device_name(self, device_name: str) -> None: # Get current entry or validate if device_name: try: - entry = self.entry_validator.validate_signal(device_name, None) - self._image_config.x_device = HeatmapDeviceSignal(name=device_name, entry=entry) - self.property_changed.emit("x_device_name", device_name) + signal = self.entry_validator.validate_signal(device_name, None) + self._image_config.device_x = HeatmapDeviceSignal(device=device_name, signal=signal) + self.property_changed.emit("device_x", device_name) self.update_labels() # Update axis labels self._try_auto_plot() except Exception: pass # Silently fail if device is not available yet else: - self._image_config.x_device = None - self.property_changed.emit("x_device_name", "") + self._image_config.device_x = None + self.property_changed.emit("device_x", "") self.update_labels() # Clear axis labels @SafeProperty(str) - def x_device_entry(self) -> str: + def signal_x(self) -> str: """Signal entry for the X axis device.""" - if self._image_config.x_device is None: + if self._image_config.device_x is None: return "" - return self._image_config.x_device.entry or "" + return self._image_config.device_x.signal or "" - @x_device_entry.setter - def x_device_entry(self, entry: str) -> None: + @signal_x.setter + def signal_x(self, entry: str) -> None: """ Set the X device entry. @@ -1209,32 +1205,32 @@ def x_device_entry(self, entry: str) -> None: if not entry: return - if self._image_config.x_device is None: - logger.warning("Cannot set x_device_entry without x_device_name set first.") + if self._image_config.device_x is None: + logger.warning("Cannot set signal_x without device_x set first.") return - device_name = self._image_config.x_device.name + device_name = self._image_config.device_x.device try: # Validate the entry for this device - validated_entry = self.entry_validator.validate_signal(device_name, entry) - self._image_config.x_device = HeatmapDeviceSignal( - name=device_name, entry=validated_entry + validated_signal = self.entry_validator.validate_signal(device_name, entry) + self._image_config.device_x = HeatmapDeviceSignal( + device=device_name, signal=validated_signal ) - self.property_changed.emit("x_device_entry", validated_entry) + self.property_changed.emit("signal_x", validated_signal) self.update_labels() # Update axis labels self._try_auto_plot() except Exception: pass # Silently fail if validation fails @SafeProperty(str) - def y_device_name(self) -> str: + def device_y(self) -> str: """Device name for the Y axis.""" - if self._image_config.y_device is None: + if self._image_config.device_y is None: return "" - return self._image_config.y_device.name or "" + return self._image_config.device_y.device or "" - @y_device_name.setter - def y_device_name(self, device_name: str) -> None: + @device_y.setter + def device_y(self, device_name: str) -> None: """ Set the Y device name. @@ -1246,27 +1242,27 @@ def y_device_name(self, device_name: str) -> None: # Get current entry or validate if device_name: try: - entry = self.entry_validator.validate_signal(device_name, None) - self._image_config.y_device = HeatmapDeviceSignal(name=device_name, entry=entry) - self.property_changed.emit("y_device_name", device_name) + signal = self.entry_validator.validate_signal(device_name, None) + self._image_config.device_y = HeatmapDeviceSignal(device=device_name, signal=signal) + self.property_changed.emit("device_y", device_name) self.update_labels() # Update axis labels self._try_auto_plot() except Exception: pass # Silently fail if device is not available yet else: - self._image_config.y_device = None - self.property_changed.emit("y_device_name", "") + self._image_config.device_y = None + self.property_changed.emit("device_y", "") self.update_labels() # Clear axis labels @SafeProperty(str) - def y_device_entry(self) -> str: + def signal_y(self) -> str: """Signal entry for the Y axis device.""" - if self._image_config.y_device is None: + if self._image_config.device_y is None: return "" - return self._image_config.y_device.entry or "" + return self._image_config.device_y.signal or "" - @y_device_entry.setter - def y_device_entry(self, entry: str) -> None: + @signal_y.setter + def signal_y(self, entry: str) -> None: """ Set the Y device entry. @@ -1276,18 +1272,18 @@ def y_device_entry(self, entry: str) -> None: if not entry: return - if self._image_config.y_device is None: - logger.warning("Cannot set y_device_entry without y_device_name set first.") + if self._image_config.device_y is None: + logger.warning("Cannot set signal_y without device_y set first.") return - device_name = self._image_config.y_device.name + device_name = self._image_config.device_y.device try: # Validate the entry for this device - validated_entry = self.entry_validator.validate_signal(device_name, entry) - self._image_config.y_device = HeatmapDeviceSignal( - name=device_name, entry=validated_entry + validated_signal = self.entry_validator.validate_signal(device_name, entry) + self._image_config.device_y = HeatmapDeviceSignal( + device=device_name, signal=validated_signal ) - self.property_changed.emit("y_device_entry", validated_entry) + self.property_changed.emit("signal_y", validated_signal) self.update_labels() # Update axis labels self._try_auto_plot() except Exception as e: @@ -1295,14 +1291,14 @@ def y_device_entry(self, entry: str) -> None: pass # Silently fail if validation fails @SafeProperty(str) - def z_device_name(self) -> str: + def device_z(self) -> str: """Device name for the Z (color) axis.""" - if self._image_config.z_device is None: + if self._image_config.device_z is None: return "" - return self._image_config.z_device.name or "" + return self._image_config.device_z.device or "" - @z_device_name.setter - def z_device_name(self, device_name: str) -> None: + @device_z.setter + def device_z(self, device_name: str) -> None: """ Set the Z device name. @@ -1314,28 +1310,28 @@ def z_device_name(self, device_name: str) -> None: # Get current entry or validate if device_name: try: - entry = self.entry_validator.validate_signal(device_name, None) - self._image_config.z_device = HeatmapDeviceSignal(name=device_name, entry=entry) - self.property_changed.emit("z_device_name", device_name) + signal = self.entry_validator.validate_signal(device_name, None) + self._image_config.device_z = HeatmapDeviceSignal(device=device_name, signal=signal) + self.property_changed.emit("device_z", device_name) self.update_labels() # Update axis labels (title) self._try_auto_plot() except Exception as e: logger.debug(f"Z device name validation failed: {e}") pass # Silently fail if device is not available yet else: - self._image_config.z_device = None - self.property_changed.emit("z_device_name", "") + self._image_config.device_z = None + self.property_changed.emit("device_z", "") self.update_labels() # Clear axis labels @SafeProperty(str) - def z_device_entry(self) -> str: + def signal_z(self) -> str: """Signal entry for the Z (color) axis device.""" - if self._image_config.z_device is None: + if self._image_config.device_z is None: return "" - return self._image_config.z_device.entry or "" + return self._image_config.device_z.signal or "" - @z_device_entry.setter - def z_device_entry(self, entry: str) -> None: + @signal_z.setter + def signal_z(self, entry: str) -> None: """ Set the Z device entry. @@ -1345,18 +1341,18 @@ def z_device_entry(self, entry: str) -> None: if not entry: return - if self._image_config.z_device is None: - logger.warning("Cannot set z_device_entry without z_device_name set first.") + if self._image_config.device_z is None: + logger.warning("Cannot set signal_z without device_z set first.") return - device_name = self._image_config.z_device.name + device_name = self._image_config.device_z.device try: # Validate the entry for this device - validated_entry = self.entry_validator.validate_signal(device_name, entry) - self._image_config.z_device = HeatmapDeviceSignal( - name=device_name, entry=validated_entry + validated_signal = self.entry_validator.validate_signal(device_name, entry) + self._image_config.device_z = HeatmapDeviceSignal( + device=device_name, signal=validated_signal ) - self.property_changed.emit("z_device_entry", validated_entry) + self.property_changed.emit("signal_z", validated_signal) self.update_labels() # Update axis labels (title) self._try_auto_plot() except Exception as e: @@ -1368,25 +1364,25 @@ def _try_auto_plot(self) -> None: Attempt to automatically call plot() if all three devices are set. Similar to waveform's approach but requires all three devices. """ - has_x = self._image_config.x_device is not None - has_y = self._image_config.y_device is not None - has_z = self._image_config.z_device is not None + has_x = self._image_config.device_x is not None + has_y = self._image_config.device_y is not None + has_z = self._image_config.device_z is not None if has_x and has_y and has_z: - x_name = self._image_config.x_device.name - x_entry = self._image_config.x_device.entry - y_name = self._image_config.y_device.name - y_entry = self._image_config.y_device.entry - z_name = self._image_config.z_device.name - z_entry = self._image_config.z_device.entry + device_x = self._image_config.device_x.device + signal_x = self._image_config.device_x.signal + device_y = self._image_config.device_y.device + signal_y = self._image_config.device_y.signal + device_z = self._image_config.device_z.device + signal_z = self._image_config.device_z.signal try: self.plot( - x_name=x_name, - y_name=y_name, - z_name=z_name, - x_entry=x_entry, - y_entry=y_entry, - z_entry=z_entry, + device_x=device_x, + device_y=device_y, + device_z=device_z, + signal_x=signal_x, + signal_y=signal_y, + signal_z=signal_z, validate_bec=False, # Don't validate - entries already validated ) except Exception as e: @@ -1533,6 +1529,6 @@ def cleanup(self): app = QApplication(sys.argv) heatmap = Heatmap() - heatmap.plot(x_name="samx", y_name="samy", z_name="bpm4i", oversampling_factor=5.0) + heatmap.plot(device_x="samx", device_y="samy", device_z="bpm4i", oversampling_factor=5.0) heatmap.show() sys.exit(app.exec_()) diff --git a/bec_widgets/widgets/plots/heatmap/settings/heatmap_setting.py b/bec_widgets/widgets/plots/heatmap/settings/heatmap_setting.py index c55d34064..8238caa77 100644 --- a/bec_widgets/widgets/plots/heatmap/settings/heatmap_setting.py +++ b/bec_widgets/widgets/plots/heatmap/settings/heatmap_setting.py @@ -48,7 +48,7 @@ def __init__(self, parent=None, target_widget=None, popup=False, *args, **kwargs if popup is False: self.ui.button_apply.clicked.connect(self.accept_changes) - self.ui.x_name.setFocus() + self.ui.device_x.setFocus() @SafeSlot() def fetch_all_properties(self): @@ -62,44 +62,44 @@ def fetch_all_properties(self): color_map = getattr(self.target_widget, "color_map", None) # Default values for device properties - x_name, x_entry = None, None - y_name, y_entry = None, None - z_name, z_entry = None, None + device_x, signal_x = None, None + device_y, signal_y = None, None + device_z, signal_z = None, None # Safely access device properties if hasattr(self.target_widget, "_image_config") and self.target_widget._image_config: config = self.target_widget._image_config - if hasattr(config, "x_device") and config.x_device: - x_name = getattr(config.x_device, "name", None) - x_entry = getattr(config.x_device, "entry", None) + if hasattr(config, "device_x") and config.device_x: + device_x = getattr(config.device_x, "device", None) + signal_x = getattr(config.device_x, "signal", None) - if hasattr(config, "y_device") and config.y_device: - y_name = getattr(config.y_device, "name", None) - y_entry = getattr(config.y_device, "entry", None) + if hasattr(config, "device_y") and config.device_y: + device_y = getattr(config.device_y, "device", None) + signal_y = getattr(config.device_y, "signal", None) - if hasattr(config, "z_device") and config.z_device: - z_name = getattr(config.z_device, "name", None) - z_entry = getattr(config.z_device, "entry", None) + if hasattr(config, "device_z") and config.device_z: + device_z = getattr(config.device_z, "device", None) + signal_z = getattr(config.device_z, "signal", None) # Apply the properties to the settings widget if hasattr(self.ui, "color_map"): self.ui.color_map.colormap = color_map - if hasattr(self.ui, "x_name"): - self.ui.x_name.set_device(x_name) - if hasattr(self.ui, "x_entry") and x_entry is not None: - self.ui.x_entry.set_to_obj_name(x_entry) + if hasattr(self.ui, "device_x"): + self.ui.device_x.set_device(device_x) + if hasattr(self.ui, "signal_x") and signal_x is not None: + self.ui.signal_x.set_to_obj_name(signal_x) - if hasattr(self.ui, "y_name"): - self.ui.y_name.set_device(y_name) - if hasattr(self.ui, "y_entry") and y_entry is not None: - self.ui.y_entry.set_to_obj_name(y_entry) + if hasattr(self.ui, "device_y"): + self.ui.device_y.set_device(device_y) + if hasattr(self.ui, "signal_y") and signal_y is not None: + self.ui.signal_y.set_to_obj_name(signal_y) - if hasattr(self.ui, "z_name"): - self.ui.z_name.set_device(z_name) - if hasattr(self.ui, "z_entry") and z_entry is not None: - self.ui.z_entry.set_to_obj_name(z_entry) + if hasattr(self.ui, "device_z"): + self.ui.device_z.set_device(device_z) + if hasattr(self.ui, "signal_z") and signal_z is not None: + self.ui.signal_z.set_to_obj_name(signal_z) if hasattr(self.ui, "interpolation"): self.ui.interpolation.setCurrentText( @@ -119,12 +119,12 @@ def accept_changes(self): """ Apply all properties from the settings widget to the target widget. """ - x_name = self.ui.x_name.currentText() - x_entry = self.ui.x_entry.get_signal_name() - y_name = self.ui.y_name.currentText() - y_entry = self.ui.y_entry.get_signal_name() - z_name = self.ui.z_name.currentText() - z_entry = self.ui.z_entry.get_signal_name() + device_x = self.ui.device_x.currentText() + signal_x = self.ui.signal_x.get_signal_name() + device_y = self.ui.device_y.currentText() + signal_y = self.ui.signal_y.get_signal_name() + device_z = self.ui.device_z.currentText() + signal_z = self.ui.signal_z.get_signal_name() validate_bec = self.ui.validate_bec.checked color_map = self.ui.color_map.colormap interpolation = self.ui.interpolation.currentText() @@ -132,12 +132,12 @@ def accept_changes(self): enforce_interpolation = self.ui.enforce_interpolation.isChecked() self.target_widget.plot( - x_name=x_name, - y_name=y_name, - z_name=z_name, - x_entry=x_entry, - y_entry=y_entry, - z_entry=z_entry, + device_x=device_x, + device_y=device_y, + device_z=device_z, + signal_x=signal_x, + signal_y=signal_y, + signal_z=signal_z, color_map=color_map, validate_bec=validate_bec, interpolation=interpolation, @@ -147,17 +147,17 @@ def accept_changes(self): ) def cleanup(self): - self.ui.x_name.close() - self.ui.x_name.deleteLater() - self.ui.x_entry.close() - self.ui.x_entry.deleteLater() - self.ui.y_name.close() - self.ui.y_name.deleteLater() - self.ui.y_entry.close() - self.ui.y_entry.deleteLater() - self.ui.z_name.close() - self.ui.z_name.deleteLater() - self.ui.z_entry.close() - self.ui.z_entry.deleteLater() + self.ui.device_x.close() + self.ui.device_x.deleteLater() + self.ui.signal_x.close() + self.ui.signal_x.deleteLater() + self.ui.device_y.close() + self.ui.device_y.deleteLater() + self.ui.signal_y.close() + self.ui.signal_y.deleteLater() + self.ui.device_z.close() + self.ui.device_z.deleteLater() + self.ui.signal_z.close() + self.ui.signal_z.deleteLater() self.ui.interpolation.close() self.ui.interpolation.deleteLater() diff --git a/bec_widgets/widgets/plots/heatmap/settings/heatmap_settings_horizontal.ui b/bec_widgets/widgets/plots/heatmap/settings/heatmap_settings_horizontal.ui index 7fe057def..801f11367 100644 --- a/bec_widgets/widgets/plots/heatmap/settings/heatmap_settings_horizontal.ui +++ b/bec_widgets/widgets/plots/heatmap/settings/heatmap_settings_horizontal.ui @@ -196,7 +196,7 @@ - + true @@ -206,7 +206,7 @@ - + true @@ -236,7 +236,7 @@ - + true @@ -246,7 +246,7 @@ - + true @@ -276,7 +276,7 @@ - + true @@ -286,7 +286,7 @@ - + true @@ -322,21 +322,21 @@ - x_name - y_name - z_name - x_entry - y_entry - z_entry + device_x + device_y + device_z + signal_x + signal_y + signal_z interpolation oversampling_factor - x_name + device_x device_reset() - x_entry + signal_x reset_selection() @@ -350,9 +350,9 @@ - x_name + device_x currentTextChanged(QString) - x_entry + signal_x set_device(QString) @@ -366,9 +366,9 @@ - y_name + device_y device_reset() - y_entry + signal_y reset_selection() @@ -382,9 +382,9 @@ - y_name + device_y currentTextChanged(QString) - y_entry + signal_y set_device(QString) @@ -398,9 +398,9 @@ - z_name + device_z device_reset() - z_entry + signal_z reset_selection() @@ -414,9 +414,9 @@ - z_name + device_z currentTextChanged(QString) - z_entry + signal_z set_device(QString) diff --git a/bec_widgets/widgets/plots/heatmap/settings/heatmap_settings_vertical.ui b/bec_widgets/widgets/plots/heatmap/settings/heatmap_settings_vertical.ui index 2835306be..dce274f25 100644 --- a/bec_widgets/widgets/plots/heatmap/settings/heatmap_settings_vertical.ui +++ b/bec_widgets/widgets/plots/heatmap/settings/heatmap_settings_vertical.ui @@ -69,7 +69,7 @@ - + true @@ -79,7 +79,7 @@ - + true @@ -109,7 +109,7 @@ - + true @@ -119,7 +119,7 @@ - + true @@ -142,7 +142,7 @@ - + true @@ -152,7 +152,7 @@ - + true @@ -264,20 +264,20 @@ - x_name - y_name - z_name + device_x + device_y + device_z button_apply - x_entry - y_entry - z_entry + signal_x + signal_y + signal_z - x_name + device_x device_reset() - x_entry + signal_x reset_selection() @@ -291,9 +291,9 @@ - x_name + device_x currentTextChanged(QString) - x_entry + signal_x set_device(QString) @@ -307,9 +307,9 @@ - y_name + device_y device_reset() - y_entry + signal_y reset_selection() @@ -323,9 +323,9 @@ - y_name + device_y currentTextChanged(QString) - y_entry + signal_y set_device(QString) @@ -339,9 +339,9 @@ - z_name + device_z device_reset() - z_entry + signal_z reset_selection() @@ -355,9 +355,9 @@ - z_name + device_z currentTextChanged(QString) - z_entry + signal_z set_device(QString) diff --git a/bec_widgets/widgets/plots/image/image.py b/bec_widgets/widgets/plots/image/image.py index a8e9b3b16..1fdc010b0 100644 --- a/bec_widgets/widgets/plots/image/image.py +++ b/bec_widgets/widgets/plots/image/image.py @@ -42,8 +42,8 @@ class ImageConfig(ConnectionConfig): class ImageLayerConfig(BaseModel): - device_name: str = Field("", description="The device name to monitor.") - device_entry: str = Field("", description="The signal/entry name to monitor on the device.") + device: str = Field("", description="The device name to monitor.") + signal: str = Field("", description="The signal/entry name to monitor on the device.") monitor_type: Literal["1d", "2d"] | None = Field(None, description="The type of monitor.") source: Literal["device_monitor_1d", "device_monitor_2d"] | None = Field( None, description="The source of the image data." @@ -80,10 +80,10 @@ class Image(ImageBase): "autorange.setter", "autorange_mode", "autorange_mode.setter", - "device_name", - "device_name.setter", - "device_entry", - "device_entry.setter", + "device", + "device.setter", + "signal", + "signal.setter", "enable_colorbar", "enable_simple_colorbar", "enable_simple_colorbar.setter", @@ -206,19 +206,19 @@ def on_device_selection_changed(self, _): signal_text = device_selection.signal_combo_box.currentText() if not device: - self.device_name = "" + self.device = "" return if not device_selection.device_combo_box.is_valid_input: return if not device_selection.signal_combo_box.is_valid_input: - if self._config.device_entry: - self.device_entry = "" - if device != self._config.device_name: - self.device_name = device + if self._config.signal: + self.signal = "" + if device != self._config.device: + self.device = device return - if device == self._config.device_name and signal_text == self._config.device_entry: + if device == self._config.device and signal_text == self._config.signal: return # Get the signal config stored in the combobox @@ -235,8 +235,8 @@ def on_device_selection_changed(self, _): # Store signal config and set properties which will trigger the connection self._signal_configs["main"] = signal_config - self.device_name = device - self.device_entry = signal_text + self.device = device + self.signal = signal_text finally: self._device_selection_updating = False @@ -244,55 +244,53 @@ def on_device_selection_changed(self, _): # Data Acquisition @SafeProperty(str, auto_emit=True) - def device_name(self) -> str: + def device(self) -> str: """ The name of the device to monitor for image data. """ - return self._config.device_name + return self._config.device - @device_name.setter - def device_name(self, value: str): + @device.setter + def device(self, value: str): """ - Set the device name for the image. This should be used together with device_entry. - When both device_name and device_entry are set, the widget connects to that device signal. + Set the device name for the image. This should be used together with signal. + When both device and signal are set, the widget connects to that device signal. Args: value(str): The name of the device to monitor. """ if not value: # Clear the monitor if empty device name - if self._config.device_name: + if self._config.device: self._disconnect_current_monitor() - self._config.device_name = "" - self._config.device_entry = "" + self._config.device = "" + self._config.signal = "" self._signal_configs.pop("main", None) self._set_connection_status("disconnected") return - old_device = self._config.device_name - self._config.device_name = value + old_device = self._config.device + self._config.device = value - # If we have a device_entry, reconnect with the new device - if self._config.device_entry: + # If we have a signal, reconnect with the new device + if self._config.signal: # Try to get fresh signal config for the new device try: device_obj = self.dev[value] # Try to get signal config for the current entry - if self._config.device_entry in device_obj._info.get("signals", {}): - self._signal_configs["main"] = device_obj._info["signals"][ - self._config.device_entry - ] + if self._config.signal in device_obj._info.get("signals", {}): + self._signal_configs["main"] = device_obj._info["signals"][self._config.signal] self._setup_connection() else: # Signal doesn't exist on new device logger.warning( - f"Signal '{self._config.device_entry}' doesn't exist on device '{value}'" + f"Signal '{self._config.signal}' doesn't exist on device '{value}'" ) self._disconnect_current_monitor() - self._config.device_entry = "" + self._config.signal = "" self._signal_configs.pop("main", None) self._set_connection_status( - "error", f"Signal '{self._config.device_entry}' doesn't exist" + "error", f"Signal '{self._config.signal}' doesn't exist" ) except (KeyError, AttributeError): # Device doesn't exist @@ -304,40 +302,40 @@ def device_name(self, value: str): # Toolbar sync happens via SafeProperty auto_emit property_changed handling. @SafeProperty(str, auto_emit=True) - def device_entry(self) -> str: + def signal(self) -> str: """ The signal/entry name to monitor on the device. """ - return self._config.device_entry + return self._config.signal - @device_entry.setter - def device_entry(self, value: str): + @signal.setter + def signal(self, value: str): """ - Set the device entry (signal) for the image. This should be used together with device_name. + Set the device signal for the image. This should be used together with device. When set, it will connect to updates from that device signal. Args: value(str): The signal name to monitor. """ if not value: - if self._config.device_entry: + if self._config.signal: self._disconnect_current_monitor() - self._config.device_entry = "" + self._config.signal = "" self._signal_configs.pop("main", None) self._set_connection_status("disconnected") return - self._config.device_entry = value + self._config.signal = value - # If we have a device_name, try to connect - if self._config.device_name: + # If we have a device, try to connect + if self._config.device: try: - device_obj = self.dev[self._config.device_name] + device_obj = self.dev[self._config.device] signal_config = device_obj._info["signals"].get(value) if not isinstance(signal_config, dict) or not signal_config.get("signal_class"): logger.warning( f"Could not find valid configuration for signal '{value}' " - f"on device '{self._config.device_name}'." + f"on device '{self._config.device}'." ) self._signal_configs.pop("main", None) self._set_connection_status("error", f"Signal '{value}' not found") @@ -347,14 +345,14 @@ def device_entry(self, value: str): self._setup_connection() except (KeyError, AttributeError): logger.warning( - f"Could not find signal '{value}' on device '{self._config.device_name}'." + f"Could not find signal '{value}' on device '{self._config.device}'." ) # Remove signal config if it can't be fetched self._signal_configs.pop("main", None) self._set_connection_status("error", f"Signal '{value}' not found") else: - logger.debug(f"device_entry setter: No device set yet for signal '{value}'") + logger.debug(f"signal setter: No device set yet for signal '{value}'") @property def main_image(self) -> ImageItem: @@ -363,17 +361,17 @@ def main_image(self) -> ImageItem: def _setup_connection(self): """ - Internal method to setup connection based on current device_name, device_entry, and signal_config. + Internal method to setup connection based on current device, signal, and signal_config. """ - if not self._config.device_name or not self._config.device_entry: - logger.warning("Cannot setup connection without both device_name and device_entry") + if not self._config.device or not self._config.signal: + logger.warning("Cannot setup connection without both device and signal") self._set_connection_status("disconnected") return signal_config = self._signal_configs.get("main") if not signal_config: logger.warning( - f"Cannot setup connection for {self._config.device_name}.{self._config.device_entry} without signal_config" + f"Cannot setup connection for {self._config.device}.{self._config.signal} without signal_config" ) self._set_connection_status("error", "Missing signal config") return @@ -387,7 +385,7 @@ def _setup_connection(self): if signal_class not in supported_classes: logger.warning( - f"Signal '{self._config.device_name}.{self._config.device_entry}' has unsupported signal class '{signal_class}'. " + f"Signal '{self._config.device}.{self._config.signal}' has unsupported signal class '{signal_class}'. " f"Supported classes: {supported_classes}" ) self._set_connection_status("error", f"Unsupported signal class '{signal_class}'") @@ -399,7 +397,7 @@ def _setup_connection(self): if ndim is None: logger.warning( - f"Signal '{self._config.device_name}.{self._config.device_entry}' does not have a valid 'ndim' in its signal_info." + f"Signal '{self._config.device}.{self._config.signal}' does not have a valid 'ndim' in its signal_info." ) self._set_connection_status("error", "Missing ndim in signal_info") return @@ -414,14 +412,12 @@ def _setup_connection(self): if signal_class == "PreviewSignal": self.bec_dispatcher.connect_slot( self.on_image_update_1d, - MessageEndpoints.device_preview( - self._config.device_name, self._config.device_entry - ), + MessageEndpoints.device_preview(self._config.device, self._config.signal), ) elif signal_class in self.SUPPORTED_SIGNALS: self.async_update = True config.async_signal_name = signal_config.get( - "obj_name", f"{self._config.device_name}_{self._config.device_entry}" + "obj_name", f"{self._config.device}_{self._config.signal}" ) self._setup_async_image(self.scan_id) elif ndim == 2: @@ -430,26 +426,24 @@ def _setup_connection(self): if signal_class == "PreviewSignal": self.bec_dispatcher.connect_slot( self.on_image_update_2d, - MessageEndpoints.device_preview( - self._config.device_name, self._config.device_entry - ), + MessageEndpoints.device_preview(self._config.device, self._config.signal), ) elif signal_class in self.SUPPORTED_SIGNALS: self.async_update = True config.async_signal_name = signal_config.get( - "obj_name", f"{self._config.device_name}_{self._config.device_entry}" + "obj_name", f"{self._config.device}_{self._config.signal}" ) self._setup_async_image(self.scan_id) else: logger.warning( - f"Unsupported ndim '{ndim}' for monitor '{self._config.device_name}.{self._config.device_entry}'." + f"Unsupported ndim '{ndim}' for monitor '{self._config.device}.{self._config.signal}'." ) self._set_connection_status("error", f"Unsupported ndim '{ndim}'") return self._set_connection_status("connected") logger.info( - f"Connected to {self._config.device_name}.{self._config.device_entry} with type {config.monitor_type}" + f"Connected to {self._config.device}.{self._config.signal} with type {config.monitor_type}" ) self._autorange_on_next_update = True @@ -457,13 +451,13 @@ def _disconnect_current_monitor(self): """ Internal method to disconnect the current monitor subscriptions. """ - if not self._config.device_name or not self._config.device_entry: + if not self._config.device or not self._config.signal: return config = self.subscriptions["main"] if self.async_update: - async_signal_name = config.async_signal_name or self._config.device_entry + async_signal_name = config.async_signal_name or self._config.signal ids_to_check = [self.scan_id, self.old_scan_id] if config.source == "device_monitor_1d": @@ -473,11 +467,11 @@ def _disconnect_current_monitor(self): self.bec_dispatcher.disconnect_slot( self.on_image_update_1d, MessageEndpoints.device_async_signal( - scan_id, self._config.device_name, async_signal_name + scan_id, self._config.device, async_signal_name ), ) logger.info( - f"Disconnecting 1d update ScanID:{scan_id}, Device Name:{self._config.device_name},Device Entry:{async_signal_name}" + f"Disconnecting 1d update ScanID:{scan_id}, Device Name:{self._config.device},Device Entry:{async_signal_name}" ) elif config.source == "device_monitor_2d": for scan_id in ids_to_check: @@ -486,33 +480,29 @@ def _disconnect_current_monitor(self): self.bec_dispatcher.disconnect_slot( self.on_image_update_2d, MessageEndpoints.device_async_signal( - scan_id, self._config.device_name, async_signal_name + scan_id, self._config.device, async_signal_name ), ) logger.info( - f"Disconnecting 2d update ScanID:{scan_id}, Device Name:{self._config.device_name},Device Entry:{async_signal_name}" + f"Disconnecting 2d update ScanID:{scan_id}, Device Name:{self._config.device},Device Entry:{async_signal_name}" ) else: if config.source == "device_monitor_1d": self.bec_dispatcher.disconnect_slot( self.on_image_update_1d, - MessageEndpoints.device_preview( - self._config.device_name, self._config.device_entry - ), + MessageEndpoints.device_preview(self._config.device, self._config.signal), ) logger.info( - f"Disconnecting preview 1d update Device Name:{self._config.device_name}, Device Entry:{self._config.device_entry}" + f"Disconnecting preview 1d update Device Name:{self._config.device}, Device Entry:{self._config.signal}" ) elif config.source == "device_monitor_2d": self.bec_dispatcher.disconnect_slot( self.on_image_update_2d, - MessageEndpoints.device_preview( - self._config.device_name, self._config.device_entry - ), + MessageEndpoints.device_preview(self._config.device, self._config.signal), ) logger.info( - f"Disconnecting preview 2d update Device Name:{self._config.device_name}, Device Entry:{self._config.device_entry}" + f"Disconnecting preview 2d update Device Name:{self._config.device}, Device Entry:{self._config.signal}" ) # Reset async state @@ -526,8 +516,8 @@ def _disconnect_current_monitor(self): @SafeSlot(popup_error=True) def image( self, - device_name: str | None = None, - device_entry: str | None = None, + device: str | None = None, + signal: str | None = None, color_map: str | None = None, color_bar: Literal["simple", "full"] | None = None, vrange: tuple[int, int] | None = None, @@ -536,8 +526,8 @@ def image( Set the image source and update the image. Args: - device_name(str|None): The name of the device to monitor. If None or empty string, the current monitor will be disconnected. - device_entry(str|None): The signal/entry name to monitor on the device. + device(str|None): The name of the device to monitor. If None or empty string, the current monitor will be disconnected. + signal(str|None): The signal/entry name to monitor on the device. color_map(str): The color map to use for the image. color_bar(str): The type of color bar to use. Options are "simple" or "full". vrange(tuple): The range of values to use for the color map. @@ -546,27 +536,27 @@ def image( ImageItem: The image object, or None if connection failed. """ # Disconnect existing monitor if any - if self._config.device_name and self._config.device_entry: + if self._config.device and self._config.signal: self._disconnect_current_monitor() - if not device_name or not device_entry: - if device_name or device_entry: - logger.warning("Both device_name and device_entry must be specified") + if not device or not signal: + if device or signal: + logger.warning("Both device and signal must be specified") else: logger.info("Disconnecting image monitor") - self.device_name = "" + self.device = "" return None # Validate device - self.entry_validator.validate_monitor(device_name) + self.entry_validator.validate_monitor(device) # Clear old entry first to avoid reconnect attempts on the new device - if self._config.device_entry: - self.device_entry = "" + if self._config.signal: + self.signal = "" # Set properties to trigger connection - self.device_name = device_name - self.device_entry = device_entry + self.device = device + self.signal = signal # Apply visual settings if color_map is not None: @@ -581,7 +571,7 @@ def image( def _sync_device_selection(self): """ Synchronize the device and signal comboboxes with the current monitor state. - This ensures the toolbar reflects the device_name and device_entry properties. + This ensures the toolbar reflects the device and signal properties. """ try: device_selection_action = self.toolbar.components.get_action("device_selection") @@ -593,8 +583,8 @@ def _sync_device_selection(self): return device_selection: DeviceSelection = device_selection_action.widget - target_device = self._config.device_name or "" - target_entry = self._config.device_entry or "" + target_device = self._config.device or "" + target_entry = self._config.signal or "" # Check if already synced if ( @@ -605,15 +595,15 @@ def _sync_device_selection(self): device_selection.set_device_and_signal(target_device, target_entry) - def _sync_device_entry_from_toolbar(self) -> None: + def _sync_signal_from_toolbar(self) -> None: """ - Pull the signal selection from the toolbar if it differs from the current device_entry. - This keeps CLI-driven device_name updates in sync with the signal combobox state. + Pull the signal selection from the toolbar if it differs from the current signal. + This keeps CLI-driven device updates in sync with the signal combobox state. """ if self._device_selection_updating: return - if not self._config.device_name: + if not self._config.device: return try: @@ -625,17 +615,17 @@ def _sync_device_entry_from_toolbar(self) -> None: return device_selection: DeviceSelection = device_selection_action.widget - if device_selection.device_combo_box.currentText() != self._config.device_name: + if device_selection.device_combo_box.currentText() != self._config.device: return signal_text = device_selection.signal_combo_box.currentText() - if not signal_text or signal_text == self._config.device_entry: + if not signal_text or signal_text == self._config.signal: return signal_config = device_selection.signal_combo_box.get_signal_config() if not signal_config: try: - device_obj = self.dev[self._config.device_name] + device_obj = self.dev[self._config.device] signal_config = device_obj._info["signals"].get(signal_text, {}) except (KeyError, AttributeError): signal_config = None @@ -646,7 +636,7 @@ def _sync_device_entry_from_toolbar(self) -> None: self._signal_configs["main"] = signal_config self._device_selection_updating = True try: - self.device_entry = signal_text + self.signal = signal_text finally: self._device_selection_updating = False @@ -795,17 +785,17 @@ def _handle_scan_change(self, current_scan_id: str): def _get_async_signal_name(self) -> tuple[str, str] | None: """ - Returns device name and async signal name used for endpoints/messages. + Returns device and async signal names used for endpoints/messages. Returns: - tuple[str, str] | None: (device_name, async_signal_name) or None if not available. + tuple[str, str] | None: (device, async_signal_name) or None if not available. """ - if not self._config.device_name or not self._config.device_entry: + if not self._config.device or not self._config.signal: return None config = self.subscriptions["main"] - async_signal = config.async_signal_name or self._config.device_entry - return self._config.device_name, async_signal + async_signal = config.async_signal_name or self._config.signal + return self._config.device, async_signal def _setup_async_image(self, scan_id: str | None): """ @@ -823,7 +813,7 @@ def _setup_async_image(self, scan_id: str | None): logger.info("Async image setup skipped because monitor information is incomplete.") return - device_name, async_signal = async_names + device, async_signal = async_names if config.monitor_type == "1d": slot = self.on_image_update_1d elif config.monitor_type == "2d": @@ -839,7 +829,7 @@ def _setup_async_image(self, scan_id: str | None): if prev_scan_id is None: continue self.bec_dispatcher.disconnect_slot( - slot, MessageEndpoints.device_async_signal(prev_scan_id, device_name, async_signal) + slot, MessageEndpoints.device_async_signal(prev_scan_id, device, async_signal) ) if scan_id is None: @@ -848,26 +838,26 @@ def _setup_async_image(self, scan_id: str | None): self.bec_dispatcher.connect_slot( slot, - MessageEndpoints.device_async_signal(scan_id, device_name, async_signal), + MessageEndpoints.device_async_signal(scan_id, device, async_signal), from_start=True, cb_info={"scan_id": scan_id}, ) - logger.info(f"Setup async image for {device_name}.{async_signal} and scan {scan_id}.") + logger.info(f"Setup async image for {device}.{async_signal} and scan {scan_id}.") - def disconnect_monitor(self, device_name: str | None = None, device_entry: str | None = None): + def disconnect_monitor(self, device: str | None = None, signal: str | None = None): """ Disconnect the monitor from the image update signals, both 1D and 2D. Args: - device_name(str|None): The name of the device to disconnect. Defaults to current device. - device_entry(str|None): The signal/entry name to disconnect. Defaults to current entry. + device(str|None): The name of the device to disconnect. Defaults to current device. + signal(str|None): The signal/entry name to disconnect. Defaults to current signal. """ config = self.subscriptions["main"] - target_device = device_name or self._config.device_name - target_entry = device_entry or self._config.device_entry + target_device = device or self._config.device + target_entry = signal or self._config.signal if not target_device or not target_entry: - logger.warning("Cannot disconnect monitor without both device_name and device_entry") + logger.warning("Cannot disconnect monitor without both device and signal") return if self.async_update: @@ -1045,10 +1035,10 @@ def _on_layer_removed(self, layer_name: str): if layer_name not in self.subscriptions: return # For the main layer, disconnect current monitor - if layer_name == "main" and self._config.device_name and self._config.device_entry: + if layer_name == "main" and self._config.device and self._config.signal: self._disconnect_current_monitor() - self._config.device_name = "" - self._config.device_entry = "" + self._config.device = "" + self._config.signal = "" self._signal_configs.pop("main", None) def cleanup(self): @@ -1058,7 +1048,7 @@ def cleanup(self): self.layer_removed.disconnect(self._on_layer_removed) # Disconnect current monitor - if self._config.device_name and self._config.device_entry: + if self._config.device and self._config.signal: self._disconnect_current_monitor() self.subscriptions.clear() diff --git a/bec_widgets/widgets/plots/image/toolbar_components/device_selection.py b/bec_widgets/widgets/plots/image/toolbar_components/device_selection.py index caef8657a..b9746f530 100644 --- a/bec_widgets/widgets/plots/image/toolbar_components/device_selection.py +++ b/bec_widgets/widgets/plots/image/toolbar_components/device_selection.py @@ -64,32 +64,32 @@ def __init__(self, parent=None, client=None): layout.addWidget(self.device_combo_box, stretch=1) layout.addWidget(self.signal_combo_box, stretch=1) - def set_device_and_signal(self, device_name: str | None, device_entry: str | None) -> None: + def set_device_and_signal(self, device: str | None, signal: str | None) -> None: """Set the displayed device and signal without emitting selection signals.""" - device_name = device_name or "" - device_entry = device_entry or "" + device = device or "" + signal = signal or "" self.device_combo_box.blockSignals(True) self.signal_combo_box.blockSignals(True) try: - if device_name: + if device: # Set device in device_combo_box - index = self.device_combo_box.findText(device_name) + index = self.device_combo_box.findText(device) if index >= 0: self.device_combo_box.setCurrentIndex(index) else: # Device not found in list, but still set it - self.device_combo_box.setCurrentText(device_name) + self.device_combo_box.setCurrentText(device) # Only update signal combobox device filter if it's actually changing # This prevents redundant repopulation which can cause duplicates !!!! current_device = getattr(self.signal_combo_box, "_device", None) - if current_device != device_name: - self.signal_combo_box.set_device(device_name) + if current_device != device: + self.signal_combo_box.set_device(device) # Sync signal combobox selection - if device_entry: + if signal: # Try to find the signal by component_name (which is what's displayed) found = False for i in range(self.signal_combo_box.count()): @@ -99,14 +99,14 @@ def set_device_and_signal(self, device_name: str | None, device_entry: str | Non # Check if this matches our signal if config_data: component_name = config_data.get("component_name", "") - if text == component_name or text == device_entry: + if text == component_name or text == signal: self.signal_combo_box.setCurrentIndex(i) found = True break if not found: - # Fallback: try to match the device_entry directly - index = self.signal_combo_box.findText(device_entry) + # Fallback: try to match the signal directly + index = self.signal_combo_box.findText(signal) if index >= 0: self.signal_combo_box.setCurrentIndex(index) else: @@ -187,8 +187,8 @@ def __init__(self, components: ToolbarComponents, target_widget=None): self.components = components self.target_widget = target_widget self._connected = False - self.register_property_sync("device_name", self._sync_from_device_name) - self.register_property_sync("device_entry", self._sync_from_device_entry) + self.register_property_sync("device", self._sync_from_device) + self.register_property_sync("signal", self._sync_from_signal) self.register_property_sync("connection_status", self._sync_connection_status) self.register_property_sync("connection_error", self._sync_connection_status) @@ -222,26 +222,22 @@ def disconnect(self): self._connected = False widget.cleanup() - def _sync_from_device_name(self, _): + def _sync_from_device(self, _): try: widget = self._widget() except Exception: return - widget.set_device_and_signal( - self.target_widget.device_name, self.target_widget.device_entry - ) - self.target_widget._sync_device_entry_from_toolbar() + widget.set_device_and_signal(self.target_widget.device, self.target_widget.signal) + self.target_widget._sync_signal_from_toolbar() - def _sync_from_device_entry(self, _): + def _sync_from_signal(self, _): try: widget = self._widget() except Exception: return - widget.set_device_and_signal( - self.target_widget.device_name, self.target_widget.device_entry - ) + widget.set_device_and_signal(self.target_widget.device, self.target_widget.signal) def _sync_connection_status(self, _): try: diff --git a/bec_widgets/widgets/plots/motor_map/motor_map.py b/bec_widgets/widgets/plots/motor_map/motor_map.py index 7073bedc4..d2f014866 100644 --- a/bec_widgets/widgets/plots/motor_map/motor_map.py +++ b/bec_widgets/widgets/plots/motor_map/motor_map.py @@ -48,14 +48,14 @@ def paint(self, painter, *args): class MotorConfig(BaseModel): - name: str | None = Field(None, description="Motor name.") + device: str | None = Field(None, description="Motor name.") limits: list[float] | None = Field(None, description="Motor limits.") # noinspection PyDataclass class MotorMapConfig(ConnectionConfig): - x_motor: MotorConfig = Field(default_factory=MotorConfig, description="Motor X name.") - y_motor: MotorConfig = Field(default_factory=MotorConfig, description="Motor Y name.") + device_x: MotorConfig = Field(default_factory=MotorConfig, description="Motor X name.") + device_y: MotorConfig = Field(default_factory=MotorConfig, description="Motor Y name.") color: str | tuple | None = Field( (255, 255, 255, 255), description="The color of the last point of current position." ) @@ -109,10 +109,10 @@ class MotorMap(PlotBase): "map", "reset_history", "get_data", - "x_motor", - "x_motor.setter", - "y_motor", - "y_motor.setter", + "device_x", + "device_x.setter", + "device_y", + "device_y.setter", ] update_signal = Signal() @@ -208,7 +208,7 @@ def on_motor_selection_changed(self, _): return if motor_x != "" and motor_y != "": - if motor_x != self.config.x_motor.name or motor_y != self.config.y_motor.name: + if motor_x != self.config.device_x.device or motor_y != self.config.device_y.device: self.map(motor_x, motor_y) def _add_motor_map_settings(self): @@ -259,32 +259,32 @@ def _motor_map_settings_closed(self): ################################################################################ @SafeProperty(str) - def x_motor(self) -> str: + def device_x(self) -> str: """Name of the motor shown on the X axis.""" - return self.config.x_motor.name or "" + return self.config.device_x.device or "" - @x_motor.setter - def x_motor(self, motor_name: str) -> None: + @device_x.setter + def device_x(self, motor_name: str) -> None: motor_name = motor_name or "" - if motor_name == (self.config.x_motor.name or ""): + if motor_name == (self.config.device_x.device or ""): return - if motor_name and self.y_motor: - self.map(motor_name, self.y_motor, suppress_errors=True) + if motor_name and self.device_y: + self.map(motor_name, self.device_y, suppress_errors=True) return self._set_motor_name(axis="x", motor_name=motor_name) @SafeProperty(str) - def y_motor(self) -> str: + def device_y(self) -> str: """Name of the motor shown on the Y axis.""" - return self.config.y_motor.name or "" + return self.config.device_y.device or "" - @y_motor.setter - def y_motor(self, motor_name: str) -> None: + @device_y.setter + def device_y(self, motor_name: str) -> None: motor_name = motor_name or "" - if motor_name == (self.config.y_motor.name or ""): + if motor_name == (self.config.device_y.device or ""): return - if motor_name and self.x_motor: - self.map(self.x_motor, motor_name, suppress_errors=True) + if motor_name and self.device_x: + self.map(self.device_x, motor_name, suppress_errors=True) return self._set_motor_name(axis="y", motor_name=motor_name) @@ -452,13 +452,13 @@ def _set_motor_name(self, axis: str, motor_name: str, *, sync_toolbar: bool = Tr Update stored motor name for given axis and optionally refresh the toolbar selection. """ motor_name = motor_name or "" - motor_config = self.config.x_motor if axis == "x" else self.config.y_motor + motor_config = self.config.device_x if axis == "x" else self.config.device_y - if motor_config.name == motor_name: + if motor_config.device == motor_name: return - motor_config.name = motor_name - self.property_changed.emit(f"{axis}_motor", motor_name) + motor_config.device = motor_name + self.property_changed.emit(f"device_{axis}", motor_name) if sync_toolbar: self._sync_motor_map_selection_toolbar() @@ -468,14 +468,14 @@ def _set_motor_name(self, axis: str, motor_name: str, *, sync_toolbar: bool = Tr ################################################################################ @SafeSlot() def map( - self, x_name: str, y_name: str, validate_bec: bool = True, suppress_errors=False + self, device_x: str, device_y: str, validate_bec: bool = True, suppress_errors=False ) -> None: """ Set the x and y motor names. Args: - x_name(str): The name of the x motor. - y_name(str): The name of the y motor. + device_x(str): The name of the x motor. + device_y(str): The name of the y motor. validate_bec(bool, optional): If True, validate the signal with BEC. Defaults to True. suppress_errors(bool, optional): If True, suppress errors during validation. Defaults to False. Used for properties setting. If the validation fails, the changes are not applied. """ @@ -484,22 +484,22 @@ def map( if validate_bec: if suppress_errors: try: - self.entry_validator.validate_signal(x_name, None) - self.entry_validator.validate_signal(y_name, None) + self.entry_validator.validate_signal(device_x, None) + self.entry_validator.validate_signal(device_y, None) except Exception: return else: - self.entry_validator.validate_signal(x_name, None) - self.entry_validator.validate_signal(y_name, None) + self.entry_validator.validate_signal(device_x, None) + self.entry_validator.validate_signal(device_y, None) - self._set_motor_name(axis="x", motor_name=x_name, sync_toolbar=False) - self._set_motor_name(axis="y", motor_name=y_name, sync_toolbar=False) + self._set_motor_name(axis="x", motor_name=device_x, sync_toolbar=False) + self._set_motor_name(axis="y", motor_name=device_y, sync_toolbar=False) - motor_x_limit = self._get_motor_limit(self.config.x_motor.name) - motor_y_limit = self._get_motor_limit(self.config.y_motor.name) + motor_x_limit = self._get_motor_limit(self.config.device_x.device) + motor_y_limit = self._get_motor_limit(self.config.device_y.device) - self.config.x_motor.limits = motor_x_limit - self.config.y_motor.limits = motor_y_limit + self.config.device_x.limits = motor_x_limit + self.config.device_y.limits = motor_y_limit # reconnect the signals self._connect_motor_to_slots() @@ -574,19 +574,19 @@ def on_device_readback(self, msg: dict, metadata: dict) -> None: msg(dict): Message from the device readback. metadata(dict): Metadata of the message. """ - x_motor = self.config.x_motor.name - y_motor = self.config.y_motor.name + device_x = self.config.device_x.device + device_y = self.config.device_y.device - if x_motor is None or y_motor is None: + if device_x is None or device_y is None: return - if x_motor in msg["signals"]: - x = msg["signals"][x_motor]["value"] + if device_x in msg["signals"]: + x = msg["signals"][device_x]["value"] self._buffer["x"].append(x) self._buffer["y"].append(self._buffer["y"][-1]) - elif y_motor in msg["signals"]: - y = msg["signals"][y_motor]["value"] + elif device_y in msg["signals"]: + y = msg["signals"][device_y]["value"] self._buffer["y"].append(y) self._buffer["x"].append(self._buffer["x"][-1]) @@ -597,12 +597,12 @@ def _connect_motor_to_slots(self): self._disconnect_current_motors() endpoints_readback = [ - MessageEndpoints.device_readback(self.config.x_motor.name), - MessageEndpoints.device_readback(self.config.y_motor.name), + MessageEndpoints.device_readback(self.config.device_x.device), + MessageEndpoints.device_readback(self.config.device_y.device), ] endpoints_limits = [ - MessageEndpoints.device_limits(self.config.x_motor.name), - MessageEndpoints.device_limits(self.config.y_motor.name), + MessageEndpoints.device_limits(self.config.device_x.device), + MessageEndpoints.device_limits(self.config.device_y.device), ] self.bec_dispatcher.connect_slot(self.on_device_readback, endpoints_readback) @@ -610,14 +610,14 @@ def _connect_motor_to_slots(self): def _disconnect_current_motors(self): """Disconnect the current motors from the slots.""" - if self.config.x_motor.name is not None and self.config.y_motor.name is not None: + if self.config.device_x.device is not None and self.config.device_y.device is not None: endpoints_readback = [ - MessageEndpoints.device_readback(self.config.x_motor.name), - MessageEndpoints.device_readback(self.config.y_motor.name), + MessageEndpoints.device_readback(self.config.device_x.device), + MessageEndpoints.device_readback(self.config.device_y.device), ] endpoints_limits = [ - MessageEndpoints.device_limits(self.config.x_motor.name), - MessageEndpoints.device_limits(self.config.y_motor.name), + MessageEndpoints.device_limits(self.config.device_x.device), + MessageEndpoints.device_limits(self.config.device_y.device), ] self.bec_dispatcher.disconnect_slot(self.on_device_readback, endpoints_readback) self.bec_dispatcher.disconnect_slot(self.on_device_limits, endpoints_limits) @@ -634,8 +634,8 @@ def on_device_limits(self, msg: dict, metadata: dict) -> None: msg(dict): Message from the device limits. metadata(dict): Metadata of the message. """ - self.config.x_motor.limits = self._get_motor_limit(self.config.x_motor.name) - self.config.y_motor.limits = self._get_motor_limit(self.config.y_motor.name) + self.config.device_x.limits = self._get_motor_limit(self.config.device_x.device) + self.config.device_y.limits = self._get_motor_limit(self.config.device_y.device) self._swap_limit_map() def _get_motor_limit(self, motor: str) -> list | None: @@ -663,8 +663,8 @@ def _make_motor_map(self) -> None: Make the motor map. """ - motor_x_limit = self.config.x_motor.limits - motor_y_limit = self.config.y_motor.limits + motor_x_limit = self.config.device_x.limits + motor_y_limit = self.config.device_y.limits self._limit_map = self._make_limit_map(motor_x_limit, motor_y_limit) self.plot_item.addItem(self._limit_map) @@ -678,10 +678,10 @@ def _make_motor_map(self) -> None: # Add the crosshair for initial motor coordinates initial_position_x = self._get_motor_init_position( - self.config.x_motor.name, self.config.precision + self.config.device_x.device, self.config.precision ) initial_position_y = self._get_motor_init_position( - self.config.y_motor.name, self.config.precision + self.config.device_y.device, self.config.precision ) self._buffer["x"] = [initial_position_x] @@ -693,8 +693,8 @@ def _make_motor_map(self) -> None: self._add_coordinates_crosshair(initial_position_x, initial_position_y) # Set default labels for the plot - self.set_x_label_suffix(f"[{self.config.x_motor.name}-{self.config.x_motor.name}]") - self.set_y_label_suffix(f"[{self.config.y_motor.name}-{self.config.y_motor.name}]") + self.set_x_label_suffix(f"[{self.config.device_x.device}-{self.config.device_x.device}]") + self.set_y_label_suffix(f"[{self.config.device_y.device}-{self.config.device_y.device}]") self.update_signal.emit() @@ -794,8 +794,8 @@ def fix_limit_pair(limits): def _swap_limit_map(self): """Swap the limit map.""" self.plot_item.removeItem(self._limit_map) - x_limits = self.config.x_motor.limits - y_limits = self.config.y_motor.limits + x_limits = self.config.device_x.limits + y_limits = self.config.device_y.limits if x_limits is not None and y_limits is not None: self._limit_map = self._make_limit_map(x_limits, y_limits) self._limit_map.setZValue(-1) @@ -828,8 +828,8 @@ def _sync_motor_map_selection_toolbar(self): if motor_selection_action is None: return motor_selection: MotorSelection = motor_selection_action.widget - target_x = self.config.x_motor.name or "" - target_y = self.config.y_motor.name or "" + target_x = self.config.device_x.device or "" + target_y = self.config.device_y.device or "" if ( motor_selection.motor_x.currentText() == target_x @@ -864,10 +864,10 @@ def __init__(self): self.setCentralWidget(self.main_widget) self.motor_map_popup = MotorMap(popups=True) - self.motor_map_popup.map(x_name="samx", y_name="samy", validate_bec=True) + self.motor_map_popup.map(device_x="samx", device_y="samy", validate_bec=True) self.motor_map_side = MotorMap(popups=False) - self.motor_map_side.map(x_name="samx", y_name="samy", validate_bec=True) + self.motor_map_side.map(device_x="samx", device_y="samy", validate_bec=True) self.layout.addWidget(self.motor_map_side) self.layout.addWidget(self.motor_map_popup) diff --git a/bec_widgets/widgets/plots/scatter_waveform/scatter_curve.py b/bec_widgets/widgets/plots/scatter_waveform/scatter_curve.py index bd12e6487..4624e50cb 100644 --- a/bec_widgets/widgets/plots/scatter_waveform/scatter_curve.py +++ b/bec_widgets/widgets/plots/scatter_waveform/scatter_curve.py @@ -20,8 +20,8 @@ class ScatterDeviceSignal(BaseModel): """The configuration of a signal in the scatter waveform widget.""" - name: str - entry: str + device: str + signal: str model_config: dict = {"validate_assignment": True} @@ -40,13 +40,13 @@ class ScatterCurveConfig(ConnectionConfig): color_map: str | None = Field( "plasma", description="The color palette of the figure widget.", validate_default=True ) - x_device: ScatterDeviceSignal | None = Field( + device_x: ScatterDeviceSignal | None = Field( None, description="The x device signal of the scatter waveform." ) - y_device: ScatterDeviceSignal | None = Field( + device_y: ScatterDeviceSignal | None = Field( None, description="The y device signal of the scatter waveform." ) - z_device: ScatterDeviceSignal | None = Field( + device_z: ScatterDeviceSignal | None = Field( None, description="The z device signal of the scatter waveform." ) diff --git a/bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.py b/bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.py index 48a20f147..94fb063f7 100644 --- a/bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.py +++ b/bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.py @@ -49,18 +49,18 @@ class ScatterWaveform(PlotBase): "update_with_scan_history", "clear_all", # Device properties - "x_device_name", - "x_device_name.setter", - "x_device_entry", - "x_device_entry.setter", - "y_device_name", - "y_device_name.setter", - "y_device_entry", - "y_device_entry.setter", - "z_device_name", - "z_device_name.setter", - "z_device_entry", - "z_device_entry.setter", + "device_x", + "device_x.setter", + "signal_x", + "signal_x.setter", + "device_y", + "device_y.setter", + "signal_y", + "signal_y.setter", + "device_z", + "device_z.setter", + "signal_z", + "signal_z.setter", ] sync_signal_update = Signal() @@ -208,12 +208,12 @@ def color_map(self, value: str): @SafeSlot(popup_error=True) def plot( self, - x_name: str, - y_name: str, - z_name: str, - x_entry: None | str = None, - y_entry: None | str = None, - z_entry: None | str = None, + device_x: str, + device_y: str, + device_z: str, + signal_x: None | str = None, + signal_y: None | str = None, + signal_z: None | str = None, color_map: str | None = "plasma", label: str | None = None, validate_bec: bool = True, @@ -222,12 +222,12 @@ def plot( Plot the data from the device signals. Args: - x_name (str): The name of the x device signal. - y_name (str): The name of the y device signal. - z_name (str): The name of the z device signal. - x_entry (None | str): The x entry of the device signal. - y_entry (None | str): The y entry of the device signal. - z_entry (None | str): The z entry of the device signal. + device_x (str): The name of the x device signal. + device_y (str): The name of the y device signal. + device_z (str): The name of the z device signal. + signal_x (None | str): The x entry of the device signal. + signal_y (None | str): The y entry of the device signal. + signal_z (None | str): The z entry of the device signal. color_map (str | None): The color map of the scatter waveform. label (str | None): The label of the curve. validate_bec (bool): Whether to validate the device signals with current BEC instance. @@ -237,9 +237,9 @@ def plot( """ if validate_bec: - x_entry = self.entry_validator.validate_signal(x_name, x_entry) - y_entry = self.entry_validator.validate_signal(y_name, y_entry) - z_entry = self.entry_validator.validate_signal(z_name, z_entry) + signal_x = self.entry_validator.validate_signal(device_x, signal_x) + signal_y = self.entry_validator.validate_signal(device_y, signal_y) + signal_z = self.entry_validator.validate_signal(device_z, signal_z) if color_map is not None: try: @@ -250,15 +250,15 @@ def plot( ) if label is None: - label = f"{z_name}-{z_entry}" + label = f"{device_z}-{signal_z}" config = ScatterCurveConfig( parent_id=self.gui_id, label=label, color_map=color_map, - x_device=ScatterDeviceSignal(name=x_name, entry=x_entry), - y_device=ScatterDeviceSignal(name=y_name, entry=y_entry), - z_device=ScatterDeviceSignal(name=z_name, entry=z_entry), + device_x=ScatterDeviceSignal(device=device_x, signal=signal_x), + device_y=ScatterDeviceSignal(device=device_y, signal=signal_y), + device_z=ScatterDeviceSignal(device=device_z, signal=signal_z), ) # Add Curve @@ -350,23 +350,23 @@ def update_sync_curves(self, _=None): return "none" try: - x_name = self._main_curve.config.x_device.name - x_entry = self._main_curve.config.x_device.entry - y_name = self._main_curve.config.y_device.name - y_entry = self._main_curve.config.y_device.entry - z_name = self._main_curve.config.z_device.name - z_entry = self._main_curve.config.z_device.entry + device_x = self._main_curve.config.device_x.device + signal_x = self._main_curve.config.device_x.signal + device_y = self._main_curve.config.device_y.device + signal_y = self._main_curve.config.device_y.signal + device_z = self._main_curve.config.device_z.device + signal_z = self._main_curve.config.device_z.signal except AttributeError: return if access_key == "val": - x_data = data.get(x_name, {}).get(x_entry, {}).get(access_key, None) - y_data = data.get(y_name, {}).get(y_entry, {}).get(access_key, None) - z_data = data.get(z_name, {}).get(z_entry, {}).get(access_key, None) + x_data = data.get(device_x, {}).get(signal_x, {}).get(access_key, None) + y_data = data.get(device_y, {}).get(signal_y, {}).get(access_key, None) + z_data = data.get(device_z, {}).get(signal_z, {}).get(access_key, None) else: - x_data = data.get(x_name, {}).get(x_entry, {}).read().get("value", None) - y_data = data.get(y_name, {}).get(y_entry, {}).read().get("value", None) - z_data = data.get(z_name, {}).get(z_entry, {}).read().get("value", None) + x_data = data.get(device_x, {}).get(signal_x, {}).read().get("value", None) + y_data = data.get(device_y, {}).get(signal_y, {}).read().get("value", None) + z_data = data.get(device_z, {}).get(signal_z, {}).read().get("value", None) self._main_curve.set_data(x=x_data, y=y_data, z=z_data) @@ -399,14 +399,14 @@ def _fetch_scan_data_and_access(self): ################################################################################ @SafeProperty(str) - def x_device_name(self) -> str: + def device_x(self) -> str: """Device name for the X axis.""" - if self._main_curve is None or self._main_curve.config.x_device is None: + if self._main_curve is None or self._main_curve.config.device_x is None: return "" - return self._main_curve.config.x_device.name or "" + return self._main_curve.config.device_x.device or "" - @x_device_name.setter - def x_device_name(self, device_name: str) -> None: + @device_x.setter + def device_x(self, device_name: str) -> None: """ Set the X device name. @@ -419,33 +419,33 @@ def x_device_name(self, device_name: str) -> None: try: entry = self.entry_validator.validate_signal(device_name, None) # Update or create config - if self._main_curve.config.x_device is None: - self._main_curve.config.x_device = ScatterDeviceSignal( - name=device_name, entry=entry + if self._main_curve.config.device_x is None: + self._main_curve.config.device_x = ScatterDeviceSignal( + device=device_name, signal=entry ) else: - self._main_curve.config.x_device.name = device_name - self._main_curve.config.x_device.entry = entry - self.property_changed.emit("x_device_name", device_name) + self._main_curve.config.device_x.device = device_name + self._main_curve.config.device_x.signal = entry + self.property_changed.emit("device_x", device_name) self.update_labels() self._try_auto_plot() except Exception: pass # Silently fail if device is not available yet else: - if self._main_curve.config.x_device is not None: - self._main_curve.config.x_device = None - self.property_changed.emit("x_device_name", "") + if self._main_curve.config.device_x is not None: + self._main_curve.config.device_x = None + self.property_changed.emit("device_x", "") self.update_labels() @SafeProperty(str) - def x_device_entry(self) -> str: + def signal_x(self) -> str: """Signal entry for the X axis device.""" - if self._main_curve is None or self._main_curve.config.x_device is None: + if self._main_curve is None or self._main_curve.config.device_x is None: return "" - return self._main_curve.config.x_device.entry or "" + return self._main_curve.config.device_x.signal or "" - @x_device_entry.setter - def x_device_entry(self, entry: str) -> None: + @signal_x.setter + def signal_x(self, entry: str) -> None: """ Set the X device entry. @@ -455,29 +455,29 @@ def x_device_entry(self, entry: str) -> None: if not entry: return - if self._main_curve.config.x_device is None: - logger.warning("Cannot set x_device_entry without x_device_name set first.") + if self._main_curve.config.device_x is None: + logger.warning("Cannot set signal_x without device_x set first.") return - device_name = self._main_curve.config.x_device.name + device_name = self._main_curve.config.device_x.device try: - validated_entry = self.entry_validator.validate_signal(device_name, entry) - self._main_curve.config.x_device.entry = validated_entry - self.property_changed.emit("x_device_entry", validated_entry) + validated_signal = self.entry_validator.validate_signal(device_name, entry) + self._main_curve.config.device_x.signal = validated_signal + self.property_changed.emit("signal_x", validated_signal) self.update_labels() self._try_auto_plot() except Exception: pass # Silently fail if validation fails @SafeProperty(str) - def y_device_name(self) -> str: + def device_y(self) -> str: """Device name for the Y axis.""" - if self._main_curve is None or self._main_curve.config.y_device is None: + if self._main_curve is None or self._main_curve.config.device_y is None: return "" - return self._main_curve.config.y_device.name or "" + return self._main_curve.config.device_y.device or "" - @y_device_name.setter - def y_device_name(self, device_name: str) -> None: + @device_y.setter + def device_y(self, device_name: str) -> None: """ Set the Y device name. @@ -490,33 +490,33 @@ def y_device_name(self, device_name: str) -> None: try: entry = self.entry_validator.validate_signal(device_name, None) # Update or create config - if self._main_curve.config.y_device is None: - self._main_curve.config.y_device = ScatterDeviceSignal( - name=device_name, entry=entry + if self._main_curve.config.device_y is None: + self._main_curve.config.device_y = ScatterDeviceSignal( + device=device_name, signal=entry ) else: - self._main_curve.config.y_device.name = device_name - self._main_curve.config.y_device.entry = entry - self.property_changed.emit("y_device_name", device_name) + self._main_curve.config.device_y.device = device_name + self._main_curve.config.device_y.signal = entry + self.property_changed.emit("device_y", device_name) self.update_labels() self._try_auto_plot() except Exception: pass # Silently fail if device is not available yet else: - if self._main_curve.config.y_device is not None: - self._main_curve.config.y_device = None - self.property_changed.emit("y_device_name", "") + if self._main_curve.config.device_y is not None: + self._main_curve.config.device_y = None + self.property_changed.emit("device_y", "") self.update_labels() @SafeProperty(str) - def y_device_entry(self) -> str: + def signal_y(self) -> str: """Signal entry for the Y axis device.""" - if self._main_curve is None or self._main_curve.config.y_device is None: + if self._main_curve is None or self._main_curve.config.device_y is None: return "" - return self._main_curve.config.y_device.entry or "" + return self._main_curve.config.device_y.signal or "" - @y_device_entry.setter - def y_device_entry(self, entry: str) -> None: + @signal_y.setter + def signal_y(self, entry: str) -> None: """ Set the Y device entry. @@ -526,29 +526,29 @@ def y_device_entry(self, entry: str) -> None: if not entry: return - if self._main_curve.config.y_device is None: - logger.warning("Cannot set y_device_entry without y_device_name set first.") + if self._main_curve.config.device_y is None: + logger.warning("Cannot set signal_y without device_y set first.") return - device_name = self._main_curve.config.y_device.name + device_name = self._main_curve.config.device_y.device try: - validated_entry = self.entry_validator.validate_signal(device_name, entry) - self._main_curve.config.y_device.entry = validated_entry - self.property_changed.emit("y_device_entry", validated_entry) + validated_signal = self.entry_validator.validate_signal(device_name, entry) + self._main_curve.config.device_y.signal = validated_signal + self.property_changed.emit("signal_y", validated_signal) self.update_labels() self._try_auto_plot() except Exception: pass # Silently fail if validation fails @SafeProperty(str) - def z_device_name(self) -> str: + def device_z(self) -> str: """Device name for the Z (color) axis.""" - if self._main_curve is None or self._main_curve.config.z_device is None: + if self._main_curve is None or self._main_curve.config.device_z is None: return "" - return self._main_curve.config.z_device.name or "" + return self._main_curve.config.device_z.device or "" - @z_device_name.setter - def z_device_name(self, device_name: str) -> None: + @device_z.setter + def device_z(self, device_name: str) -> None: """ Set the Z device name. @@ -561,33 +561,33 @@ def z_device_name(self, device_name: str) -> None: try: entry = self.entry_validator.validate_signal(device_name, None) # Update or create config - if self._main_curve.config.z_device is None: - self._main_curve.config.z_device = ScatterDeviceSignal( - name=device_name, entry=entry + if self._main_curve.config.device_z is None: + self._main_curve.config.device_z = ScatterDeviceSignal( + device=device_name, signal=entry ) else: - self._main_curve.config.z_device.name = device_name - self._main_curve.config.z_device.entry = entry - self.property_changed.emit("z_device_name", device_name) + self._main_curve.config.device_z.device = device_name + self._main_curve.config.device_z.signal = entry + self.property_changed.emit("device_z", device_name) self.update_labels() self._try_auto_plot() except Exception: pass # Silently fail if device is not available yet else: - if self._main_curve.config.z_device is not None: - self._main_curve.config.z_device = None - self.property_changed.emit("z_device_name", "") + if self._main_curve.config.device_z is not None: + self._main_curve.config.device_z = None + self.property_changed.emit("device_z", "") self.update_labels() @SafeProperty(str) - def z_device_entry(self) -> str: + def signal_z(self) -> str: """Signal entry for the Z (color) axis device.""" - if self._main_curve is None or self._main_curve.config.z_device is None: + if self._main_curve is None or self._main_curve.config.device_z is None: return "" - return self._main_curve.config.z_device.entry or "" + return self._main_curve.config.device_z.signal or "" - @z_device_entry.setter - def z_device_entry(self, entry: str) -> None: + @signal_z.setter + def signal_z(self, entry: str) -> None: """ Set the Z device entry. @@ -597,15 +597,15 @@ def z_device_entry(self, entry: str) -> None: if not entry: return - if self._main_curve.config.z_device is None: - logger.warning("Cannot set z_device_entry without z_device_name set first.") + if self._main_curve.config.device_z is None: + logger.warning("Cannot set signal_z without device_z set first.") return - device_name = self._main_curve.config.z_device.name + device_name = self._main_curve.config.device_z.device try: - validated_entry = self.entry_validator.validate_signal(device_name, entry) - self._main_curve.config.z_device.entry = validated_entry - self.property_changed.emit("z_device_entry", validated_entry) + validated_signal = self.entry_validator.validate_signal(device_name, entry) + self._main_curve.config.device_z.signal = validated_signal + self.property_changed.emit("signal_z", validated_signal) self.update_labels() self._try_auto_plot() except Exception: @@ -615,25 +615,25 @@ def _try_auto_plot(self) -> None: """ Attempt to automatically call plot() if all three devices are set. """ - has_x = self._main_curve.config.x_device is not None - has_y = self._main_curve.config.y_device is not None - has_z = self._main_curve.config.z_device is not None + has_x = self._main_curve.config.device_x is not None + has_y = self._main_curve.config.device_y is not None + has_z = self._main_curve.config.device_z is not None if has_x and has_y and has_z: - x_name = self._main_curve.config.x_device.name - x_entry = self._main_curve.config.x_device.entry - y_name = self._main_curve.config.y_device.name - y_entry = self._main_curve.config.y_device.entry - z_name = self._main_curve.config.z_device.name - z_entry = self._main_curve.config.z_device.entry + device_x = self._main_curve.config.device_x.device + signal_x = self._main_curve.config.device_x.signal + device_y = self._main_curve.config.device_y.device + signal_y = self._main_curve.config.device_y.signal + device_z = self._main_curve.config.device_z.device + signal_z = self._main_curve.config.device_z.signal try: self.plot( - x_name=x_name, - y_name=y_name, - z_name=z_name, - x_entry=x_entry, - y_entry=y_entry, - z_entry=z_entry, + device_x=device_x, + device_y=device_y, + device_z=device_z, + signal_x=signal_x, + signal_y=signal_y, + signal_z=signal_z, validate_bec=False, # Don't validate - entries already validated ) except Exception as e: @@ -650,21 +650,21 @@ def update_labels(self): config = self._main_curve.config # Safely get device names - x_device = config.x_device - y_device = config.y_device + device_x = config.device_x + device_y = config.device_y - x_name = x_device.name if x_device else None - y_name = y_device.name if y_device else None + device_x = device_x.device if device_x else None + device_y = device_y.device if device_y else None - if x_name is not None: - self.x_label = x_name # type: ignore - x_dev = self.dev.get(x_name) + if device_x is not None: + self.x_label = device_x # type: ignore + x_dev = self.dev.get(device_x) if x_dev and hasattr(x_dev, "egu"): self.x_label_units = x_dev.egu() - if y_name is not None: - self.y_label = y_name # type: ignore - y_dev = self.dev.get(y_name) + if device_y is not None: + self.y_label = device_y # type: ignore + y_dev = self.dev.get(device_y) if y_dev and hasattr(y_dev, "egu"): self.y_label_units = y_dev.egu() @@ -756,7 +756,7 @@ def __init__(self): self.setCentralWidget(self.main_widget) self.waveform_popup = ScatterWaveform(popups=True) - self.waveform_popup.plot("samx", "samy", "bpm4i") + self.waveform_popup.plot(device_x="samx", device_y="samy", device_z="bpm4i") self.waveform_side = ScatterWaveform(popups=False) self.waveform_popup.plot("samx", "samy", "bpm3a") diff --git a/bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_setting.py b/bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_setting.py index 475181c51..46f211f55 100644 --- a/bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_setting.py +++ b/bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_setting.py @@ -58,81 +58,81 @@ def fetch_all_properties(self): color_map = getattr(self.target_widget, "color_map", None) # Default values for device properties - x_name, x_entry = None, None - y_name, y_entry = None, None - z_name, z_entry = None, None + device_x, signal_x = None, None + device_y, signal_y = None, None + device_z, signal_z = None, None # Safely access device properties if hasattr(self.target_widget, "main_curve") and self.target_widget.main_curve: if hasattr(self.target_widget.main_curve, "config"): config = self.target_widget.main_curve.config - if hasattr(config, "x_device") and config.x_device: - x_name = getattr(config.x_device, "name", None) - x_entry = getattr(config.x_device, "entry", None) + if hasattr(config, "device_x") and config.device_x: + device_x = getattr(config.device_x, "device", None) + signal_x = getattr(config.device_x, "signal", None) - if hasattr(config, "y_device") and config.y_device: - y_name = getattr(config.y_device, "name", None) - y_entry = getattr(config.y_device, "entry", None) + if hasattr(config, "device_y") and config.device_y: + device_y = getattr(config.device_y, "device", None) + signal_y = getattr(config.device_y, "signal", None) - if hasattr(config, "z_device") and config.z_device: - z_name = getattr(config.z_device, "name", None) - z_entry = getattr(config.z_device, "entry", None) + if hasattr(config, "device_z") and config.device_z: + device_z = getattr(config.device_z, "device", None) + signal_z = getattr(config.device_z, "signal", None) # Apply the properties to the settings widget if hasattr(self.ui, "color_map"): self.ui.color_map.colormap = color_map - if hasattr(self.ui, "x_name"): - self.ui.x_name.set_device(x_name) - if hasattr(self.ui, "x_entry") and x_entry is not None: - self.ui.x_entry.set_to_obj_name(x_entry) + if hasattr(self.ui, "device_x"): + self.ui.device_x.set_device(device_x) + if hasattr(self.ui, "signal_x") and signal_x is not None: + self.ui.signal_x.set_to_obj_name(signal_x) - if hasattr(self.ui, "y_name"): - self.ui.y_name.set_device(y_name) - if hasattr(self.ui, "y_entry") and y_entry is not None: - self.ui.y_entry.set_to_obj_name(y_entry) + if hasattr(self.ui, "device_y"): + self.ui.device_y.set_device(device_y) + if hasattr(self.ui, "signal_y") and signal_y is not None: + self.ui.signal_y.set_to_obj_name(signal_y) - if hasattr(self.ui, "z_name"): - self.ui.z_name.set_device(z_name) - if hasattr(self.ui, "z_entry") and z_entry is not None: - self.ui.z_entry.set_to_obj_name(z_entry) + if hasattr(self.ui, "device_z"): + self.ui.device_z.set_device(device_z) + if hasattr(self.ui, "signal_z") and signal_z is not None: + self.ui.signal_z.set_to_obj_name(signal_z) @SafeSlot() def accept_changes(self): """ Apply all properties from the settings widget to the target widget. """ - x_name = self.ui.x_name.currentText() - x_entry = self.ui.x_entry.get_signal_name() - y_name = self.ui.y_name.currentText() - y_entry = self.ui.y_entry.get_signal_name() - z_name = self.ui.z_name.currentText() - z_entry = self.ui.z_entry.get_signal_name() + device_x = self.ui.device_x.currentText() + signal_x = self.ui.signal_x.get_signal_name() + device_y = self.ui.device_y.currentText() + signal_y = self.ui.signal_y.get_signal_name() + device_z = self.ui.device_z.currentText() + signal_z = self.ui.signal_z.get_signal_name() validate_bec = self.ui.validate_bec.checked color_map = self.ui.color_map.colormap self.target_widget.plot( - x_name=x_name, - y_name=y_name, - z_name=z_name, - x_entry=x_entry, - y_entry=y_entry, - z_entry=z_entry, + device_x=device_x, + device_y=device_y, + device_z=device_z, + signal_x=signal_x, + signal_y=signal_y, + signal_z=signal_z, color_map=color_map, validate_bec=validate_bec, ) def cleanup(self): - self.ui.x_name.close() - self.ui.x_name.deleteLater() - self.ui.x_entry.close() - self.ui.x_entry.deleteLater() - self.ui.y_name.close() - self.ui.y_name.deleteLater() - self.ui.y_entry.close() - self.ui.y_entry.deleteLater() - self.ui.z_name.close() - self.ui.z_name.deleteLater() - self.ui.z_entry.close() - self.ui.z_entry.deleteLater() + self.ui.device_x.close() + self.ui.device_x.deleteLater() + self.ui.signal_x.close() + self.ui.signal_x.deleteLater() + self.ui.device_y.close() + self.ui.device_y.deleteLater() + self.ui.signal_y.close() + self.ui.signal_y.deleteLater() + self.ui.device_z.close() + self.ui.device_z.deleteLater() + self.ui.signal_z.close() + self.ui.signal_z.deleteLater() diff --git a/bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_horizontal.ui b/bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_horizontal.ui index c8527291c..7a9addf06 100644 --- a/bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_horizontal.ui +++ b/bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_horizontal.ui @@ -61,7 +61,7 @@ - + true @@ -71,7 +71,7 @@ - + true @@ -101,7 +101,7 @@ - + true @@ -111,7 +111,7 @@ - + true @@ -141,7 +141,7 @@ - + true @@ -151,7 +151,7 @@ - + true @@ -187,19 +187,19 @@ - x_name - y_name - z_name - x_entry - y_entry - z_entry + device_x + device_y + device_z + signal_x + signal_y + signal_z - x_name + device_x device_reset() - x_entry + signal_x reset_selection() @@ -213,9 +213,9 @@ - y_name + device_y device_reset() - y_entry + signal_y reset_selection() @@ -229,9 +229,9 @@ - z_name + device_z device_reset() - z_entry + signal_z reset_selection() @@ -245,9 +245,9 @@ - x_name + device_x currentTextChanged(QString) - x_entry + signal_x set_device(QString) @@ -261,9 +261,9 @@ - y_name + device_y currentTextChanged(QString) - y_entry + signal_y set_device(QString) @@ -277,9 +277,9 @@ - z_name + device_z currentTextChanged(QString) - z_entry + signal_z set_device(QString) diff --git a/bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_vertical.ui b/bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_vertical.ui index 3529de4a5..27d47885f 100644 --- a/bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_vertical.ui +++ b/bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_vertical.ui @@ -58,7 +58,7 @@ - + @@ -68,7 +68,7 @@ - + @@ -87,7 +87,7 @@ - + @@ -97,7 +97,7 @@ - + @@ -116,7 +116,7 @@ - + @@ -126,7 +126,7 @@ - + @@ -153,9 +153,9 @@ - x_name + device_x textChanged(QString) - x_entry + signal_x clear() @@ -169,9 +169,9 @@ - y_name + device_y textChanged(QString) - y_entry + signal_y clear() @@ -185,9 +185,9 @@ - z_name + device_z textChanged(QString) - z_entry + signal_z clear() diff --git a/bec_widgets/widgets/plots/waveform/curve.py b/bec_widgets/widgets/plots/waveform/curve.py index 250a83e2f..6f2894590 100644 --- a/bec_widgets/widgets/plots/waveform/curve.py +++ b/bec_widgets/widgets/plots/waveform/curve.py @@ -20,8 +20,8 @@ class DeviceSignal(BaseModel): """The configuration of a signal in the 1D waveform widget.""" - name: str - entry: str + device: str + signal: str dap: str | None = None dap_oversample: int = 1 diff --git a/bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_setting.py b/bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_setting.py index a5a0e0f71..3f3693177 100644 --- a/bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_setting.py +++ b/bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_setting.py @@ -140,7 +140,7 @@ def accept_changes(self): signal_x = self.signal_x.currentText() signal_data = self.signal_x.itemData(self.signal_x.currentIndex()) if signal_x != "": - self.target_widget.x_entry = signal_data.get("obj_name", signal_x) + self.target_widget.signal_x = signal_data.get("obj_name", signal_x) else: self.target_widget.x_mode = self.mode_combo.currentText() self.curve_manager.send_curve_json() diff --git a/bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_tree.py b/bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_tree.py index ac4469799..10c78b461 100644 --- a/bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_tree.py +++ b/bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_tree.py @@ -6,7 +6,6 @@ from bec_lib.logger import bec_logger from bec_qthemes._icon.material_icons import material_icon from qtpy.QtGui import QValidator -from qtpy.QtWidgets import QApplication class ScanIndexValidator(QValidator): @@ -226,7 +225,7 @@ def _init_source_ui(self): self.device_edit.currentTextChanged.connect(self.entry_edit.set_device) self.device_edit.device_reset.connect(self.entry_edit.reset_selection) if self.config.signal: - device_index = self.device_edit.findText(self.config.signal.name or "") + device_index = self.device_edit.findText(self.config.signal.device or "") if device_index >= 0: self.device_edit.setCurrentIndex(device_index) # Force the entry_edit to update based on the device name @@ -235,7 +234,7 @@ def _init_source_ui(self): # If the device name is not found, set the first enabled item self.device_edit.setCurrentIndex(0) - if not self.entry_edit.set_to_obj_name(self.config.signal.entry): + if not self.entry_edit.set_to_obj_name(self.config.signal.signal): # If the entry is not found, try to set it to the first enabled item if not self.entry_edit.set_to_first_enabled(): # If no enabled item is found, set to the first item @@ -309,15 +308,15 @@ def add_dap_row(self): dev_name = "" dev_entry = "" if self.config.signal: - dev_name = self.config.signal.name - dev_entry = self.config.signal.entry + dev_name = self.config.signal.device + dev_entry = self.config.signal.signal # Create a new config for the DAP row dap_cfg = CurveConfig( widget_class="Curve", source="dap", parent_label=parent_label, - signal=DeviceSignal(name=dev_name, entry=dev_entry), + signal=DeviceSignal(device=dev_name, signal=dev_entry), ) new_dap = CurveRow(self.tree, parent_item=self, config=dap_cfg, device_manager=self.dev) # Expand device row to show new child @@ -395,10 +394,10 @@ def export_data(self) -> dict: device_entry = device_entry_info.get("obj_name", device_entry) else: device_entry = self.entry_validator.validate_signal( - name=device_name, entry=device_entry + device=device_name, signal=device_entry ) - self.config.signal = DeviceSignal(name=device_name, entry=device_entry) + self.config.signal = DeviceSignal(device=device_name, signal=device_entry) scan_combo_text = self.scan_index_combo.currentText() if scan_combo_text == "live" or scan_combo_text == "": self.config.scan_number = None @@ -422,16 +421,16 @@ def export_data(self) -> dict: if self.parent_item: parent_conf_dict = self.parent_item.export_data() parent_conf = CurveConfig(**parent_conf_dict) - dev_name = "" - dev_entry = "" + device = "" + signal = "" if parent_conf.signal: - dev_name = parent_conf.signal.name - dev_entry = parent_conf.signal.entry + device = parent_conf.signal.device + signal = parent_conf.signal.signal # Dap from the DapComboBox new_dap = "GaussianModel" if hasattr(self, "dap_combo"): new_dap = self.dap_combo.fit_model_combobox.currentText() - self.config.signal = DeviceSignal(name=dev_name, entry=dev_entry, dap=new_dap) + self.config.signal = DeviceSignal(device=device, signal=signal, dap=new_dap) self.config.source = "dap" self.config.parent_label = parent_conf.label self.config.label = f"{parent_conf.label}-{new_dap}" @@ -613,15 +612,12 @@ def renormalize_colors(self): item.config.color = new_col item.config.symbol_color = new_col - def add_new_curve(self, name: str = None, entry: str = None): + def add_new_curve(self, device: str = None, signal: str = None): """Add a new device-type CurveRow with an assigned colormap color. Args: - name (str, optional): Device name. - entry (str, optional): Device entry. - style (str, optional): Pen style. Defaults to "solid". - width (int, optional): Pen width. Defaults to 4. - symbol_size (int, optional): Symbol size. Defaults to 7. + device (str, optional): Device name. + signal (str, optional): Device entry. Returns: CurveRow: The newly created top-level row. @@ -630,7 +626,7 @@ def add_new_curve(self, name: str = None, entry: str = None): widget_class="Curve", parent_id=self.waveform.gui_id, source="device", - signal=DeviceSignal(name=name or "", entry=entry or ""), + signal=DeviceSignal(device=device or "", signal=signal or ""), ) new_row = CurveRow(self.tree, parent_item=None, config=cfg, device_manager=self.dev) diff --git a/bec_widgets/widgets/plots/waveform/waveform.py b/bec_widgets/widgets/plots/waveform/waveform.py index 51223ebd7..603a0952b 100644 --- a/bec_widgets/widgets/plots/waveform/waveform.py +++ b/bec_widgets/widgets/plots/waveform/waveform.py @@ -73,8 +73,8 @@ class Waveform(PlotBase): "curves", "x_mode", "x_mode.setter", - "x_entry", - "x_entry.setter", + "signal_x", + "signal_x.setter", "color_palette", "color_palette.setter", "skip_large_dataset_warning", @@ -409,7 +409,7 @@ def show_scan_history_popup(self): self.scan_history_dialog.layout.addWidget(self.scan_history_widget) self.scan_history_widget.scan_history_device_viewer.request_history_plot.connect( lambda scan_id, device_name, signal_name: self.plot( - y_name=device_name, y_entry=signal_name, scan_id=scan_id + device_y=device_name, signal_y=signal_name, scan_id=scan_id ) ) self.scan_history_dialog.finished.connect(self._scan_history_closed) @@ -534,14 +534,14 @@ def x_mode(self, value: str): self.round_plot_widget.apply_plot_widget_style() # To keep the correct theme @SafeProperty(str) - def x_entry(self) -> str | None: + def signal_x(self) -> str | None: """ The x signal name. """ return self.x_axis_mode["entry"] - @x_entry.setter - def x_entry(self, value: str | None): + @signal_x.setter + def signal_x(self, value: str | None): """ Set the x signal name. @@ -551,7 +551,7 @@ def x_entry(self, value: str | None): if value is None: return if self.x_axis_mode["name"] in ["auto", "index", "timestamp"]: - logger.warning("Cannot set x_entry when x_mode is not 'device'.") + logger.warning("Cannot set signal_x when x_mode is not 'device'.") return self.x_axis_mode["entry"] = self.entry_validator.validate_signal(self.x_mode, value) self._switch_x_axis_item(mode="device") @@ -690,10 +690,10 @@ def plot( arg1: list | np.ndarray | str | None = None, y: list | np.ndarray | None = None, x: list | np.ndarray | None = None, - x_name: str | None = None, - y_name: str | None = None, - x_entry: str | None = None, - y_entry: str | None = None, + device_x: str | None = None, + device_y: str | None = None, + signal_x: str | None = None, + signal_y: str | None = None, color: str | None = None, label: str | None = None, dap: str | None = None, @@ -705,17 +705,17 @@ def plot( Plot a curve to the plot widget. Args: - arg1(list | np.ndarray | str | None): First argument, which can be x data, y data, or y_name. + arg1(list | np.ndarray | str | None): First argument, which can be x data, y data, or device_y. y(list | np.ndarray): Custom y data to plot. x(list | np.ndarray): Custom y data to plot. - x_name(str): Name of the x signal. + device_x(str): Name of the x signal. - "auto": Use the best effort signal. - "timestamp": Use the timestamp signal. - "index": Use the index signal. - Custom signal name of a device from BEC. - y_name(str): The name of the device for the y-axis. - x_entry(str): The name of the entry for the x-axis. - y_entry(str): The name of the entry for the y-axis. + device_y(str): The name of the device for the y-axis. + signal_x(str): The name of the entry for the x-axis. + signal_y(str): The name of the entry for the y-axis. color(str): The color of the curve. label(str): The label of the curve. dap(str): The dap model to use for the curve. When provided, a DAP curve is @@ -741,7 +741,7 @@ def plot( y_data = np.asarray(y) if isinstance(arg1, str): - y_name = arg1 + device_y = arg1 elif isinstance(arg1, list): if isinstance(y, list): source = "custom" @@ -762,17 +762,17 @@ def plot( x_data = arg1[:, 0] y_data = arg1[:, 1] - # If y_name is set => device data - if y_name is not None and x_data is None and y_data is None: + # If device_y is set => device data + if device_y is not None and x_data is None and y_data is None: source = "device" # Validate or obtain entry - y_entry = self.entry_validator.validate_signal(name=y_name, entry=y_entry) + signal_y = self.entry_validator.validate_signal(device_y, signal_y) - # If user gave x_name => store in x_axis_mode, but do not set data here - if x_name is not None: - self.x_mode = x_name - if x_name not in ["timestamp", "index", "auto"]: - self.x_axis_mode["entry"] = self.entry_validator.validate_signal(x_name, x_entry) + # If user gave device_x => store in x_axis_mode, but do not set data here + if device_x is not None: + self.x_mode = device_x + if device_x not in ["timestamp", "index", "auto"]: + self.x_axis_mode["entry"] = self.entry_validator.validate_signal(device_x, signal_x) # Decide label if not provided if label is None: @@ -781,7 +781,7 @@ def plot( "Curve", [c.object_name for c in self.curves] ) else: - label = f"{y_name}-{y_entry}" + label = f"{device_y}-{signal_y}" # If color not provided, generate from palette if color is None: @@ -801,7 +801,7 @@ def plot( # If it's device-based, attach DeviceSignal if source == "device": - config.signal = DeviceSignal(name=y_name, entry=y_entry) + config.signal = DeviceSignal(device=device_y, signal=signal_y) if scan_id is not None or scan_number is not None: config.source = "history" @@ -851,8 +851,8 @@ def add_dap_curve( f"Only device, history, or custom curves support fitting." ) - dev_name = getattr(getattr(device_curve.config, "signal", None), "name", None) - dev_entry = getattr(getattr(device_curve.config, "signal", None), "entry", None) + dev_name = getattr(getattr(device_curve.config, "signal", None), "device", None) + dev_entry = getattr(getattr(device_curve.config, "signal", None), "signal", None) if dev_name is None: dev_name = device_label if dev_entry is None: @@ -882,7 +882,7 @@ def add_dap_curve( # Attach device signal with DAP config.signal = DeviceSignal( - name=dev_name, entry=dev_entry, dap=dap_name, dap_oversample=dap_oversample + device=dev_name, signal=dev_entry, dap=dap_name, dap_oversample=dap_oversample ) # 4) Create the DAP curve config using `_add_curve(...)` @@ -927,7 +927,7 @@ def _add_curve( label = config.label if config.source == "history": - label = f"{config.signal.name}-{config.signal.entry}-scan-{config.scan_number}" + label = f"{config.signal.device}-{config.signal.signal}-scan-{config.scan_number}" config.label = label if not label: # Fallback label @@ -1003,8 +1003,8 @@ def _fetch_history_data_for_curve( self, curve: Curve, scan_item: ScanDataContainer ) -> Curve | None: # Check if the data are already set - device = curve.config.signal.name - entry = curve.config.signal.entry + device = curve.config.signal.device + entry = curve.config.signal.signal all_devices_used = getattr( getattr(scan_item, "_msg", None), "stored_data_info", None @@ -1043,20 +1043,20 @@ def _fetch_history_data_for_curve( ) curve.setVisible(False) return - x_entry_custom = self.x_axis_mode.get("entry") - if x_entry_custom is None: - x_entry_custom = self.entry_validator.validate_signal( + signal_x_custom = self.x_axis_mode.get("entry") + if signal_x_custom is None: + signal_x_custom = self.entry_validator.validate_signal( self.x_axis_mode["name"], None ) - if x_entry_custom not in all_devices_used[self.x_axis_mode["name"]]: + if signal_x_custom not in all_devices_used[self.x_axis_mode["name"]]: logger.warning( - f"Custom entry '{x_entry_custom}' for device '{self.x_axis_mode['name']}' not found in scan item of history curve '{curve.name()}'; scan ID: {curve.config.scan_id}." + f"Custom entry '{signal_x_custom}' for device '{self.x_axis_mode['name']}' not found in scan item of history curve '{curve.name()}'; scan ID: {curve.config.scan_id}." ) curve.setVisible(False) return x_shape = ( scan_item._msg.stored_data_info.get(self.x_axis_mode["name"]) - .get(x_entry_custom) + .get(signal_x_custom) .shape[0] ) if x_shape != y_shape: @@ -1066,9 +1066,9 @@ def _fetch_history_data_for_curve( curve.setVisible(False) return x_device = scan_item.devices.get(self.x_axis_mode["name"]) - x_data = x_device.get(x_entry_custom).read().get("value") + x_data = x_device.get(signal_x_custom).read().get("value") curve.config.current_x_mode = self.x_axis_mode["name"] - self._update_x_label_suffix(f" (custom: {self.x_axis_mode['name']}-{x_entry_custom})") + self._update_x_label_suffix(f" (custom: {self.x_axis_mode['name']}-{signal_x_custom})") elif self.x_axis_mode["name"] == "auto": if ( self._current_x_device is None @@ -1083,24 +1083,24 @@ def _fetch_history_data_for_curve( curve.set_data(x=x_data, y=y_data) self._update_x_label_suffix(" (auto: index)") return curve - x_entry = self.entry_validator.validate_signal(scan_motors[0], None) - if x_entry not in all_devices_used.get(scan_motors[0], {}): + signal_x = self.entry_validator.validate_signal(scan_motors[0], None) + if signal_x not in all_devices_used.get(scan_motors[0], {}): logger.warning( - f"Auto x entry '{x_entry}' for device '{scan_motors[0]}' not found in scan item of history curve '{curve.name()}'; scan ID: {curve.config.scan_id}." + f"Auto x entry '{signal_x}' for device '{scan_motors[0]}' not found in scan item of history curve '{curve.name()}'; scan ID: {curve.config.scan_id}." ) curve.setVisible(False) return - if y_shape != all_devices_used.get(scan_motors[0]).get(x_entry, {}).shape[0]: + if y_shape != all_devices_used.get(scan_motors[0]).get(signal_x, {}).shape[0]: logger.warning( - f"Shape mismatch for x data '{all_devices_used.get(scan_motors[0]).get(x_entry, {}).get('shape', [0])[0]}' and y data '{y_shape}' in history curve '{curve.name()}'; scan ID: {curve.config.scan_id}." + f"Shape mismatch for x data '{all_devices_used.get(scan_motors[0]).get(signal_x, {}).get('shape', [0])[0]}' and y data '{y_shape}' in history curve '{curve.name()}'; scan ID: {curve.config.scan_id}." ) curve.setVisible(False) return - x_data = scan_item.devices.get(scan_motors[0]).get(x_entry).read().get("value") - self._current_x_device = (scan_motors[0], x_entry) - self._update_x_label_suffix(f" (auto: {scan_motors[0]}-{x_entry})") + x_data = scan_item.devices.get(scan_motors[0]).get(signal_x).read().get("value") + self._current_x_device = (scan_motors[0], signal_x) + self._update_x_label_suffix(f" (auto: {scan_motors[0]}-{signal_x})") curve.config.current_x_mode = "auto" - self._update_x_label_suffix(f" (auto: {scan_motors[0]}-{x_entry})") + self._update_x_label_suffix(f" (auto: {scan_motors[0]}-{signal_x})") else: # Scan in auto mode was done and live scan already set the current x device if self._current_x_device[0] not in all_devices_used: logger.warning( @@ -1446,8 +1446,8 @@ def update_sync_curves(self): return data, access_key = self._fetch_scan_data_and_access() for curve in self._sync_curves: - device_name = curve.config.signal.name - device_entry = curve.config.signal.entry + device_name = curve.config.signal.device + device_entry = curve.config.signal.signal if access_key == "val": device_data = data.get(device_name, {}).get(device_entry, {}).get(access_key, None) else: @@ -1481,8 +1481,8 @@ def update_async_curves(self): data, access_key = self._fetch_scan_data_and_access() for curve in self._async_curves: - device_name = curve.config.signal.name - device_entry = curve.config.signal.entry + device_name = curve.config.signal.device + device_entry = curve.config.signal.signal if access_key == "val": # live access device_data = data.get(device_name, {}).get(device_entry, {}).get(access_key, None) else: # history access @@ -1535,8 +1535,8 @@ def _check_async_signal_found(self, name: str, signal: str) -> tuple[bool, str]: bec_async_signals = self.client.device_manager.get_bec_signals( ["AsyncSignal", "AsyncMultiSignal"] ) - for entry_name, _, entry_data in bec_async_signals: - if entry_name == name and entry_data.get("obj_name") == signal: + for signal_name, _, entry_data in bec_async_signals: + if signal_name == name and entry_data.get("obj_name") == signal: return True, entry_data.get("storage_name") return False, signal @@ -1547,8 +1547,8 @@ def _setup_async_curve(self, curve: Curve): Args: curve(Curve): The curve to set up. """ - name = curve.config.signal.name - signal = curve.config.signal.entry + name = curve.config.signal.device + signal = curve.config.signal.signal async_signal_found, signal = self._check_async_signal_found(name, signal) try: @@ -1621,7 +1621,7 @@ def on_async_readback(self, msg, metadata): x_data = None # Reset x_data y_data = None # Reset y_data # Get the curve data - async_data = msg["signals"].get(curve.config.signal.entry, None) + async_data = msg["signals"].get(curve.config.signal.signal, None) if async_data is None: continue # y-data @@ -1665,12 +1665,12 @@ def on_async_readback(self, msg, metadata): # x_axis_mode is device signal # Only consider device signals that are async for now, fallback is index - x_device_entry = self.x_axis_mode["entry"] - async_data = msg["signals"].get(x_device_entry, None) + signal_x = self.x_axis_mode["entry"] + async_data = msg["signals"].get(signal_x, None) # Make sure the signal exists, otherwise fall back to index if async_data is None: # Try to grab the data from device signals - data_plot_x = self._get_x_data(plot_mode, x_device_entry) + data_plot_x = self._get_x_data(plot_mode, signal_x) else: data_plot_x = np.asarray(async_data["value"]) if x_data is not None: @@ -1678,7 +1678,7 @@ def on_async_readback(self, msg, metadata): # Fallback incase data is not of equal length if len(data_plot_x) != len(data_plot_y): logger.warning( - f"Async data for curve {curve.name()} and x_axis {x_device_entry} is not of equal length. Falling back to 'index' plotting." + f"Async data for curve {curve.name()} and x_axis {signal_x} is not of equal length. Falling back to 'index' plotting." ) data_plot_x = np.linspace(0, len(data_plot_y) - 1, len(data_plot_y)) @@ -1858,18 +1858,18 @@ def _get_x_data(self, device_name: str, device_entry: str) -> list | np.ndarray # 1 User wants custom signal if self.x_axis_mode["name"] not in ["timestamp", "index", "auto"]: - x_name = self.x_axis_mode["name"] - x_entry = self.x_axis_mode.get("entry", None) - if x_entry is None: - x_entry = self.entry_validator.validate_signal(x_name, None) + device_x = self.x_axis_mode["name"] + signal_x = self.x_axis_mode.get("entry", None) + if signal_x is None: + signal_x = self.entry_validator.validate_signal(device_x, None) # if the motor was not scanned, an empty list is returned and curves are not updated if access_key == "val": # live data - x_data = data.get(x_name, {}).get(x_entry, {}).get(access_key, [0]) + x_data = data.get(device_x, {}).get(signal_x, {}).get(access_key, [0]) else: # history data - entry_obj = data.get(x_name, {}).get(x_entry) + entry_obj = data.get(device_x, {}).get(signal_x) x_data = entry_obj.read()["value"] if entry_obj else [0] - new_suffix = f" (custom: {x_name}-{x_entry})" - self._current_x_device = (x_name, x_entry) + new_suffix = f" (custom: {device_x}-{signal_x})" + self._current_x_device = (device_x, signal_x) # 2 User wants timestamp if self.x_axis_mode["name"] == "timestamp": @@ -1913,15 +1913,15 @@ def _get_x_data(self, device_name: str, device_entry: str) -> list | np.ndarray x_data = None new_suffix = " (auto: index)" else: - x_name = scan_report_devices[0] - x_entry = self.entry_validator.validate_signal(x_name, None) + device_x = scan_report_devices[0] + signal_x = self.entry_validator.validate_signal(device_x, None) if access_key == "val": - x_data = data.get(x_name, {}).get(x_entry, {}).get(access_key, None) + x_data = data.get(device_x, {}).get(signal_x, {}).get(access_key, None) else: - entry_obj = data.get(x_name, {}).get(x_entry) + entry_obj = data.get(device_x, {}).get(signal_x) x_data = entry_obj.read()["value"] if entry_obj else None - new_suffix = f" (auto: {x_name}-{x_entry})" - self._current_x_device = (x_name, x_entry) + new_suffix = f" (auto: {device_x}-{signal_x})" + self._current_x_device = (device_x, signal_x) self._update_x_label_suffix(new_suffix) return x_data @@ -1999,7 +1999,7 @@ def _categorise_device_curves(self) -> str: for curve in self.curves: if curve.config.source != "device": continue - dev_name = curve.config.signal.name + dev_name = curve.config.signal.device if dev_name in readout_priority_async: self._async_curves.append(curve) if hasattr(self.scan_item, "live_data"): @@ -2347,11 +2347,11 @@ def __init__(self): self.setCentralWidget(self.main_widget) self.waveform_popup = Waveform(popups=True) - self.waveform_popup.plot(y_name="waveform") + self.waveform_popup.plot(device_y="waveform") self.waveform_side = Waveform(popups=False) - self.waveform_side.plot(y_name="bpm4i", y_entry="bpm4i", dap="GaussianModel") - self.waveform_side.plot(y_name="bpm3a", y_entry="bpm3a") + self.waveform_side.plot(device_y="bpm4i", signal_y="bpm4i", dap="GaussianModel") + self.waveform_side.plot(device_y="bpm3a", signal_y="bpm3a") self.custom_waveform = Waveform(popups=True) self._populate_custom_curve_demo() diff --git a/docs/user/customisation.md b/docs/user/customisation.md index d724ba55f..15a2dfd58 100644 --- a/docs/user/customisation.md +++ b/docs/user/customisation.md @@ -55,7 +55,7 @@ bec_figure = BECFigure(gui_id="my_gui_app_id") window.setCentralWidget(bec_figure) # prepare to plot samx motor vs bpm4i value -bec_figure.plot(x_name="samx", y_name="bpm4i") +bec_figure.plot(device_x="samx", device_y="bpm4i") ``` In the example just above, the resulting application will show a plot of samx @@ -96,7 +96,7 @@ window = QMainWindow() bec_figure = BECFigure(parent=window, gui_id="my_gui_app_id") window.setCentralWidget(bec_figure) -bec_figure.plot(x_name="samx", y_name="bpm4i") +bec_figure.plot(device_x="samx", device_y="bpm4i") # ensuring proper cleanup def final_cleanup(): diff --git a/docs/user/getting_started/quick_start.md b/docs/user/getting_started/quick_start.md index f0bfa7460..c2263e4fd 100644 --- a/docs/user/getting_started/quick_start.md +++ b/docs/user/getting_started/quick_start.md @@ -45,7 +45,7 @@ For the introduction given here, we will focus on the plotting widgets of BECWid ```python plt = gui.new().new().new(gui.available_widgets.Waveform) -plt.plot(x_name='samx', y_name='bpm4i') +plt.plot(device_x='samx', device_y='bpm4i') ``` Here, we create a new plot with a subscription to the devices `samx` and `bpm4i` and assign the plot to the object `plt`. We can now use this object to further customize the plot, e.g. changing the title (`title`), axis labels (`x_label`) @@ -112,7 +112,7 @@ Let's assume BEC was just started and the `gui` object is available in the clien ```python dock_area = gui.new() plt = dock_area.new().new(gui.available_widgets.Waveform) -plt.plot(x_name='samx', y_name='bpm4i') +plt.plot(device_x='samx', device_y='bpm4i') plt.curves[0].set_color(color="white") plt.title = '1D Waveform' ``` diff --git a/docs/user/widgets/heatmap/heatmap_widget.md b/docs/user/widgets/heatmap/heatmap_widget.md index 77d8a9949..d019f9951 100644 --- a/docs/user/widgets/heatmap/heatmap_widget.md +++ b/docs/user/widgets/heatmap/heatmap_widget.md @@ -47,9 +47,9 @@ heatmap_widget = dock_area.new().new(gui.available_widgets.Heatmap) # Plot a heatmap with x and y motor positions and z detector signal heatmap_widget.plot( - x_name='samx', # X-axis motor - y_name='samy', # Y-axis motor - z_name='bpm4i', # Z-axis detector signal + device_x='samx', # X-axis motor + device_y='samy', # Y-axis motor + device_z='bpm4i', # Z-axis detector signal color_map='plasma' ) heatmap_widget.title = "Grid Scan - Sample Position vs BPM Intensity" @@ -66,12 +66,12 @@ heatmap_widget = dock_area.new().new(gui.available_widgets.Heatmap) # Plot heatmap with specific data entries heatmap_widget.plot( - x_name='motor1', - y_name='motor2', - z_name='detector1', - x_entry='RBV', # Use readback value for x - y_entry='RBV', # Use readback value for y - z_entry='value', # Use main value for z + device_x='motor1', + device_y='motor2', + device_z='detector1', + signal_x='RBV', # Use readback value for x + signal_y='RBV', # Use readback value for y + signal_z='value', # Use main value for z color_map='viridis', reload=True # Force reload of data ) diff --git a/docs/user/widgets/image/image_widget.md b/docs/user/widgets/image/image_widget.md index cc02dbd6d..52e6a0ffe 100644 --- a/docs/user/widgets/image/image_widget.md +++ b/docs/user/widgets/image/image_widget.md @@ -32,7 +32,7 @@ dock_area = gui.new() img_widget = dock_area.new().new(gui.available_widgets.Image) # Add an ImageWidget to the BECFigure for a 2D detector -img_widget.image(device_name='eiger', device_entry='preview') +img_widget.image(device='eiger', signal='preview') img_widget.title = "Camera Image - Eiger Detector" ``` @@ -46,7 +46,7 @@ dock_area = gui.new() img_widget = dock_area.new().new(gui.available_widgets.Image) # Add an ImageWidget to the BECFigure for a 2D detector -img_widget.image(device_name='waveform', device_entry='data') +img_widget.image(device='waveform', signal='data') img_widget.title = "Line Detector Data" # Optional: Set the color map and value range @@ -84,7 +84,7 @@ The Image Widget can be configured for different detectors by specifying the cor ```python # For a 2D camera detector -img_widget = fig.image(device_name='eiger', device_entry='preview') +img_widget = fig.image(device='eiger', signal='preview') img_widget.set_title("Eiger Camera Image") ``` @@ -92,7 +92,7 @@ img_widget.set_title("Eiger Camera Image") ```python # For a 1D line detector -img_widget = fig.image(device_name='waveform', device_entry='data') +img_widget = fig.image(device='waveform', signal='data') img_widget.set_title("Line Detector Data") ``` diff --git a/docs/user/widgets/motor_map/motor_map.md b/docs/user/widgets/motor_map/motor_map.md index 4b42e2466..09e51a7f1 100644 --- a/docs/user/widgets/motor_map/motor_map.md +++ b/docs/user/widgets/motor_map/motor_map.md @@ -29,8 +29,8 @@ mm1 = dock_area.new().new(gui.available_widgets.MotorMap) mm2 = dock_area.new().new(gui.available_widgets.MotorMap) # Add signals to the MotorMaps -mm1.map(x_name='samx', y_name='samy') -mm2.map(x_name='aptrx', y_name='aptry') +mm1.map(device_x='samx', device_y='samy') +mm2.map(device_x='aptrx', device_y='aptry') ``` ## Example 2 - Customizing Motor Map Display @@ -57,7 +57,7 @@ You can dynamically change the motors being tracked and reset the history of the mm1.reset_history() # Change the motors being tracked -mm1.map(x_name='aptrx', y_name='aptry') +mm1.map(device_x='aptrx', device_y='aptry') ``` ```` diff --git a/docs/user/widgets/scatter_waveform/scatter_waveform.md b/docs/user/widgets/scatter_waveform/scatter_waveform.md index 4c9ffce68..10426cdae 100644 --- a/docs/user/widgets/scatter_waveform/scatter_waveform.md +++ b/docs/user/widgets/scatter_waveform/scatter_waveform.md @@ -20,7 +20,7 @@ The 2D scatter plot widget is designed for more complex data visualization. It e ```python # Add a new dock_area, a new dock and a BECWaveForm to the dock plt = gui.new().new().new(gui.available_widgets.ScatterWaveform) -plt.plot(x_name='samx', y_name='samy', z_name='bpm4i') +plt.plot(device_x='samx', device_y='samy', device_z='bpm4i') ``` diff --git a/docs/user/widgets/waveform/waveform_widget.md b/docs/user/widgets/waveform/waveform_widget.md index a896bccb0..c1d68e966 100644 --- a/docs/user/widgets/waveform/waveform_widget.md +++ b/docs/user/widgets/waveform/waveform_widget.md @@ -32,8 +32,8 @@ plt1 = dock_area.new().new('Waveform') plt2 = gui.my_new_dock_area.new().new(gui.available_widgets.Waveform) # as an alternative example via dynamic name space # Add signals to the WaveformWidget -plt1.plot(x_name='samx', y_name='bpm4i') -plt2.plot(x_name='samx', y_name='bpm3i') +plt1.plot(device_x='samx', device_y='bpm4i') +plt2.plot(device_x='samx', device_y='bpm3i') # set axis labels plt1.title = "Gauss plots vs. samx" @@ -60,10 +60,10 @@ In addition to the scan curve, you can also add a second curve that fits the sig ```python # Add a new dock_area, dock and Waveform and plot bpm4i vs samx with a GaussianModel DAP plt = gui.new().new().new('Waveform') -plt.plot(x_name='samx', y_name='bpm4i', dap="GaussianModel") +plt.plot(device_x='samx', device_y='bpm4i', dap="GaussianModel") # Add a second curve to the same plot without DAP -plt.plot(x_name='samx', y_name='bpm3a') +plt.plot(device_x='samx', device_y='bpm3a') # Add DAP to the second curve plt.add_dap_curve(device_label='bpm3a-bpm3a', dap_name='GaussianModel') diff --git a/tests/end-2-end/test_bec_dock_rpc_e2e.py b/tests/end-2-end/test_bec_dock_rpc_e2e.py index 55c45a8dd..300605b5c 100644 --- a/tests/end-2-end/test_bec_dock_rpc_e2e.py +++ b/tests/end-2-end/test_bec_dock_rpc_e2e.py @@ -58,8 +58,8 @@ def check_widgets_registered(): assert gui._ipython_registry[mm._gui_id].__class__ == MotorMap mm.map("samx", "samy") - curve = wf.plot(x_name="samx", y_name="bpm4i") - im_item = im.image(device_name="eiger", device_entry="preview") + curve = wf.plot(device_x="samx", device_y="bpm4i") + im_item = im.image(device="eiger", signal="preview") assert curve.__class__.__name__ == "RPCReference" assert curve.__class__ == RPCReference diff --git a/tests/end-2-end/test_plotting_framework_e2e.py b/tests/end-2-end/test_plotting_framework_e2e.py index e98c9236c..a5a57a5cd 100644 --- a/tests/end-2-end/test_plotting_framework_e2e.py +++ b/tests/end-2-end/test_plotting_framework_e2e.py @@ -34,7 +34,7 @@ def test_rpc_plotting_shortcuts_init_configs(qtbot, connected_client_gui_obj): sw = dock_area.new("ScatterWaveform") mw = dock_area.new("MultiWaveform") - c1 = wf.plot(x_name="samx", y_name="bpm4i") + c1 = wf.plot(device_x="samx", device_y="bpm4i") # Adding custom curves, removing one and adding it again should not crash c2 = wf.plot(y=[1, 2, 3], x=[1, 2, 3]) assert c2.object_name == "Curve_0" @@ -42,9 +42,9 @@ def test_rpc_plotting_shortcuts_init_configs(qtbot, connected_client_gui_obj): c3 = wf.plot(y=[1, 2, 3], x=[1, 2, 3]) assert c3.object_name == "Curve_0" - im.image(device_name="eiger", device_entry="preview") - mm.map(x_name="samx", y_name="samy") - sw.plot(x_name="samx", y_name="samy", z_name="bpm4a") + im.image(device="eiger", signal="preview") + mm.map(device_x="samx", device_y="samy") + sw.plot(device_x="samx", device_y="samy", device_z="bpm4a") mw.plot(monitor="waveform") # Adding multiple custom curves sho @@ -70,8 +70,8 @@ def test_rpc_plotting_shortcuts_init_configs(qtbot, connected_client_gui_obj): # Curve assert c1._config_dict["signal"] == { "dap": None, - "name": "bpm4i", - "entry": "bpm4i", + "device": "bpm4i", + "signal": "bpm4i", "dap_oversample": 1, } assert c1._config_dict["source"] == "device" @@ -90,9 +90,9 @@ def test_rpc_waveform_scan(qtbot, bec_client_lib, connected_client_gui_obj): wf = dock_area.new("Waveform") # add 3 different curves to track - wf.plot(x_name="samx", y_name="bpm4i") - wf.plot(x_name="samx", y_name="bpm3a") - wf.plot(x_name="samx", y_name="bpm4d") + wf.plot(device_x="samx", device_y="bpm4i") + wf.plot(device_x="samx", device_y="bpm3a") + wf.plot(device_x="samx", device_y="bpm4d") status = scans.line_scan(dev.samx, -5, 5, steps=10, exp_time=0.05, relative=False) status.wait() @@ -133,7 +133,7 @@ def test_async_plotting(qtbot, bec_client_lib, connected_client_gui_obj): dev.waveform.async_update.set("add").wait() dev.waveform.waveform_shape.set(10000).wait() wf = dock_area.new("Waveform") - curve = wf.plot(y_name="waveform") + curve = wf.plot(device_y="waveform") status = scans.line_scan(dev.samx, -5, 5, steps=5, exp_time=0.05, relative=False) status.wait() @@ -165,7 +165,7 @@ def test_rpc_image(qtbot, bec_client_lib, connected_client_gui_obj): scans = client.scans im = dock_area.new("Image") - im.image(device_name="eiger", device_entry="preview") + im.image(device="eiger", signal="preview") status = scans.line_scan(dev.samx, -5, 5, steps=10, exp_time=0.05, relative=False) status.wait() @@ -188,7 +188,7 @@ def test_rpc_motor_map(qtbot, bec_client_lib, connected_client_gui_obj): dock_area = gui.bec motor_map = dock_area.new("MotorMap") - motor_map.map(x_name="samx", y_name="samy") + motor_map.map(device_x="samx", device_y="samy") initial_pos_x = dev.samx.read()["samx"]["value"] initial_pos_y = dev.samy.read()["samy"]["value"] @@ -219,7 +219,7 @@ def test_dap_rpc(qtbot, bec_client_lib, connected_client_gui_obj): dock_area = gui.bec wf = dock_area.new("Waveform") - wf.plot(x_name="samx", y_name="bpm4i", dap="GaussianModel") + wf.plot(device_x="samx", device_y="bpm4i", dap="GaussianModel") dev.bpm4i.sim.select_model("GaussianModel") params = dev.bpm4i.sim.params @@ -262,7 +262,7 @@ def test_waveform_passing_device(qtbot, bec_client_lib, connected_client_gui_obj wf = dock_area.new("Waveform") c1 = wf.plot( - y_name=dev.samx, y_entry=dev.samx.setpoint + device_y=dev.samx, signal_y=dev.samx.setpoint ) # using setpoint to not use readback signal assert c1.object_name == "samx_samx_setpoint" @@ -342,7 +342,7 @@ def _wait_for_scan_in_history(): # Add curve from history using the chosen selector; single curve per scan to avoid duplicates kwargs = {history_selector: sel_value} - curve = wf.plot(x_name="samx", y_name="bpm4i", **kwargs) + curve = wf.plot(device_x="samx", device_y="bpm4i", **kwargs) num_elements = 10 diff --git a/tests/end-2-end/test_rpc_register_e2e.py b/tests/end-2-end/test_rpc_register_e2e.py index 3e1bfca3d..aeb42a025 100644 --- a/tests/end-2-end/test_rpc_register_e2e.py +++ b/tests/end-2-end/test_rpc_register_e2e.py @@ -12,19 +12,19 @@ def test_rpc_reference_objects(connected_client_gui_obj): dock_area = gui.window_list[0] plt = dock_area.new("Waveform", object_name="fig") - plt.plot(x_name="samx", y_name="bpm4i") + plt.plot(device_x="samx", device_y="bpm4i") im = dock_area.new("Image") - im.image(device_name="eiger", device_entry="preview") + im.image(device="eiger", signal="preview") motor_map = dock_area.new("MotorMap") motor_map.map("samx", "samy") plt_z = dock_area.new("Waveform") - plt_z.plot(x_name="samx", y_name="samy", z_name="bpm4i") + plt_z.plot(device_x="samx", device_y="samy", device_z="bpm4i") assert len(plt_z.curves) == 1 assert len(plt.curves) == 1 - assert im.device_name == "eiger" - assert im.device_entry == "preview" + assert im.device == "eiger" + assert im.signal == "preview" assert isinstance(im.main_image, RPCReference) image_item = gui._ipython_registry.get(im.main_image._gui_id, None) diff --git a/tests/end-2-end/user_interaction/test_user_interaction_e2e.py b/tests/end-2-end/user_interaction/test_user_interaction_e2e.py index cb5d85b57..e4b0b480f 100644 --- a/tests/end-2-end/user_interaction/test_user_interaction_e2e.py +++ b/tests/end-2-end/user_interaction/test_user_interaction_e2e.py @@ -234,7 +234,7 @@ def test_widgets_e2e_image(qtbot, connected_client_gui_obj, random_generator_fro scans = bec.scans dev = bec.device_manager.devices # Test rpc calls - img = widget.image(device_name=dev.eiger.name, device_entry="preview") + img = widget.image(device=dev.eiger.name, signal="preview") assert img.get_data() is None # Run a scan and plot the image s = scans.line_scan(dev.samx, -3, 3, steps=50, exp_time=0.01, relative=False) @@ -254,7 +254,7 @@ def _wait_for_scan_in_history(): assert np.allclose(img.get_data(), last_img) # Now add a device with a preview signal - img = widget.image(device_name="eiger", device_entry="preview") + img = widget.image(device="eiger", signal="preview") s = scans.line_scan(dev.samx, -3, 3, steps=50, exp_time=0.01, relative=False) s.wait() diff --git a/tests/unit_tests/test_curve_settings.py b/tests/unit_tests/test_curve_settings.py index 7c630bd28..faaaa89cf 100644 --- a/tests/unit_tests/test_curve_settings.py +++ b/tests/unit_tests/test_curve_settings.py @@ -179,15 +179,15 @@ def test_add_new_curve(curve_tree_fixture): assert curve_tree.tree.topLevelItemCount() == 0 with patch.object(curve_tree, "_ensure_color_buffer_size") as ensure_spy: - new_item = curve_tree.add_new_curve(name="bpm4i", entry="bpm4i") + new_item = curve_tree.add_new_curve(device="bpm4i", signal="bpm4i") ensure_spy.assert_called_once() assert curve_tree.tree.topLevelItemCount() == 1 last_item = curve_tree.all_items[-1] assert last_item is new_item assert new_item.config.source == "device" - assert new_item.config.signal.name == "bpm4i" - assert new_item.config.signal.entry == "bpm4i" + assert new_item.config.signal.device == "bpm4i" + assert new_item.config.signal.signal == "bpm4i" assert new_item.config.color in curve_tree.color_buffer @@ -197,8 +197,8 @@ def test_renormalize_colors(curve_tree_fixture): """ curve_tree, wf = curve_tree_fixture # Add multiple curves - c1 = curve_tree.add_new_curve(name="bpm4i", entry="bpm4i") - c2 = curve_tree.add_new_curve(name="bpm3a", entry="bpm3a") + c1 = curve_tree.add_new_curve(device="bpm4i", signal="bpm4i") + c2 = curve_tree.add_new_curve(device="bpm3a", signal="bpm3a") curve_tree.color_buffer = [] set_color_spy_c1 = patch.object(c1.color_button, "set_color") @@ -215,7 +215,7 @@ def test_expand_collapse(curve_tree_fixture): Test expand_all_daps() and collapse_all_daps() calls expand/collapse on every top-level item. """ curve_tree, wf = curve_tree_fixture - c1 = curve_tree.add_new_curve(name="bpm4i", entry="bpm4i") + c1 = curve_tree.add_new_curve(device="bpm4i", signal="bpm4i") curve_tree.tree.expandAll() expand_spy = patch.object(curve_tree.tree, "expandItem") collapse_spy = patch.object(curve_tree.tree, "collapseItem") @@ -236,8 +236,8 @@ def test_send_curve_json(curve_tree_fixture, monkeypatch): """ curve_tree, wf = curve_tree_fixture # Add multiple curves - curve_tree.add_new_curve(name="bpm4i", entry="bpm4i") - curve_tree.add_new_curve(name="bpm3a", entry="bpm3a") + curve_tree.add_new_curve(device="bpm4i", signal="bpm4i") + curve_tree.add_new_curve(device="bpm3a", signal="bpm3a") curve_tree.color_palette = "viridis" curve_tree.send_curve_json() @@ -282,7 +282,7 @@ def test_add_dap_row(curve_tree_fixture): curve_tree, wf = curve_tree_fixture # Add a device curve first - device_row = curve_tree.add_new_curve(name="bpm4i", entry="bpm4i") + device_row = curve_tree.add_new_curve(device="bpm4i", signal="bpm4i") assert device_row.source == "device" assert curve_tree.tree.topLevelItemCount() == 1 assert device_row.childCount() == 0 @@ -299,8 +299,8 @@ def test_add_dap_row(curve_tree_fixture): assert dap_child.config.parent_label == device_row.config.label # Check that the DAP inherits device name/entry from parent - assert dap_child.config.signal.name == "bpm4i" - assert dap_child.config.signal.entry == "bpm4i" + assert dap_child.config.signal.device == "bpm4i" + assert dap_child.config.signal.signal == "bpm4i" # Check that the item is in the curve_tree's all_items list assert dap_child in curve_tree.all_items @@ -313,8 +313,8 @@ def test_remove_self_top_level(curve_tree_fixture): curve_tree, wf = curve_tree_fixture # Add two device curves - row1 = curve_tree.add_new_curve(name="bpm4i", entry="bpm4i") - row2 = curve_tree.add_new_curve(name="bpm3a", entry="bpm3a") + row1 = curve_tree.add_new_curve(device="bpm4i", signal="bpm4i") + row2 = curve_tree.add_new_curve(device="bpm3a", signal="bpm3a") assert curve_tree.tree.topLevelItemCount() == 2 assert len(curve_tree.all_items) == 2 @@ -335,7 +335,7 @@ def test_remove_self_child(curve_tree_fixture): curve_tree, wf = curve_tree_fixture # Add a device curve and a DAP child - device_row = curve_tree.add_new_curve(name="bpm4i", entry="bpm4i") + device_row = curve_tree.add_new_curve(device="bpm4i", signal="bpm4i") device_row.add_dap_row() dap_child = device_row.child(0) @@ -360,7 +360,7 @@ def test_export_data_dap(curve_tree_fixture): curve_tree, wf = curve_tree_fixture # Add a device curve with specific parameters - device_row = curve_tree.add_new_curve(name="bpm4i", entry="bpm4i") + device_row = curve_tree.add_new_curve(device="bpm4i", signal="bpm4i") # Add a DAP child device_row.add_dap_row() @@ -375,8 +375,8 @@ def test_export_data_dap(curve_tree_fixture): # Check the exported data assert exported["source"] == "dap" assert exported["parent_label"] == "bpm4i-bpm4i" - assert exported["signal"]["name"] == "bpm4i" - assert exported["signal"]["entry"] == "bpm4i" + assert exported["signal"]["device"] == "bpm4i" + assert exported["signal"]["signal"] == "bpm4i" assert exported["signal"]["dap"] == "GaussianModel" assert exported["label"] == "bpm4i-bpm4i-GaussianModel" @@ -422,7 +422,7 @@ def test_export_data_history_curve(curve_tree_fixture, scan_history_factory): wf.client.queue.scan_storage.current_scan = None # Create a device row and select scan index "2" - device_row = curve_tree.add_new_curve(name="bpm4i", entry="bpm4i") + device_row = curve_tree.add_new_curve(device="bpm4i", signal="bpm4i") device_row.scan_index_combo.setCurrentText("2") exported = device_row.export_data() diff --git a/tests/unit_tests/test_heatmap_widget.py b/tests/unit_tests/test_heatmap_widget.py index fe8e0ee87..ef5f09efe 100644 --- a/tests/unit_tests/test_heatmap_widget.py +++ b/tests/unit_tests/test_heatmap_widget.py @@ -30,11 +30,11 @@ def heatmap_widget(qtbot, mocked_client): def test_heatmap_plot(heatmap_widget): - heatmap_widget.plot(x_name="samx", y_name="samy", z_name="bpm4i") + heatmap_widget.plot(device_x="samx", device_y="samy", device_z="bpm4i") - assert heatmap_widget._image_config.x_device.name == "samx" - assert heatmap_widget._image_config.y_device.name == "samy" - assert heatmap_widget._image_config.z_device.name == "bpm4i" + assert heatmap_widget._image_config.device_x.device == "samx" + assert heatmap_widget._image_config.device_y.device == "samy" + assert heatmap_widget._image_config.device_z.device == "bpm4i" def test_heatmap_on_scan_status_no_scan_id(heatmap_widget): @@ -78,7 +78,7 @@ def test_heatmap_get_image_data_grid_scan(heatmap_widget): info={}, request_inputs={"arg_bundle": ["samx", -5, 5, 10, "samy", -5, 5, 10], "kwargs": {}}, ) - heatmap_widget.plot(x_name="samx", y_name="samy", z_name="bpm4i") + heatmap_widget.plot(device_x="samx", device_y="samy", device_z="bpm4i") heatmap_widget.status_message = scan_msg with mock.patch.object(heatmap_widget, "get_grid_scan_image") as mock_get_grid_scan_image: @@ -147,9 +147,9 @@ def test_heatmap_get_grid_scan_image(heatmap_widget): ) heatmap_widget._image_config = HeatmapConfig( parent_id="parent_id", - x_device=HeatmapDeviceSignal(name="samx", entry="samx"), - y_device=HeatmapDeviceSignal(name="samy", entry="samy"), - z_device=HeatmapDeviceSignal(name="bpm4i", entry="bpm4i"), + device_x=HeatmapDeviceSignal(device="samx", signal="samx"), + device_y=HeatmapDeviceSignal(device="samy", signal="samy"), + device_z=HeatmapDeviceSignal(device="bpm4i", signal="bpm4i"), color_map="viridis", ) img, _ = heatmap_widget.get_grid_scan_image(list(range(100)), msg=scan_msg) @@ -174,9 +174,9 @@ def _grid_positions( def test_heatmap_grid_scan_direction_and_snaking_x_fast(heatmap_widget): heatmap_widget._image_config = HeatmapConfig( parent_id="parent_id", - x_device=HeatmapDeviceSignal(name="samx", entry="samx"), - y_device=HeatmapDeviceSignal(name="samy", entry="samy"), - z_device=HeatmapDeviceSignal(name="bpm4i", entry="bpm4i"), + device_x=HeatmapDeviceSignal(device="samx", signal="samx"), + device_y=HeatmapDeviceSignal(device="samy", signal="samy"), + device_z=HeatmapDeviceSignal(device="bpm4i", signal="bpm4i"), color_map="viridis", ) @@ -219,9 +219,9 @@ def test_heatmap_grid_scan_direction_and_snaking_x_fast(heatmap_widget): def test_heatmap_grid_scan_direction_and_snaking_y_fast(heatmap_widget): heatmap_widget._image_config = HeatmapConfig( parent_id="parent_id", - x_device=HeatmapDeviceSignal(name="samx", entry="samx"), - y_device=HeatmapDeviceSignal(name="samy", entry="samy"), - z_device=HeatmapDeviceSignal(name="bpm4i", entry="bpm4i"), + device_x=HeatmapDeviceSignal(device="samx", signal="samx"), + device_y=HeatmapDeviceSignal(device="samy", signal="samy"), + device_z=HeatmapDeviceSignal(device="bpm4i", signal="bpm4i"), color_map="viridis", ) @@ -277,13 +277,13 @@ def test_heatmap_get_step_scan_image(heatmap_widget): heatmap_widget.scan_item.status_message = scan_msg heatmap_widget._image_config = HeatmapConfig( parent_id="parent_id", - x_device=HeatmapDeviceSignal(name="samx", entry="samx"), - y_device=HeatmapDeviceSignal(name="samy", entry="samy"), - z_device=HeatmapDeviceSignal(name="bpm4i", entry="bpm4i"), + device_x=HeatmapDeviceSignal(device="samx", signal="samx"), + device_y=HeatmapDeviceSignal(device="samy", signal="samy"), + device_z=HeatmapDeviceSignal(device="bpm4i", signal="bpm4i"), color_map="viridis", ) img, _ = heatmap_widget.get_step_scan_image( - list(np.random.rand(100)), list(np.random.rand(100)), list(range(100)), msg=scan_msg + list(np.random.rand(100)), list(np.random.rand(100)), list(range(100)) ) assert img.shape > (10, 10) @@ -291,9 +291,9 @@ def test_heatmap_get_step_scan_image(heatmap_widget): def test_heatmap_update_plot_no_scan_item(heatmap_widget): heatmap_widget._image_config = HeatmapConfig( parent_id="parent_id", - x_device=HeatmapDeviceSignal(name="samx", entry="samx"), - y_device=HeatmapDeviceSignal(name="samy", entry="samy"), - z_device=HeatmapDeviceSignal(name="bpm4i", entry="bpm4i"), + device_x=HeatmapDeviceSignal(device="samx", signal="samx"), + device_y=HeatmapDeviceSignal(device="samy", signal="samy"), + device_z=HeatmapDeviceSignal(device="bpm4i", signal="bpm4i"), color_map="viridis", ) with mock.patch.object(heatmap_widget.main_image, "setImage") as mock_set_image: @@ -304,9 +304,9 @@ def test_heatmap_update_plot_no_scan_item(heatmap_widget): def test_heatmap_update_plot(heatmap_widget): heatmap_widget._image_config = HeatmapConfig( parent_id="parent_id", - x_device=HeatmapDeviceSignal(name="samx", entry="samx"), - y_device=HeatmapDeviceSignal(name="samy", entry="samy"), - z_device=HeatmapDeviceSignal(name="bpm4i", entry="bpm4i"), + device_x=HeatmapDeviceSignal(device="samx", signal="samx"), + device_y=HeatmapDeviceSignal(device="samy", signal="samy"), + device_z=HeatmapDeviceSignal(device="bpm4i", signal="bpm4i"), color_map="viridis", ) heatmap_widget.scan_item = create_dummy_scan_item() @@ -331,9 +331,9 @@ def test_heatmap_update_plot(heatmap_widget): def test_heatmap_update_plot_without_status_message(heatmap_widget): heatmap_widget._image_config = HeatmapConfig( parent_id="parent_id", - x_device=HeatmapDeviceSignal(name="samx", entry="samx"), - y_device=HeatmapDeviceSignal(name="samy", entry="samy"), - z_device=HeatmapDeviceSignal(name="bpm4i", entry="bpm4i"), + device_x=HeatmapDeviceSignal(device="samx", signal="samx"), + device_y=HeatmapDeviceSignal(device="samy", signal="samy"), + device_z=HeatmapDeviceSignal(device="bpm4i", signal="bpm4i"), color_map="viridis", ) heatmap_widget.scan_item = create_dummy_scan_item() @@ -346,9 +346,9 @@ def test_heatmap_update_plot_without_status_message(heatmap_widget): def test_heatmap_update_plot_no_img_data(heatmap_widget): heatmap_widget._image_config = HeatmapConfig( parent_id="parent_id", - x_device=HeatmapDeviceSignal(name="samx", entry="samx"), - y_device=HeatmapDeviceSignal(name="samy", entry="samy"), - z_device=HeatmapDeviceSignal(name="bpm4i", entry="bpm4i"), + device_x=HeatmapDeviceSignal(device="samx", signal="samx"), + device_y=HeatmapDeviceSignal(device="samy", signal="samy"), + device_z=HeatmapDeviceSignal(device="bpm4i", signal="bpm4i"), color_map="viridis", ) heatmap_widget.scan_item = create_dummy_scan_item() @@ -407,7 +407,7 @@ def test_heatmap_settings_popup_accept_changes(heatmap_widget, qtbot): """ Test that changes made in the settings dialog are applied correctly. """ - heatmap_widget.plot(x_name="samx", y_name="samy", z_name="bpm4i") + heatmap_widget.plot(device_x="samx", device_y="samy", device_z="bpm4i") assert heatmap_widget.color_map == "plasma" # Default colormap heatmap_widget.show_heatmap_settings() qtbot.waitUntil(lambda: heatmap_widget.heatmap_dialog is not None) @@ -431,7 +431,7 @@ def test_heatmap_settings_popup_show_settings(heatmap_widget, qtbot): """ Test that the settings dialog opens and contains the expected elements. """ - heatmap_widget.plot(x_name="samx", y_name="samy", z_name="bpm4i") + heatmap_widget.plot(device_x="samx", device_y="samy", device_z="bpm4i") heatmap_widget.show_heatmap_settings() qtbot.waitUntil(lambda: heatmap_widget.heatmap_dialog is not None) @@ -439,13 +439,13 @@ def test_heatmap_settings_popup_show_settings(heatmap_widget, qtbot): assert dialog.isVisible() assert dialog.widget is not None assert hasattr(dialog.widget.ui, "color_map") - assert hasattr(dialog.widget.ui, "x_name") - assert hasattr(dialog.widget.ui, "y_name") - assert hasattr(dialog.widget.ui, "z_name") + assert hasattr(dialog.widget.ui, "device_x") + assert hasattr(dialog.widget.ui, "device_y") + assert hasattr(dialog.widget.ui, "device_z") # Check that the ui elements are correctly initialized assert dialog.widget.ui.color_map.colormap == heatmap_widget.color_map - assert dialog.widget.ui.x_name.currentText() == heatmap_widget._image_config.x_device.name + assert dialog.widget.ui.device_x.currentText() == heatmap_widget._image_config.device_x.device dialog.reject() qtbot.waitUntil(lambda: heatmap_widget.heatmap_dialog is None) @@ -458,7 +458,7 @@ def test_heatmap_widget_reset(heatmap_widget): heatmap_widget._pending_interpolation_request = object() heatmap_widget._latest_interpolation_version = 5 heatmap_widget.scan_item = create_dummy_scan_item() - heatmap_widget.plot(x_name="samx", y_name="samy", z_name="bpm4i") + heatmap_widget.plot(device_x="samx", device_y="samy", device_z="bpm4i") heatmap_widget.reset() assert heatmap_widget._grid_index is None @@ -476,12 +476,12 @@ def test_heatmap_widget_update_plot_with_scan_history(heatmap_widget, grid_scan_ heatmap_widget.client.history._scan_ids.append(grid_scan_history_msg.scan_id) heatmap_widget.client.queue.scan_storage.current_scan = None heatmap_widget.plot( - x_name="samx", - y_name="samy", - z_name="bpm4i", - x_entry="samx", - y_entry="samy", - z_entry="bpm4i", + device_x="samx", + device_y="samy", + device_z="bpm4i", + signal_x="samx", + signal_y="samy", + signal_z="bpm4i", ) qtbot.waitUntil(lambda: heatmap_widget.main_image.raw_data is not None) qtbot.waitUntil(lambda: heatmap_widget.main_image.raw_data.shape == (10, 10)) @@ -602,219 +602,219 @@ def test_finish_interpolation_thread_cleans_references(heatmap_widget): def test_device_safe_properties_get(heatmap_widget): """Test that device SafeProperty getters work correctly.""" # Initially devices should be empty - assert heatmap_widget.x_device_name == "" - assert heatmap_widget.x_device_entry == "" - assert heatmap_widget.y_device_name == "" - assert heatmap_widget.y_device_entry == "" - assert heatmap_widget.z_device_name == "" - assert heatmap_widget.z_device_entry == "" + assert heatmap_widget.device_x == "" + assert heatmap_widget.signal_x == "" + assert heatmap_widget.device_y == "" + assert heatmap_widget.signal_y == "" + assert heatmap_widget.device_z == "" + assert heatmap_widget.signal_z == "" # Set devices via plot - heatmap_widget.plot(x_name="samx", y_name="samy", z_name="bpm4i") + heatmap_widget.plot(device_x="samx", device_y="samy", device_z="bpm4i") # Check properties return device names and entries separately - assert heatmap_widget.x_device_name == "samx" - assert heatmap_widget.x_device_entry # Should have some entry - assert heatmap_widget.y_device_name == "samy" - assert heatmap_widget.y_device_entry # Should have some entry - assert heatmap_widget.z_device_name == "bpm4i" - assert heatmap_widget.z_device_entry # Should have some entry + assert heatmap_widget.device_x == "samx" + assert heatmap_widget.signal_x # Should have some entry + assert heatmap_widget.device_y == "samy" + assert heatmap_widget.signal_y # Should have some entry + assert heatmap_widget.device_z == "bpm4i" + assert heatmap_widget.signal_z # Should have some entry def test_device_safe_properties_set_name(heatmap_widget): """Test that device SafeProperty setters work for device names.""" - # Set x_device_name - should auto-validate entry - heatmap_widget.x_device_name = "samx" - assert heatmap_widget._image_config.x_device is not None - assert heatmap_widget._image_config.x_device.name == "samx" - assert heatmap_widget._image_config.x_device.entry is not None # Entry should be validated - assert heatmap_widget.x_device_name == "samx" - - # Set y_device_name - heatmap_widget.y_device_name = "samy" - assert heatmap_widget._image_config.y_device is not None - assert heatmap_widget._image_config.y_device.name == "samy" - assert heatmap_widget._image_config.y_device.entry is not None - assert heatmap_widget.y_device_name == "samy" - - # Set z_device_name - heatmap_widget.z_device_name = "bpm4i" - assert heatmap_widget._image_config.z_device is not None - assert heatmap_widget._image_config.z_device.name == "bpm4i" - assert heatmap_widget._image_config.z_device.entry is not None - assert heatmap_widget.z_device_name == "bpm4i" + # Set device_x - should auto-validate entry + heatmap_widget.device_x = "samx" + assert heatmap_widget._image_config.device_x is not None + assert heatmap_widget._image_config.device_x.device == "samx" + assert heatmap_widget._image_config.device_x.signal is not None # Entry should be validated + assert heatmap_widget.device_x == "samx" + + # Set device_y + heatmap_widget.device_y = "samy" + assert heatmap_widget._image_config.device_y is not None + assert heatmap_widget._image_config.device_y.device == "samy" + assert heatmap_widget._image_config.device_y.signal is not None + assert heatmap_widget.device_y == "samy" + + # Set device_z + heatmap_widget.device_z = "bpm4i" + assert heatmap_widget._image_config.device_z is not None + assert heatmap_widget._image_config.device_z.device == "bpm4i" + assert heatmap_widget._image_config.device_z.signal is not None + assert heatmap_widget.device_z == "bpm4i" def test_device_safe_properties_set_entry(heatmap_widget): """Test that device entry properties can override default entries.""" # Set device name first - this auto-validates entry - heatmap_widget.x_device_name = "samx" - initial_entry = heatmap_widget.x_device_entry + heatmap_widget.device_x = "samx" + initial_entry = heatmap_widget.signal_x assert initial_entry # Should have auto-validated entry # Override with specific entry - heatmap_widget.x_device_entry = "samx" - assert heatmap_widget._image_config.x_device.entry == "samx" - assert heatmap_widget.x_device_entry == "samx" + heatmap_widget.signal_x = "samx" + assert heatmap_widget._image_config.device_x.signal == "samx" + assert heatmap_widget.signal_x == "samx" # Same for y device - heatmap_widget.y_device_name = "samy" - heatmap_widget.y_device_entry = "samy_setpoint" - assert heatmap_widget._image_config.y_device.entry == "samy_setpoint" + heatmap_widget.device_y = "samy" + heatmap_widget.signal_y = "samy_setpoint" + assert heatmap_widget._image_config.device_y.signal == "samy_setpoint" # Same for z device - heatmap_widget.z_device_name = "bpm4i" - heatmap_widget.z_device_entry = "bpm4i" - assert heatmap_widget._image_config.z_device.entry == "bpm4i" + heatmap_widget.device_z = "bpm4i" + heatmap_widget.signal_z = "bpm4i" + assert heatmap_widget._image_config.device_z.signal == "bpm4i" def test_device_entry_cannot_be_set_without_name(heatmap_widget): """Test that setting entry without device name logs warning and does nothing.""" # Try to set entry without device name - heatmap_widget.x_device_entry = "some_entry" + heatmap_widget.signal_x = "some_entry" # Should not crash, entry should remain empty - assert heatmap_widget.x_device_entry == "" - assert heatmap_widget._image_config.x_device is None + assert heatmap_widget.signal_x == "" + assert heatmap_widget._image_config.device_x is None def test_device_safe_properties_set_empty(heatmap_widget): """Test that device SafeProperty setters handle empty strings.""" # Set device first - heatmap_widget.x_device_name = "samx" - assert heatmap_widget._image_config.x_device is not None + heatmap_widget.device_x = "samx" + assert heatmap_widget._image_config.device_x is not None # Set to empty string - should clear the device - heatmap_widget.x_device_name = "" - assert heatmap_widget.x_device_name == "" - assert heatmap_widget._image_config.x_device is None + heatmap_widget.device_x = "" + assert heatmap_widget.device_x == "" + assert heatmap_widget._image_config.device_x is None def test_device_safe_properties_auto_plot(heatmap_widget): """Test that setting all three devices triggers auto-plot.""" # Set all three devices - heatmap_widget.x_device_name = "samx" - heatmap_widget.y_device_name = "samy" - heatmap_widget.z_device_name = "bpm4i" + heatmap_widget.device_x = "samx" + heatmap_widget.device_y = "samy" + heatmap_widget.device_z = "bpm4i" # Check that plot was called (image_config should be updated) - assert heatmap_widget._image_config.x_device is not None - assert heatmap_widget._image_config.y_device is not None - assert heatmap_widget._image_config.z_device is not None + assert heatmap_widget._image_config.device_x is not None + assert heatmap_widget._image_config.device_y is not None + assert heatmap_widget._image_config.device_z is not None def test_device_properties_update_labels(heatmap_widget): """Test that setting device properties updates axis labels.""" # Set x device - should update x label - heatmap_widget.x_device_name = "samx" + heatmap_widget.device_x = "samx" assert heatmap_widget.x_label == "samx" # Set y device - should update y label - heatmap_widget.y_device_name = "samy" + heatmap_widget.device_y = "samy" assert heatmap_widget.y_label == "samy" # Set z device - should update title - heatmap_widget.z_device_name = "bpm4i" + heatmap_widget.device_z = "bpm4i" assert heatmap_widget.title == "bpm4i" def test_device_properties_partial_configuration(heatmap_widget): """Test that widget handles partial device configuration gracefully.""" # Set only x device - heatmap_widget.x_device_name = "samx" - assert heatmap_widget.x_device_name == "samx" - assert heatmap_widget.y_device_name == "" - assert heatmap_widget.z_device_name == "" + heatmap_widget.device_x = "samx" + assert heatmap_widget.device_x == "samx" + assert heatmap_widget.device_y == "" + assert heatmap_widget.device_z == "" # Set only y device (x already set) - heatmap_widget.y_device_name = "samy" - assert heatmap_widget.x_device_name == "samx" - assert heatmap_widget.y_device_name == "samy" - assert heatmap_widget.z_device_name == "" + heatmap_widget.device_y = "samy" + assert heatmap_widget.device_x == "samx" + assert heatmap_widget.device_y == "samy" + assert heatmap_widget.device_z == "" # Auto-plot should not trigger yet (z missing) # But devices should be configured - assert heatmap_widget._image_config.x_device is not None - assert heatmap_widget._image_config.y_device is not None + assert heatmap_widget._image_config.device_x is not None + assert heatmap_widget._image_config.device_y is not None def test_device_properties_in_user_access(heatmap_widget): """Test that device properties are exposed in USER_ACCESS for RPC.""" from bec_widgets.widgets.plots.heatmap.heatmap import Heatmap - assert "x_device_name" in Heatmap.USER_ACCESS - assert "x_device_name.setter" in Heatmap.USER_ACCESS - assert "x_device_entry" in Heatmap.USER_ACCESS - assert "x_device_entry.setter" in Heatmap.USER_ACCESS - assert "y_device_name" in Heatmap.USER_ACCESS - assert "y_device_name.setter" in Heatmap.USER_ACCESS - assert "y_device_entry" in Heatmap.USER_ACCESS - assert "y_device_entry.setter" in Heatmap.USER_ACCESS - assert "z_device_name" in Heatmap.USER_ACCESS - assert "z_device_name.setter" in Heatmap.USER_ACCESS - assert "z_device_entry" in Heatmap.USER_ACCESS - assert "z_device_entry.setter" in Heatmap.USER_ACCESS + assert "device_x" in Heatmap.USER_ACCESS + assert "device_x.setter" in Heatmap.USER_ACCESS + assert "signal_x" in Heatmap.USER_ACCESS + assert "signal_x.setter" in Heatmap.USER_ACCESS + assert "device_y" in Heatmap.USER_ACCESS + assert "device_y.setter" in Heatmap.USER_ACCESS + assert "signal_y" in Heatmap.USER_ACCESS + assert "signal_y.setter" in Heatmap.USER_ACCESS + assert "device_z" in Heatmap.USER_ACCESS + assert "device_z.setter" in Heatmap.USER_ACCESS + assert "signal_z" in Heatmap.USER_ACCESS + assert "signal_z.setter" in Heatmap.USER_ACCESS def test_device_properties_validation(heatmap_widget): """Test that device entries are validated through entry_validator.""" # Set device name - entry should be auto-validated - heatmap_widget.x_device_name = "samx" - initial_entry = heatmap_widget.x_device_entry + heatmap_widget.device_x = "samx" + initial_entry = heatmap_widget.signal_x # The entry should be validated (will be "samx" in the mock) assert initial_entry == "samx" # Set a different entry - should also be validated - heatmap_widget.x_device_entry = "samx" # Use same name as validated entry - assert heatmap_widget.x_device_entry == "samx" + heatmap_widget.signal_x = "samx" # Use same name as validated entry + assert heatmap_widget.signal_x == "samx" def test_device_properties_with_plot_method(heatmap_widget): """Test that device properties reflect values set via plot() method.""" # Use plot method - heatmap_widget.plot(x_name="samx", y_name="samy", z_name="bpm4i") + heatmap_widget.plot(device_x="samx", device_y="samy", device_z="bpm4i") # Properties should reflect the plotted devices - assert heatmap_widget.x_device_name == "samx" - assert heatmap_widget.y_device_name == "samy" - assert heatmap_widget.z_device_name == "bpm4i" + assert heatmap_widget.device_x == "samx" + assert heatmap_widget.device_y == "samy" + assert heatmap_widget.device_z == "bpm4i" # Entries should be validated - assert heatmap_widget.x_device_entry == "samx" - assert heatmap_widget.y_device_entry == "samy" - assert heatmap_widget.z_device_entry == "bpm4i" + assert heatmap_widget.signal_x == "samx" + assert heatmap_widget.signal_y == "samy" + assert heatmap_widget.signal_z == "bpm4i" def test_device_properties_overwrite_via_properties(heatmap_widget): """Test that device properties can overwrite values set via plot().""" # First set via plot - heatmap_widget.plot(x_name="samx", y_name="samy", z_name="bpm4i") + heatmap_widget.plot(device_x="samx", device_y="samy", device_z="bpm4i") # Overwrite x device via properties - heatmap_widget.x_device_name = "samz" - assert heatmap_widget.x_device_name == "samz" - assert heatmap_widget._image_config.x_device.name == "samz" + heatmap_widget.device_x = "samz" + assert heatmap_widget.device_x == "samz" + assert heatmap_widget._image_config.device_x.device == "samz" # Overwrite y device entry - heatmap_widget.y_device_entry = "samy" - assert heatmap_widget.y_device_entry == "samy" + heatmap_widget.signal_y = "samy" + assert heatmap_widget.signal_y == "samy" def test_device_properties_clearing_devices(heatmap_widget): """Test clearing devices by setting to empty string.""" # Set all devices - heatmap_widget.x_device_name = "samx" - heatmap_widget.y_device_name = "samy" - heatmap_widget.z_device_name = "bpm4i" + heatmap_widget.device_x = "samx" + heatmap_widget.device_y = "samy" + heatmap_widget.device_z = "bpm4i" # Clear x device - heatmap_widget.x_device_name = "" - assert heatmap_widget.x_device_name == "" - assert heatmap_widget._image_config.x_device is None + heatmap_widget.device_x = "" + assert heatmap_widget.device_x == "" + assert heatmap_widget._image_config.device_x is None # Y and Z should still be set - assert heatmap_widget.y_device_name == "samy" - assert heatmap_widget.z_device_name == "bpm4i" + assert heatmap_widget.device_y == "samy" + assert heatmap_widget.device_z == "bpm4i" def test_device_properties_property_changed_signal(heatmap_widget): @@ -826,12 +826,12 @@ def test_device_properties_property_changed_signal(heatmap_widget): heatmap_widget.property_changed.connect(mock_handler) # Set device name - heatmap_widget.x_device_name = "samx" + heatmap_widget.device_x = "samx" # Signal should have been emitted assert mock_handler.called # Check it was called with correct arguments - mock_handler.assert_any_call("x_device_name", "samx") + mock_handler.assert_any_call("device_x", "samx") def test_auto_emit_syncs_heatmap_toolbar_actions(heatmap_widget): @@ -855,7 +855,7 @@ def test_auto_emit_syncs_heatmap_toolbar_actions(heatmap_widget): def test_device_entry_validation_with_invalid_device(heatmap_widget): """Test that invalid device names are handled gracefully.""" # Try to set invalid device name - heatmap_widget.x_device_name = "nonexistent_device" + heatmap_widget.device_x = "nonexistent_device" # Should not crash, but device might not be set if validation fails # The implementation silently fails, so we just check it doesn't crash @@ -864,28 +864,28 @@ def test_device_entry_validation_with_invalid_device(heatmap_widget): def test_device_properties_sequential_entry_changes(heatmap_widget): """Test changing device entry multiple times.""" # Set device - heatmap_widget.x_device_name = "samx" + heatmap_widget.device_x = "samx" # Change entry multiple times - heatmap_widget.x_device_entry = "samx_velocity" - assert heatmap_widget.x_device_entry == "samx_velocity" + heatmap_widget.signal_x = "samx_velocity" + assert heatmap_widget.signal_x == "samx_velocity" - heatmap_widget.x_device_entry = "samx_setpoint" - assert heatmap_widget.x_device_entry == "samx_setpoint" + heatmap_widget.signal_x = "samx_setpoint" + assert heatmap_widget.signal_x == "samx_setpoint" - heatmap_widget.x_device_entry = "samx" - assert heatmap_widget.x_device_entry == "samx" + heatmap_widget.signal_x = "samx" + assert heatmap_widget.signal_x == "samx" def test_device_properties_with_none_values(heatmap_widget): """Test that None values are handled as empty strings.""" # Device name None should be treated as empty - heatmap_widget.x_device_name = None - assert heatmap_widget.x_device_name == "" + heatmap_widget.device_x = None + assert heatmap_widget.device_x == "" # Set a device first - heatmap_widget.y_device_name = "samy" + heatmap_widget.device_y = "samy" # Entry None should not change anything - heatmap_widget.y_device_entry = None - assert heatmap_widget.y_device_entry # Should still have validated entry + heatmap_widget.signal_y = None + assert heatmap_widget.signal_y # Should still have validated entry diff --git a/tests/unit_tests/test_image_view_next_gen.py b/tests/unit_tests/test_image_view_next_gen.py index 6144468d8..dfdb4f983 100644 --- a/tests/unit_tests/test_image_view_next_gen.py +++ b/tests/unit_tests/test_image_view_next_gen.py @@ -14,14 +14,9 @@ def _set_signal_config( - client, - device_name: str, - signal_name: str, - signal_class: str, - ndim: int, - obj_name: str | None = None, + client, device: str, signal_name: str, signal_class: str, ndim: int, obj_name: str | None = None ): - device = client.device_manager.devices[device_name] + device = client.device_manager.devices[device] device._info["signals"][signal_name] = { "obj_name": obj_name or signal_name, "signal_class": signal_class, @@ -153,14 +148,14 @@ def test_image_setup_preview_signal_1d(qtbot, mocked_client): obj_name="waveform1d_img", ) - view.image(device_name="waveform1d", device_entry="img") + view.image(device="waveform1d", signal="img") # Subscriptions should indicate 1‑D preview connection sub = view.subscriptions["main"] assert sub.source == "device_monitor_1d" assert sub.monitor_type == "1d" - assert view.device_name == "waveform1d" - assert view.device_entry == "img" + assert view.device == "waveform1d" + assert view.signal == "img" # Simulate a waveform update from the dispatcher waveform = np.arange(25, dtype=float) @@ -187,14 +182,14 @@ def test_image_setup_preview_signal_2d(qtbot, mocked_client): obj_name="eiger_img2d", ) - view.image(device_name="eiger", device_entry="img2d") + view.image(device="eiger", signal="img2d") # Subscriptions should indicate 2‑D preview connection sub = view.subscriptions["main"] assert sub.source == "device_monitor_2d" assert sub.monitor_type == "2d" - assert view.device_name == "eiger" - assert view.device_entry == "img2d" + assert view.device == "eiger" + assert view.signal == "img2d" # Simulate a 2‑D image update test_data = np.arange(16, dtype=float).reshape(4, 4) @@ -259,7 +254,7 @@ def test_image_async_signal_uses_obj_name(qtbot, mocked_client, monkeypatch): mocked_client, "eiger", "img", signal_class="AsyncSignal", ndim=1, obj_name="async_obj" ) - view.image(device_name="eiger", device_entry="img") + view.image(device="eiger", signal="img") assert view.subscriptions["main"].async_signal_name == "async_obj" assert view.async_update is True @@ -300,7 +295,7 @@ def test_disconnect_clears_async_state(qtbot, mocked_client, monkeypatch): mocked_client, "eiger", "img", signal_class="AsyncSignal", ndim=2, obj_name="async_obj" ) - view.image(device_name="eiger", device_entry="img") + view.image(device="eiger", signal="img") view.scan_id = "scan_x" view.old_scan_id = "scan_y" view.subscriptions["main"].async_signal_name = "async_obj" @@ -308,7 +303,7 @@ def test_disconnect_clears_async_state(qtbot, mocked_client, monkeypatch): # Avoid touching real dispatcher monkeypatch.setattr(view.bec_dispatcher, "disconnect_slot", lambda *args, **kwargs: None) - view.disconnect_monitor(device_name="eiger", device_entry="img") + view.disconnect_monitor(device="eiger", signal="img") assert view.subscriptions["main"].async_signal_name is None assert view.async_update is False @@ -322,7 +317,7 @@ def test_image_setup_rejects_unsupported_signal_class(qtbot, mocked_client): view = create_widget(qtbot, Image, client=mocked_client) _set_signal_config(mocked_client, "eiger", "img", signal_class="Signal", ndim=2) - view.image(device_name="eiger", device_entry="img") + view.image(device="eiger", signal="img") assert view.subscriptions["main"].source is None assert view.subscriptions["main"].monitor_type is None @@ -333,13 +328,13 @@ def test_image_disconnects_with_missing_entry(qtbot, mocked_client): view = create_widget(qtbot, Image, client=mocked_client) _set_signal_config(mocked_client, "eiger", "img", signal_class="PreviewSignal", ndim=2) - view.image(device_name="eiger", device_entry="img") - assert view.device_name == "eiger" - assert view.device_entry == "img" + view.image(device="eiger", signal="img") + assert view.device == "eiger" + assert view.signal == "img" - view.image(device_name="eiger", device_entry=None) - assert view.device_name == "" - assert view.device_entry == "" + view.image(device="eiger", signal=None) + assert view.device == "" + assert view.signal == "" def test_handle_scan_change_clears_buffers_and_resets_crosshair(qtbot, mocked_client, monkeypatch): @@ -541,8 +536,8 @@ def test_setup_image_from_toolbar(qtbot, mocked_client, monkeypatch): bec_image_view.on_device_selection_changed(None) qtbot.wait(200) - assert bec_image_view.device_name == "eiger" - assert bec_image_view.device_entry == "img" + assert bec_image_view.device == "eiger" + assert bec_image_view.signal == "img" assert bec_image_view.subscriptions["main"].source == "device_monitor_2d" assert bec_image_view.subscriptions["main"].monitor_type == "2d" assert bec_image_view.main_image.raw_data is None @@ -834,8 +829,8 @@ def test_device_selection_syncs_from_properties(qtbot, mocked_client, monkeypatc ), ) - view.device_name = "eiger" - view.device_entry = "img2d" + view.device = "eiger" + view.signal = "img2d" qtbot.wait(200) # Allow signal processing @@ -847,19 +842,19 @@ def test_device_selection_syncs_from_properties(qtbot, mocked_client, monkeypatc ) -def test_device_entry_syncs_from_toolbar(qtbot, mocked_client): +def test_signal_syncs_from_toolbar(qtbot, mocked_client): view = create_widget(qtbot, Image, client=mocked_client) _set_signal_config(mocked_client, "eiger", "img_a", signal_class="PreviewSignal", ndim=2) _set_signal_config(mocked_client, "eiger", "img_b", signal_class="PreviewSignal", ndim=2) - view.device_name = "eiger" - view.device_entry = "img_a" + view.device = "eiger" + view.signal = "img_a" device_selection = view.toolbar.components.get_action("device_selection").widget device_selection.signal_combo_box.blockSignals(True) device_selection.signal_combo_box.setCurrentText("img_b") device_selection.signal_combo_box.blockSignals(False) - view._sync_device_entry_from_toolbar() + view._sync_signal_from_toolbar() - assert view.device_entry == "img_b" + assert view.signal == "img_b" diff --git a/tests/unit_tests/test_motor_map_next_gen.py b/tests/unit_tests/test_motor_map_next_gen.py index 4e296f63d..5a348675a 100644 --- a/tests/unit_tests/test_motor_map_next_gen.py +++ b/tests/unit_tests/test_motor_map_next_gen.py @@ -23,12 +23,12 @@ def test_motor_map_select_motor(qtbot, mocked_client): """Test selecting motors for the motor map.""" mm = create_widget(qtbot, MotorMap, client=mocked_client) - mm.map(x_name="samx", y_name="samy", validate_bec=True) + mm.map(device_x="samx", device_y="samy", validate_bec=True) - assert mm.config.x_motor.name == "samx" - assert mm.config.y_motor.name == "samy" - assert mm.config.x_motor.limits == [-10, 10] - assert mm.config.y_motor.limits == [-5, 5] + assert mm.config.device_x.device == "samx" + assert mm.config.device_y.device == "samy" + assert mm.config.device_x.limits == [-10, 10] + assert mm.config.device_y.limits == [-5, 5] assert mm.config.scatter_size == 5 assert mm.config.max_points == 5000 assert mm.config.num_dim_points == 100 @@ -39,7 +39,7 @@ def test_motor_map_select_motor(qtbot, mocked_client): def test_motor_map_properties(qtbot, mocked_client): """Test setting and getting properties of MotorMap.""" mm = create_widget(qtbot, MotorMap, client=mocked_client) - mm.map(x_name="samx", y_name="samy") + mm.map(device_x="samx", device_y="samy") # Test color property mm.color = (100, 150, 200, 255) @@ -86,7 +86,7 @@ def test_motor_map_properties(qtbot, mocked_client): def test_motor_map_get_limits(qtbot, mocked_client): """Test getting motor limits.""" mm = create_widget(qtbot, MotorMap, client=mocked_client) - mm.map(x_name="samx", y_name="samy") + mm.map(device_x="samx", device_y="samy") expected_limits = {"samx": [-10, 10], "samy": [-5, 5]} for motor_name, expected_limit in expected_limits.items(): @@ -133,7 +133,7 @@ def test_motor_map_reset_history(qtbot, mocked_client): def test_motor_map_on_device_readback(qtbot, mocked_client): """Test the motor map updates when receiving device readback.""" mm = create_widget(qtbot, MotorMap, client=mocked_client) - mm.map(x_name="samx", y_name="samy") + mm.map(device_x="samx", device_y="samy") # Clear the buffer and add initial position mm._buffer = {"x": [1.0], "y": [2.0]} @@ -161,7 +161,7 @@ def test_motor_map_on_device_readback(qtbot, mocked_client): def test_motor_map_max_points_limit(qtbot, mocked_client): """Test that the buffer doesn't exceed max_points.""" mm = create_widget(qtbot, MotorMap, client=mocked_client) - mm.map(x_name="samx", y_name="samy") + mm.map(device_x="samx", device_y="samy") # Add more points than max_points mm._buffer = {"x": [1.0, 2.0, 3.0, 4.0], "y": [5.0, 6.0, 7.0, 8.0]} @@ -219,7 +219,7 @@ def test_motor_map_limit_map(qtbot, mocked_client): def test_motor_map_change_limits(qtbot, mocked_client): mm = create_widget(qtbot, MotorMap, client=mocked_client) - mm.map(x_name="samx", y_name="samy") + mm.map(device_x="samx", device_y="samy") # Original mocked limits are # samx: [-10, 10] @@ -229,8 +229,8 @@ def test_motor_map_change_limits(qtbot, mocked_client): rect = mm._limit_map.boundingRect() assert rect.width() == 20 # -10 to 10 inclusive assert rect.height() == 10 # -5 to 5 inclusive - assert mm.config.x_motor.limits == [-10, 10] - assert mm.config.y_motor.limits == [-5, 5] + assert mm.config.device_x.limits == [-10, 10] + assert mm.config.device_y.limits == [-5, 5] # Change the limits of the samx motor mm.dev["samx"].limits = [-20, 20] @@ -239,8 +239,8 @@ def test_motor_map_change_limits(qtbot, mocked_client): qtbot.wait(200) # Allow time for the update to process # Check that the limits map was updated - assert mm.config.x_motor.limits == [-20, 20] - assert mm.config.y_motor.limits == [-5, 5] + assert mm.config.device_x.limits == [-20, 20] + assert mm.config.device_y.limits == [-5, 5] rect = mm._limit_map.boundingRect() assert rect.width() == 40 # -20 to 20 inclusive assert rect.height() == 10 # -5 to 5 inclusive -> same as before @@ -276,13 +276,13 @@ def test_motor_map_toolbar_selection(qtbot, mocked_client): motor_selection.widget.motor_x.setCurrentText("samx") motor_selection.widget.motor_y.setCurrentText("samy") - assert mm.config.x_motor.name == "samx" - assert mm.config.y_motor.name == "samy" + assert mm.config.device_x.device == "samx" + assert mm.config.device_y.device == "samy" motor_selection.widget.motor_y.setCurrentText("samz") - assert mm.config.x_motor.name == "samx" - assert mm.config.y_motor.name == "samz" + assert mm.config.device_x.device == "samx" + assert mm.config.device_y.device == "samz" def test_motor_selection_set_motors_blocks_signals(qtbot, mocked_client): @@ -306,19 +306,19 @@ def test_motor_properties_partial_then_complete_map(qtbot, mocked_client): mm = create_widget(qtbot, MotorMap, client=mocked_client) spy = QSignalSpy(mm.property_changed) - mm.x_motor = "samx" + mm.device_x = "samx" - assert mm.config.x_motor.name == "samx" - assert mm.config.y_motor.name is None + assert mm.config.device_x.device == "samx" + assert mm.config.device_y.device is None assert mm._trace is None # map not triggered yet - assert spy.at(0) == ["x_motor", "samx"] + assert spy.at(0) == ["device_x", "samx"] - mm.y_motor = "samy" + mm.device_y = "samy" - assert mm.config.x_motor.name == "samx" - assert mm.config.y_motor.name == "samy" + assert mm.config.device_x.device == "samx" + assert mm.config.device_y.device == "samy" assert mm._trace is not None # map called once both valid - assert spy.at(1) == ["y_motor", "samy"] + assert spy.at(1) == ["device_y", "samy"] assert len(mm._buffer["x"]) == 1 assert len(mm._buffer["y"]) == 1 @@ -331,9 +331,9 @@ def test_set_motor_name_emits_and_syncs_toolbar(qtbot, mocked_client): spy = QSignalSpy(mm.property_changed) mm._set_motor_name("x", "samx") - assert mm.config.x_motor.name == "samx" + assert mm.config.device_x.device == "samx" assert motor_selection.motor_x.currentText() == "samx" - assert spy.at(0) == ["x_motor", "samx"] + assert spy.at(0) == ["device_x", "samx"] # Calling with same name should be a no-op initial_count = spy.count() @@ -350,7 +350,7 @@ def test_motor_map_settings_dialog(qtbot, mocked_client): assert action_ref().action.isVisible() # set properties to be fetched by dialog - mm.map(x_name="samx", y_name="samy") + mm.map(device_x="samx", device_y="samy") mm.precision = 2 mm.max_points = 1000 mm.scatter_size = 10 diff --git a/tests/unit_tests/test_scatter_waveform.py b/tests/unit_tests/test_scatter_waveform.py index f0ba5620a..a34e12d37 100644 --- a/tests/unit_tests/test_scatter_waveform.py +++ b/tests/unit_tests/test_scatter_waveform.py @@ -37,7 +37,7 @@ def test_scatter_waveform_plot(qtbot, mocked_client): assert curve is not None assert isinstance(curve.config, ScatterCurveConfig) - assert curve.config.x_device == ScatterDeviceSignal(name="samx", entry="samx") + assert curve.config.device_x == ScatterDeviceSignal(device="samx", signal="samx") assert curve.config.label == "bpm4i-bpm4i" @@ -144,49 +144,49 @@ def test_device_safe_properties_get(qtbot, mocked_client): swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) # Initially devices should be empty - assert swf.x_device_name == "" - assert swf.x_device_entry == "" - assert swf.y_device_name == "" - assert swf.y_device_entry == "" - assert swf.z_device_name == "" - assert swf.z_device_entry == "" + assert swf.device_x == "" + assert swf.signal_x == "" + assert swf.device_y == "" + assert swf.signal_y == "" + assert swf.device_z == "" + assert swf.signal_z == "" # Set devices via plot - swf.plot(x_name="samx", y_name="samy", z_name="bpm4i") + swf.plot(device_x="samx", device_y="samy", device_z="bpm4i") # Check properties return device names and entries separately - assert swf.x_device_name == "samx" - assert swf.x_device_entry # Should have some entry - assert swf.y_device_name == "samy" - assert swf.y_device_entry # Should have some entry - assert swf.z_device_name == "bpm4i" - assert swf.z_device_entry # Should have some entry + assert swf.device_x == "samx" + assert swf.signal_x # Should have some entry + assert swf.device_y == "samy" + assert swf.signal_y # Should have some entry + assert swf.device_z == "bpm4i" + assert swf.signal_z # Should have some entry def test_device_safe_properties_set_name(qtbot, mocked_client): """Test that device SafeProperty setters work for device names.""" swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) - # Set x_device_name - should auto-validate entry - swf.x_device_name = "samx" - assert swf._main_curve.config.x_device is not None - assert swf._main_curve.config.x_device.name == "samx" - assert swf._main_curve.config.x_device.entry is not None # Entry should be validated - assert swf.x_device_name == "samx" + # Set device_x - should auto-validate entry + swf.device_x = "samx" + assert swf._main_curve.config.device_x is not None + assert swf._main_curve.config.device_x.device == "samx" + assert swf._main_curve.config.device_x.signal is not None # Entry should be validated + assert swf.device_x == "samx" - # Set y_device_name - swf.y_device_name = "samy" - assert swf._main_curve.config.y_device is not None - assert swf._main_curve.config.y_device.name == "samy" - assert swf._main_curve.config.y_device.entry is not None - assert swf.y_device_name == "samy" + # Set device_y + swf.device_y = "samy" + assert swf._main_curve.config.device_y is not None + assert swf._main_curve.config.device_y.device == "samy" + assert swf._main_curve.config.device_y.signal is not None + assert swf.device_y == "samy" - # Set z_device_name - swf.z_device_name = "bpm4i" - assert swf._main_curve.config.z_device is not None - assert swf._main_curve.config.z_device.name == "bpm4i" - assert swf._main_curve.config.z_device.entry is not None - assert swf.z_device_name == "bpm4i" + # Set device_z + swf.device_z = "bpm4i" + assert swf._main_curve.config.device_z is not None + assert swf._main_curve.config.device_z.device == "bpm4i" + assert swf._main_curve.config.device_z.signal is not None + assert swf.device_z == "bpm4i" def test_device_safe_properties_set_entry(qtbot, mocked_client): @@ -194,24 +194,24 @@ def test_device_safe_properties_set_entry(qtbot, mocked_client): swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) # Set device name first - this auto-validates entry - swf.x_device_name = "samx" - initial_entry = swf.x_device_entry + swf.device_x = "samx" + initial_entry = swf.signal_x assert initial_entry # Should have auto-validated entry # Override with specific entry - swf.x_device_entry = "samx" - assert swf._main_curve.config.x_device.entry == "samx" - assert swf.x_device_entry == "samx" + swf.signal_x = "samx" + assert swf._main_curve.config.device_x.signal == "samx" + assert swf.signal_x == "samx" # Same for y device - swf.y_device_name = "samy" - swf.y_device_entry = "samy_setpoint" - assert swf._main_curve.config.y_device.entry == "samy_setpoint" + swf.device_y = "samy" + swf.signal_y = "samy_setpoint" + assert swf._main_curve.config.device_y.signal == "samy_setpoint" # Same for z device - swf.z_device_name = "bpm4i" - swf.z_device_entry = "bpm4i" - assert swf._main_curve.config.z_device.entry == "bpm4i" + swf.device_z = "bpm4i" + swf.signal_z = "bpm4i" + assert swf._main_curve.config.device_z.signal == "bpm4i" def test_device_entry_cannot_be_set_without_name(qtbot, mocked_client): @@ -219,10 +219,10 @@ def test_device_entry_cannot_be_set_without_name(qtbot, mocked_client): swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) # Try to set entry without device name - swf.x_device_entry = "some_entry" + swf.signal_x = "some_entry" # Should not crash, entry should remain empty - assert swf.x_device_entry == "" - assert swf._main_curve.config.x_device is None + assert swf.signal_x == "" + assert swf._main_curve.config.device_x is None def test_device_safe_properties_set_empty(qtbot, mocked_client): @@ -230,13 +230,13 @@ def test_device_safe_properties_set_empty(qtbot, mocked_client): swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) # Set device first - swf.x_device_name = "samx" - assert swf._main_curve.config.x_device is not None + swf.device_x = "samx" + assert swf._main_curve.config.device_x is not None # Set to empty string - should clear the device - swf.x_device_name = "" - assert swf.x_device_name == "" - assert swf._main_curve.config.x_device is None + swf.device_x = "" + assert swf.device_x == "" + assert swf._main_curve.config.device_x is None def test_device_safe_properties_auto_plot(qtbot, mocked_client): @@ -244,14 +244,14 @@ def test_device_safe_properties_auto_plot(qtbot, mocked_client): swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) # Set all three devices - swf.x_device_name = "samx" - swf.y_device_name = "samy" - swf.z_device_name = "bpm4i" + swf.device_x = "samx" + swf.device_y = "samy" + swf.device_z = "bpm4i" # Check that plot was called (config should be updated) - assert swf._main_curve.config.x_device is not None - assert swf._main_curve.config.y_device is not None - assert swf._main_curve.config.z_device is not None + assert swf._main_curve.config.device_x is not None + assert swf._main_curve.config.device_y is not None + assert swf._main_curve.config.device_z is not None def test_device_properties_update_labels(qtbot, mocked_client): @@ -259,11 +259,11 @@ def test_device_properties_update_labels(qtbot, mocked_client): swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) # Set x device - should update x label - swf.x_device_name = "samx" + swf.device_x = "samx" assert swf.x_label == "samx" # Set y device - should update y label - swf.y_device_name = "samy" + swf.device_y = "samy" assert swf.y_label == "samy" # Note: ScatterWaveform doesn't have a title like Heatmap does for z_device @@ -274,39 +274,39 @@ def test_device_properties_partial_configuration(qtbot, mocked_client): swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) # Set only x device - swf.x_device_name = "samx" - assert swf.x_device_name == "samx" - assert swf.y_device_name == "" - assert swf.z_device_name == "" + swf.device_x = "samx" + assert swf.device_x == "samx" + assert swf.device_y == "" + assert swf.device_z == "" # Set only y device (x already set) - swf.y_device_name = "samy" - assert swf.x_device_name == "samx" - assert swf.y_device_name == "samy" - assert swf.z_device_name == "" + swf.device_y = "samy" + assert swf.device_x == "samx" + assert swf.device_y == "samy" + assert swf.device_z == "" # Auto-plot should not trigger yet (z missing) # But devices should be configured - assert swf._main_curve.config.x_device is not None - assert swf._main_curve.config.y_device is not None + assert swf._main_curve.config.device_x is not None + assert swf._main_curve.config.device_y is not None def test_device_properties_in_user_access(qtbot, mocked_client): """Test that device properties are exposed in USER_ACCESS for RPC.""" swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) - assert "x_device_name" in ScatterWaveform.USER_ACCESS - assert "x_device_name.setter" in ScatterWaveform.USER_ACCESS - assert "x_device_entry" in ScatterWaveform.USER_ACCESS - assert "x_device_entry.setter" in ScatterWaveform.USER_ACCESS - assert "y_device_name" in ScatterWaveform.USER_ACCESS - assert "y_device_name.setter" in ScatterWaveform.USER_ACCESS - assert "y_device_entry" in ScatterWaveform.USER_ACCESS - assert "y_device_entry.setter" in ScatterWaveform.USER_ACCESS - assert "z_device_name" in ScatterWaveform.USER_ACCESS - assert "z_device_name.setter" in ScatterWaveform.USER_ACCESS - assert "z_device_entry" in ScatterWaveform.USER_ACCESS - assert "z_device_entry.setter" in ScatterWaveform.USER_ACCESS + assert "device_x" in ScatterWaveform.USER_ACCESS + assert "device_x.setter" in ScatterWaveform.USER_ACCESS + assert "signal_x" in ScatterWaveform.USER_ACCESS + assert "signal_x.setter" in ScatterWaveform.USER_ACCESS + assert "device_y" in ScatterWaveform.USER_ACCESS + assert "device_y.setter" in ScatterWaveform.USER_ACCESS + assert "signal_y" in ScatterWaveform.USER_ACCESS + assert "signal_y.setter" in ScatterWaveform.USER_ACCESS + assert "device_z" in ScatterWaveform.USER_ACCESS + assert "device_z.setter" in ScatterWaveform.USER_ACCESS + assert "signal_z" in ScatterWaveform.USER_ACCESS + assert "signal_z.setter" in ScatterWaveform.USER_ACCESS def test_device_properties_validation(qtbot, mocked_client): @@ -314,15 +314,15 @@ def test_device_properties_validation(qtbot, mocked_client): swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) # Set device name - entry should be auto-validated - swf.x_device_name = "samx" - initial_entry = swf.x_device_entry + swf.device_x = "samx" + initial_entry = swf.signal_x # The entry should be validated (will be "samx" in the mock) assert initial_entry == "samx" # Set a different entry - should also be validated - swf.x_device_entry = "samx" # Use same name as validated entry - assert swf.x_device_entry == "samx" + swf.signal_x = "samx" # Use same name as validated entry + assert swf.signal_x == "samx" def test_device_properties_with_plot_method(qtbot, mocked_client): @@ -330,17 +330,17 @@ def test_device_properties_with_plot_method(qtbot, mocked_client): swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) # Use plot method - swf.plot(x_name="samx", y_name="samy", z_name="bpm4i") + swf.plot(device_x="samx", device_y="samy", device_z="bpm4i") # Properties should reflect the plotted devices - assert swf.x_device_name == "samx" - assert swf.y_device_name == "samy" - assert swf.z_device_name == "bpm4i" + assert swf.device_x == "samx" + assert swf.device_y == "samy" + assert swf.device_z == "bpm4i" # Entries should be validated - assert swf.x_device_entry == "samx" - assert swf.y_device_entry == "samy" - assert swf.z_device_entry == "bpm4i" + assert swf.signal_x == "samx" + assert swf.signal_y == "samy" + assert swf.signal_z == "bpm4i" def test_device_properties_overwrite_via_properties(qtbot, mocked_client): @@ -348,16 +348,16 @@ def test_device_properties_overwrite_via_properties(qtbot, mocked_client): swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) # First set via plot - swf.plot(x_name="samx", y_name="samy", z_name="bpm4i") + swf.plot(device_x="samx", device_y="samy", device_z="bpm4i") # Overwrite x device via properties - swf.x_device_name = "samz" - assert swf.x_device_name == "samz" - assert swf._main_curve.config.x_device.name == "samz" + swf.device_x = "samz" + assert swf.device_x == "samz" + assert swf._main_curve.config.device_x.device == "samz" # Overwrite y device entry - swf.y_device_entry = "samy" - assert swf.y_device_entry == "samy" + swf.signal_y = "samy" + assert swf.signal_y == "samy" def test_device_properties_clearing_devices(qtbot, mocked_client): @@ -365,18 +365,18 @@ def test_device_properties_clearing_devices(qtbot, mocked_client): swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) # Set all devices - swf.x_device_name = "samx" - swf.y_device_name = "samy" - swf.z_device_name = "bpm4i" + swf.device_x = "samx" + swf.device_y = "samy" + swf.device_z = "bpm4i" # Clear x device - swf.x_device_name = "" - assert swf.x_device_name == "" - assert swf._main_curve.config.x_device is None + swf.device_x = "" + assert swf.device_x == "" + assert swf._main_curve.config.device_x is None # Y and Z should still be set - assert swf.y_device_name == "samy" - assert swf.z_device_name == "bpm4i" + assert swf.device_y == "samy" + assert swf.device_z == "bpm4i" def test_device_properties_property_changed_signal(qtbot, mocked_client): @@ -390,12 +390,12 @@ def test_device_properties_property_changed_signal(qtbot, mocked_client): swf.property_changed.connect(mock_handler) # Set device name - swf.x_device_name = "samx" + swf.device_x = "samx" # Signal should have been emitted assert mock_handler.called # Check it was called with correct arguments - mock_handler.assert_any_call("x_device_name", "samx") + mock_handler.assert_any_call("device_x", "samx") def test_device_entry_validation_with_invalid_device(qtbot, mocked_client): @@ -403,7 +403,7 @@ def test_device_entry_validation_with_invalid_device(qtbot, mocked_client): swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) # Try to set invalid device name - swf.x_device_name = "nonexistent_device" + swf.device_x = "nonexistent_device" # Should not crash, but device might not be set if validation fails # The implementation silently fails, so we just check it doesn't crash @@ -414,17 +414,17 @@ def test_device_properties_sequential_entry_changes(qtbot, mocked_client): swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) # Set device - swf.x_device_name = "samx" + swf.device_x = "samx" # Change entry multiple times - swf.x_device_entry = "samx_velocity" - assert swf.x_device_entry == "samx_velocity" + swf.signal_x = "samx_velocity" + assert swf.signal_x == "samx_velocity" - swf.x_device_entry = "samx_setpoint" - assert swf.x_device_entry == "samx_setpoint" + swf.signal_x = "samx_setpoint" + assert swf.signal_x == "samx_setpoint" - swf.x_device_entry = "samx" - assert swf.x_device_entry == "samx" + swf.signal_x = "samx" + assert swf.signal_x == "samx" def test_device_properties_with_none_values(qtbot, mocked_client): @@ -432,15 +432,15 @@ def test_device_properties_with_none_values(qtbot, mocked_client): swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) # Device name None should be treated as empty - swf.x_device_name = None - assert swf.x_device_name == "" + swf.device_x = None + assert swf.device_x == "" # Set a device first - swf.y_device_name = "samy" + swf.device_y = "samy" # Entry None should not change anything - swf.y_device_entry = None - assert swf.y_device_entry # Should still have validated entry + swf.signal_y = None + assert swf.signal_y # Should still have validated entry ################################################################################ @@ -457,9 +457,9 @@ def test_scatter_curve_settings_accept_changes(qtbot, mocked_client): qtbot.addWidget(settings) # Set up the widgets with test values - settings.ui.x_name.set_device("samx") - settings.ui.y_name.set_device("samy") - settings.ui.z_name.set_device("bpm4i") + settings.ui.device_x.set_device("samx") + settings.ui.device_y.set_device("samy") + settings.ui.device_z.set_device("bpm4i") # Mock the plot method to verify it gets called with correct arguments with patch.object(swf, "plot") as mock_plot: @@ -472,9 +472,9 @@ def test_scatter_curve_settings_accept_changes(qtbot, mocked_client): call_kwargs = mock_plot.call_args[1] # Verify device names were extracted correctly - assert call_kwargs["x_name"] == "samx" - assert call_kwargs["y_name"] == "samy" - assert call_kwargs["z_name"] == "bpm4i" + assert call_kwargs["device_x"] == "samx" + assert call_kwargs["device_y"] == "samy" + assert call_kwargs["device_z"] == "bpm4i" def test_scatter_curve_settings_accept_changes_with_entries(qtbot, mocked_client): @@ -486,9 +486,9 @@ def test_scatter_curve_settings_accept_changes_with_entries(qtbot, mocked_client qtbot.addWidget(settings) # Set devices first to populate signal comboboxes - settings.ui.x_name.set_device("samx") - settings.ui.y_name.set_device("samy") - settings.ui.z_name.set_device("bpm4i") + settings.ui.device_x.set_device("samx") + settings.ui.device_y.set_device("samy") + settings.ui.device_z.set_device("bpm4i") qtbot.wait(100) # Allow time for signals to populate # Mock the plot method @@ -499,9 +499,9 @@ def test_scatter_curve_settings_accept_changes_with_entries(qtbot, mocked_client call_kwargs = mock_plot.call_args[1] # Verify entries are extracted (will use get_signal_name()) - assert "x_entry" in call_kwargs - assert "y_entry" in call_kwargs - assert "z_entry" in call_kwargs + assert "signal_x" in call_kwargs + assert "signal_y" in call_kwargs + assert "signal_z" in call_kwargs def test_scatter_curve_settings_accept_changes_color_map(qtbot, mocked_client): @@ -514,9 +514,9 @@ def test_scatter_curve_settings_accept_changes_color_map(qtbot, mocked_client): qtbot.addWidget(settings) # Set devices - settings.ui.x_name.set_device("samx") - settings.ui.y_name.set_device("samy") - settings.ui.z_name.set_device("bpm4i") + settings.ui.device_x.set_device("samx") + settings.ui.device_y.set_device("samy") + settings.ui.device_z.set_device("bpm4i") # Get the current colormap color_map = settings.ui.color_map.colormap @@ -532,13 +532,13 @@ def test_scatter_curve_settings_fetch_all_properties(qtbot, mocked_client): swf = create_widget(qtbot, ScatterWaveform, client=mocked_client) # First set up the scatter waveform with some data - swf.plot(x_name="samx", y_name="samy", z_name="bpm4i") + swf.plot(device_x="samx", device_y="samy", device_z="bpm4i") # Create the settings widget - it should fetch properties automatically settings = ScatterCurveSettings(parent=None, target_widget=swf, popup=True) qtbot.addWidget(settings) # Verify the settings widget has fetched the values - assert settings.ui.x_name.currentText() == "samx" - assert settings.ui.y_name.currentText() == "samy" - assert settings.ui.z_name.currentText() == "bpm4i" + assert settings.ui.device_x.currentText() == "samx" + assert settings.ui.device_y.currentText() == "samy" + assert settings.ui.device_z.currentText() == "bpm4i" diff --git a/tests/unit_tests/test_waveform.py b/tests/unit_tests/test_waveform.py index 142b0e73b..a749a4cad 100644 --- a/tests/unit_tests/test_waveform.py +++ b/tests/unit_tests/test_waveform.py @@ -107,8 +107,8 @@ def test_plot_single_arg_input_sync(qtbot, mocked_client): assert c1.config.source == "device" assert c2.config.source == "device" - assert c1.config.signal == DeviceSignal(name="bpm4i", entry="bpm4i", dap=None) - assert c2.config.signal == DeviceSignal(name="bpm3a", entry="bpm3a", dap=None) + assert c1.config.signal == DeviceSignal(device="bpm4i", signal="bpm4i", dap=None) + assert c2.config.signal == DeviceSignal(device="bpm3a", signal="bpm3a", dap=None) # Check that the curve is added to the plot assert len(wf.plot_item.curves) == 2 @@ -122,8 +122,8 @@ def test_plot_single_arg_input_async(qtbot, mocked_client): assert c1.config.source == "device" assert c2.config.source == "device" - assert c1.config.signal == DeviceSignal(name="eiger", entry="eiger", dap=None) - assert c2.config.signal == DeviceSignal(name="async_device", entry="async_device", dap=None) + assert c1.config.signal == DeviceSignal(device="eiger", signal="eiger", dap=None) + assert c2.config.signal == DeviceSignal(device="async_device", signal="async_device", dap=None) # Check that the curve is added to the plot assert len(wf.plot_item.curves) == 2 @@ -305,7 +305,7 @@ def test_curve_json_setter_ignores_custom(qtbot, mocked_client): "label": "device_curve", "color": "#ff0000", "source": "device", - "signal": {"name": "bpm4i", "entry": "bpm4i", "dap": None}, + "signal": {"device": "bpm4i", "signal": "bpm4i", "dap": None}, } custom_curve_config = { "widget_class": "Curve", @@ -475,7 +475,7 @@ def test_add_dap_curve(qtbot, mocked_client_with_dap, monkeypatch): dap_curve = wf.add_dap_curve(device_label="bpm4i-bpm4i", dap_name="GaussianModel") assert dap_curve is not None assert dap_curve.config.source == "dap" - assert dap_curve.config.signal.name == "bpm4i" + assert dap_curve.config.signal.device == "bpm4i" assert dap_curve.config.signal.dap == "GaussianModel" @@ -491,8 +491,8 @@ def test_add_dap_curve_custom_source(qtbot, mocked_client_with_dap): dap_curve = wf.add_dap_curve(device_label=custom_curve.name(), dap_name="GaussianModel") assert dap_curve.config.source == "dap" assert dap_curve.config.parent_label == custom_curve.name() - assert dap_curve.config.signal.name == custom_curve.name() - assert dap_curve.config.signal.entry == "custom" + assert dap_curve.config.signal.device == custom_curve.name() + assert dap_curve.config.signal.signal == "custom" assert dap_curve.config.signal.dap == "GaussianModel" @@ -764,7 +764,7 @@ def test_curve_set_data_error_non_custom(qtbot, mocked_client): Test that calling set_data on a non-custom (device) curve raises a ValueError. """ wf = create_widget(qtbot, Waveform, client=mocked_client) - # Create a device curve by providing y_name (which makes source 'device') + # Create a device curve by providing device_y (which makes source 'device') # Assume that entry_validator returns a valid entry. c = wf.plot(arg1="bpm4i", label="device_curve") with pytest.raises(ValueError): @@ -1136,20 +1136,20 @@ def test_update_with_scan_history_by_index(qtbot, mocked_client, scan_history_fa assert len(wf.client.history._scan_ids) == 2, "Expected two history scans" # Do history curve plotting - wf.plot(y_name="bpm4i", y_entry="bpm4i", scan_id="hist1") - wf.plot(y_name="bpm4i", scan_number=2) + wf.plot(device_y="bpm4i", signal_y="bpm4i", scan_id="hist1") + wf.plot(device_y="bpm4i", scan_number=2) assert len(wf.plot_item.curves) == 2, "Expected two curves for history scans" c1, c2 = wf.plot_item.curves # First curve should be for hist1, second for hist2 - assert c1.config.signal.name == "bpm4i" - assert c1.config.signal.entry == "bpm4i" + assert c1.config.signal.device == "bpm4i" + assert c1.config.signal.signal == "bpm4i" assert c1.config.scan_id == "hist1" assert c1.config.scan_number == 1 assert c1.name() == "bpm4i-bpm4i-scan-1" - assert c2.config.signal.name == "bpm4i" - assert c2.config.signal.entry == "bpm4i" + assert c2.config.signal.device == "bpm4i" + assert c2.config.signal.signal == "bpm4i" assert c2.config.scan_id == "hist2" assert c2.config.scan_number == 2 assert c2.name() == "bpm4i-bpm4i-scan-2" @@ -1163,7 +1163,7 @@ def test_history_curve_x_modes_pre_plot(qtbot, mocked_client, scan_history_facto wf = create_widget(qtbot, Waveform, client=mocked_client) hist1, hist2 = inject_scan_history(wf, scan_history_factory, ("hist1", 1), ("hist2", 2)) wf.x_mode = mode - c = wf.plot(y_name="bpm4i", y_entry="bpm4i", scan_id="hist1") + c = wf.plot(device_y="bpm4i", signal_y="bpm4i", scan_id="hist1") assert c.config.current_x_mode == mode @@ -1174,7 +1174,7 @@ def test_history_curve_x_modes_post_plot(qtbot, mocked_client, scan_history_fact """ wf = create_widget(qtbot, Waveform, client=mocked_client) hist1, hist2 = inject_scan_history(wf, scan_history_factory, ("hist1", 1), ("hist2", 2)) - c = wf.plot(y_name="bpm4i", y_entry="bpm4i", scan_id="hist1") + c = wf.plot(device_y="bpm4i", signal_y="bpm4i", scan_id="hist1") # Change x_mode after plotting wf.x_mode = mode # Refresh history curves @@ -1191,7 +1191,7 @@ def test_history_curve_incompatible_x_mode_hides_curve(qtbot, mocked_client, sca # Inject history scan for this test [history_msg] = inject_scan_history(wf, scan_history_factory, ("hist_bad", 1)) # Plot history curve - c = wf.plot(y_name="bpm4i", y_entry="bpm4i", scan_id=history_msg.scan_id) + c = wf.plot(device_y="bpm4i", signal_y="bpm4i", scan_id=history_msg.scan_id) # Curve should be hidden due to incompatible x_mode assert not c.isVisible() @@ -1212,7 +1212,7 @@ def test_fetch_history_data_no_stored_data_raises( # Force get_history_scan_item to return our dummy monkeypatch.setattr(wf, "get_history_scan_item", lambda scan_id, scan_index: dummy_scan) # Attempt to plot history curve should be suppressed by SafeSlot and return None - c = wf.plot(y_name="bpm4i", y_entry="bpm4i", scan_id="dummy", scan_number=1) + c = wf.plot(device_y="bpm4i", signal_y="bpm4i", scan_id="dummy", scan_number=1) assert c is None assert len(wf.curves) == 0 @@ -1224,7 +1224,7 @@ def test_history_curve_device_missing_returns_none(qtbot, mocked_client, scan_hi wf = create_widget(qtbot, Waveform, client=mocked_client) wf.x_mode = "index" [history_msg] = inject_scan_history(wf, scan_history_factory, ("hist_dev_missing", 1)) - c = wf.plot(y_name="non-existing", y_entry="non-existing", scan_id=history_msg.scan_id) + c = wf.plot(device_y="non-existing", signal_y="non-existing", scan_id=history_msg.scan_id) assert c is None @@ -1238,7 +1238,7 @@ def test_history_curve_custom_shape_mismatch_hides_curve( wf.x_mode = "async_device" [history_msg] = inject_scan_history(wf, scan_history_factory, ("hist_custom_shape", 1)) # Force shape mismatch for x-data - c = wf.plot(y_name="bpm4i", y_entry="bpm4i", scan_id=history_msg.scan_id) + c = wf.plot(device_y="bpm4i", signal_y="bpm4i", scan_id=history_msg.scan_id) assert c is not None assert not c.isVisible() @@ -1250,7 +1250,7 @@ def test_history_curve_index_mode_plots_curve(qtbot, mocked_client, scan_history wf = create_widget(qtbot, Waveform, client=mocked_client) wf.x_mode = "index" [history_msg] = inject_scan_history(wf, scan_history_factory, ("hist_index", 1)) - c = wf.plot(y_name="bpm4i", y_entry="bpm4i", scan_id=history_msg.scan_id) + c = wf.plot(device_y="bpm4i", signal_y="bpm4i", scan_id=history_msg.scan_id) assert c is not None assert c.isVisible() assert c.config.current_x_mode == "index" @@ -1263,7 +1263,7 @@ def test_history_curve_timestamp_mode_plots_curve(qtbot, mocked_client, scan_his wf = create_widget(qtbot, Waveform, client=mocked_client) wf.x_mode = "timestamp" [history_msg] = inject_scan_history(wf, scan_history_factory, ("hist_time", 1)) - c = wf.plot(y_name="bpm4i", y_entry="bpm4i", scan_id=history_msg.scan_id) + c = wf.plot(device_y="bpm4i", signal_y="bpm4i", scan_id=history_msg.scan_id) assert c is not None assert c.isVisible() assert c.config.current_x_mode == "timestamp" @@ -1279,7 +1279,7 @@ def test_history_curve_auto_valid_uses_first_report_device( wf.x_mode = "auto" [history_msg] = inject_scan_history(wf, scan_history_factory, ("hist_auto_valid", 1)) # Plot history curve - c = wf.plot(y_name="bpm4i", y_entry="bpm4i", scan_id=history_msg.scan_id) + c = wf.plot(device_y="bpm4i", signal_y="bpm4i", scan_id=history_msg.scan_id) assert c is not None assert c.isVisible() # Should have fallen back to the first scan_report_device @@ -1295,7 +1295,7 @@ def test_history_curve_file_not_found_returns_none(qtbot, mocked_client, scan_hi # Inject a valid history message then corrupt its file_path [history_msg] = inject_scan_history(wf, scan_history_factory, ("bad_file", 1)) history_msg.file_path = "/nonexistent/path.h5" - c = wf.plot(y_name="bpm4i", y_entry="bpm4i", scan_id=history_msg.scan_id) + c = wf.plot(device_y="bpm4i", signal_y="bpm4i", scan_id=history_msg.scan_id) assert c is None @@ -1306,5 +1306,5 @@ def test_history_curve_scan_not_found_returns_none(qtbot, mocked_client): wf = create_widget(qtbot, Waveform, client=mocked_client) wf.x_mode = "index" # No history scans injected for this widget - c = wf.plot(y_name="bpm4i", y_entry="bpm4i", scan_id="unknown_scan") + c = wf.plot(device_y="bpm4i", signal_y="bpm4i", scan_id="unknown_scan") assert c is None