diff --git a/bec_widgets/cli/client.py b/bec_widgets/cli/client.py index b052e742..773d5b44 100644 --- a/bec_widgets/cli/client.py +++ b/bec_widgets/cli/client.py @@ -19,6 +19,7 @@ class Widgets(str, enum.Enum): BECMotorMapWidget = "BECMotorMapWidget" BECQueue = "BECQueue" BECStatusBox = "BECStatusBox" + BECWaveformWidget = "BECWaveformWidget" DeviceBox = "DeviceBox" DeviceComboBox = "DeviceComboBox" DeviceLineEdit = "DeviceLineEdit" @@ -27,7 +28,6 @@ class Widgets(str, enum.Enum): StopButton = "StopButton" TextBox = "TextBox" VSCodeEditor = "VSCodeEditor" - BECWaveformWidget = "BECWaveformWidget" WebsiteWidget = "WebsiteWidget" @@ -469,8 +469,9 @@ class BECFigure(RPCBase): @rpc_call def plot( self, - x: "list | np.ndarray | None" = None, + 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, z_name: "str | None" = None, @@ -492,8 +493,9 @@ class BECFigure(RPCBase): Add a 1D waveform plot to the figure. Always access the first waveform widget in the figure. Args: - x(list | np.ndarray): Custom x data to plot. + arg1(list | np.ndarray | str | None): First argument which can be x data, y data, or y_name. y(list | np.ndarray): Custom y data to plot. + x(list | np.ndarray): Custom x data to plot. x_name(str): The name of the device for the x-axis. y_name(str): The name of the device for the y-axis. z_name(str): The name of the device for the z-axis. @@ -1498,8 +1500,9 @@ class BECWaveform(RPCBase): @rpc_call def plot( self, - x: "list | np.ndarray | None" = None, + 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, z_name: "str | None" = None, @@ -1511,13 +1514,20 @@ class BECWaveform(RPCBase): label: "str | None" = None, validate: "bool" = True, dap: "str | None" = None, + **kwargs, ) -> "BECCurve": """ Plot a curve to the plot widget. + Args: - x(list | np.ndarray): Custom x data to plot. + arg1(list | np.ndarray | str | None): First argument which can be x data, y data, or y_name. y(list | np.ndarray): Custom y data to plot. - x_name(str): The name of the device for the x-axis. + x(list | np.ndarray): Custom y data to plot. + x_name(str): Name of the x signal. + - "best_effort": Use the best effort signal. + - "timestamp": Use the timestamp signal. + - "index": Use the index signal. + - Custom signal name of device from BEC. y_name(str): The name of the device for the y-axis. z_name(str): The name of the device for the z-axis. x_entry(str): The name of the entry for the x-axis. @@ -1527,7 +1537,7 @@ class BECWaveform(RPCBase): color_map_z(str): The color map to use for the z-axis. label(str): The label of the curve. validate(bool): If True, validate the device names and entries. - dap(str): The dap model to use for the curve. If not specified, none will be added. + dap(str): The dap model to use for the curve, only available for sync devices. If not specified, none will be added. Returns: BECCurve: The curve object. @@ -1536,12 +1546,13 @@ class BECWaveform(RPCBase): @rpc_call def add_dap( self, - x_name: "str", - y_name: "str", + x_name: "str | None" = None, + y_name: "str | None" = None, x_entry: "Optional[str]" = None, y_entry: "Optional[str]" = None, color: "Optional[str]" = None, dap: "str" = "GaussianModel", + validate_bec: "bool" = True, **kwargs, ) -> "BECCurve": """ @@ -1556,12 +1567,27 @@ class BECWaveform(RPCBase): color_map_z(str): The color map to use for the z-axis. label(str, optional): Label of the curve. Defaults to None. dap(str): The dap model to use for the curve. + validate_bec(bool, optional): If True, validate the signal with BEC. Defaults to True. **kwargs: Additional keyword arguments for the curve configuration. Returns: BECCurve: The curve object. """ + @rpc_call + def set_x(self, x_name: "str", x_entry: "str | None" = None): + """ + Change the x axis of the plot widget. + + Args: + x_name(str): Name of the x signal. + - "best_effort": Use the best effort signal. + - "timestamp": Use the timestamp signal. + - "index": Use the index signal. + - Custom signal name of device from BEC. + x_entry(str): Entry of the x signal. + """ + @rpc_call def get_dap_params(self) -> "dict": """ @@ -1746,6 +1772,12 @@ class BECWaveform(RPCBase): Remove the plot widget from the figure. """ + @rpc_call + def clear_all(self): + """ + None + """ + @rpc_call def set_legend_label_size(self, size: "int" = None): """ @@ -1756,24 +1788,6 @@ class BECWaveform(RPCBase): """ -class DeviceBox(RPCBase): - @property - @rpc_call - def _config_dict(self) -> "dict": - """ - Get the configuration of the widget. - - Returns: - dict: The configuration of the widget. - """ - - @rpc_call - def _get_all_rpc(self) -> "dict": - """ - Get all registered RPC objects. - """ - - class BECWaveformWidget(RPCBase): @property @rpc_call @@ -1800,6 +1814,7 @@ class BECWaveformWidget(RPCBase): label: "str | None" = None, validate: "bool" = True, dap: "str | None" = None, + **kwargs, ) -> "BECCurve": """ Plot a curve to the plot widget. @@ -2003,6 +2018,24 @@ class BECWaveformWidget(RPCBase): """ +class DeviceBox(RPCBase): + @property + @rpc_call + def _config_dict(self) -> "dict": + """ + Get the configuration of the widget. + + Returns: + dict: The configuration of the widget. + """ + + @rpc_call + def _get_all_rpc(self) -> "dict": + """ + Get all registered RPC objects. + """ + + class DeviceComboBox(RPCBase): @property @rpc_call diff --git a/bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/curve_dialog.py b/bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/curve_dialog.py index d8b98a51..71990343 100644 --- a/bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/curve_dialog.py +++ b/bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/curve_dialog.py @@ -29,18 +29,42 @@ class CurveSettings(SettingWidget): self.layout.addWidget(self.ui) self.ui.add_curve.clicked.connect(self.add_curve) + self.ui.x_mode.currentIndexChanged.connect(self.set_x_mode) @Slot(dict) def display_current_settings(self, config: dict | BaseModel): curves = config["scan_segment"] - first_label, first_curve = next(iter(curves.items())) - self.ui.x_name.setText(first_curve.config.signals.x.name) - self.ui.x_entry.setText(first_curve.config.signals.x.entry) + + # set mode of x axis box + x_name = self.target_widget.waveform._x_axis_mode["name"] + x_entry = self.target_widget.waveform._x_axis_mode["entry"] + self._setup_x_box(x_name, x_entry) + for label, curve in curves.items(): row_count = self.ui.scan_table.rowCount() self.ui.scan_table.insertRow(row_count) ScanRow(table_widget=self.ui.scan_table, row=row_count, config=curve.config) + def _setup_x_box(self, name, entry): + if name in ["index", "timestamp", "best_effort"]: + self.ui.x_mode.setCurrentText(name) + self.set_x_mode() + else: + self.ui.x_mode.setCurrentText("device") + self.set_x_mode() + self.ui.x_name.setText(name) + self.ui.x_entry.setText(entry) + + @Slot() + def set_x_mode(self): + x_mode = self.ui.x_mode.currentText() + if x_mode in ["index", "timestamp", "best_effort"]: + self.ui.x_name.setEnabled(False) + self.ui.x_entry.setEnabled(False) + else: + self.ui.x_name.setEnabled(True) + self.ui.x_entry.setEnabled(True) + @Slot() def accept_changes(self): self.accept_scan_curve_changes() @@ -52,8 +76,17 @@ class CurveSettings(SettingWidget): self.get_curve_params() def get_curve_params(self): - x_name = self.ui.x_name.text() - x_entry = self.ui.x_entry.text() + x_mode = self.ui.x_mode.currentText() + + if x_mode in ["index", "timestamp", "best_effort"]: + x_name = x_mode + x_entry = x_mode + else: + x_name = self.ui.x_name.text() + x_entry = self.ui.x_entry.text() + + self.target_widget.set_x(x_name=x_name, x_entry=x_entry) + for row in range(self.ui.scan_table.rowCount()): y_name = self.ui.scan_table.cellWidget(row, 0).text() y_entry = self.ui.scan_table.cellWidget(row, 1).text() @@ -62,8 +95,6 @@ class CurveSettings(SettingWidget): width = self.ui.scan_table.cellWidget(row, 4).value() symbol_size = self.ui.scan_table.cellWidget(row, 5).value() self.target_widget.plot( - x_name=x_name, - x_entry=x_entry, y_name=y_name, y_entry=y_entry, color=color, diff --git a/bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/curve_dialog.ui b/bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/curve_dialog.ui index 32df4fa1..437169d5 100644 --- a/bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/curve_dialog.ui +++ b/bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/curve_dialog.ui @@ -31,7 +31,67 @@ X Axis - + + + + + X Axis Mode + + + + + + + + best_effort + + + + + device + + + + + index + + + + + timestamp + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + QFrame::Shadow::Sunken + + + 1 + + + 0 + + + Qt::Orientation::Vertical + + + diff --git a/bec_widgets/widgets/waveform/waveform_widget.py b/bec_widgets/widgets/waveform/waveform_widget.py index f59f639d..dac4b99c 100644 --- a/bec_widgets/widgets/waveform/waveform_widget.py +++ b/bec_widgets/widgets/waveform/waveform_widget.py @@ -124,7 +124,9 @@ class BECWaveformWidget(BECConnector, QWidget): dialog.resize(800, 600) dialog.exec() - def _check_if_scans_have_same_x(self, enabled=True, x_name_to_check: str = None) -> bool: + def _check_if_scans_have_same_x( + self, enabled=True, x_name_to_check: str = None + ) -> bool: # TODO probably not needed anymore """ Check if all scans have the same x-axis. @@ -173,6 +175,20 @@ class BECWaveformWidget(BECConnector, QWidget): """ return self.waveform.get_curve(identifier) + def set_x(self, x_name: str, x_entry: str | None = None): + """ + Change the x axis of the plot widget. + + Args: + x_name(str): Name of the x signal. + - "best_effort": Use the best effort signal. + - "timestamp": Use the timestamp signal. + - "index": Use the index signal. + - Custom signal name of device from BEC. + x_entry(str): Entry of the x signal. + """ + self.waveform.set_x(x_name, x_entry) + def plot( self, x: list | np.ndarray | None = None, @@ -210,7 +226,7 @@ class BECWaveformWidget(BECConnector, QWidget): Returns: BECCurve: The curve object. """ - self._check_if_scans_have_same_x(enabled=True, x_name_to_check=x_name) + # self._check_if_scans_have_same_x(enabled=True, x_name_to_check=x_name) return self.waveform.plot( x=x, y=y,