diff --git a/bec_widgets/cli/client.py b/bec_widgets/cli/client.py index 75f147fd..2e77cbcb 100644 --- a/bec_widgets/cli/client.py +++ b/bec_widgets/cli/client.py @@ -615,6 +615,12 @@ class BECFigure(RPCBase): theme(Literal["dark","light"]): The theme to set for the figure widget. """ + @rpc_call + def export(self): + """ + Export the plot widget. + """ + @rpc_call def clear_all(self): """ @@ -1097,6 +1103,12 @@ class BECImageShow(RPCBase): lock(bool): True to lock, False to unlock. """ + @rpc_call + def export(self): + """ + Show the Export Dialog of the plot widget. + """ + @rpc_call def remove(self): """ @@ -1205,6 +1217,12 @@ class BECMotorMap(RPCBase): dict: Data of the motor map. """ + @rpc_call + def export(self): + """ + Show the Export Dialog of the plot widget. + """ + @rpc_call def remove(self): """ @@ -1299,6 +1317,12 @@ class BECMotorMapWidget(RPCBase): Reset the history of the motor map. """ + @rpc_call + def export(self): + """ + Show the export dialog for the motor map. + """ + class BECPlotBase(RPCBase): @property @@ -1427,6 +1451,12 @@ class BECPlotBase(RPCBase): lock(bool): True to lock, False to unlock. """ + @rpc_call + def export(self): + """ + Show the Export Dialog of the plot widget. + """ + @rpc_call def remove(self): """ @@ -1773,6 +1803,12 @@ class BECWaveform(RPCBase): lock(bool): True to lock, False to unlock. """ + @rpc_call + def export(self): + """ + Show the Export Dialog of the plot widget. + """ + @rpc_call def remove(self): """ @@ -1806,38 +1842,15 @@ class BECWaveformWidget(RPCBase): """ @rpc_call - def plot(widget, *args, **kwargs): + def plot(*args, **kwargs): """ None """ @rpc_call - def add_dap( - self, - x_name: "str", - y_name: "str", - x_entry: "str | None" = None, - y_entry: "str | None" = None, - color: "str | None" = None, - dap: "str" = "GaussianModel", - validate_bec: "bool" = True, - **kwargs, - ) -> "BECCurve": + def add_dap(*args, **kwargs): """ - Add LMFIT dap model curve to the plot widget. - - Args: - x_name(str): Name of the x signal. - x_entry(str): Entry of the x signal. - y_name(str): Name of the y signal. - y_entry(str): Entry of the y signal. - color(str, optional): Color 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. + None """ @rpc_call @@ -1991,6 +2004,12 @@ class BECWaveformWidget(RPCBase): lock(bool): Lock the aspect ratio. """ + @rpc_call + def export(self): + """ + Show the export dialog for the plot widget. + """ + class DeviceBox(RPCBase): @property diff --git a/bec_widgets/widgets/figure/figure.py b/bec_widgets/widgets/figure/figure.py index f2d67910..50272519 100644 --- a/bec_widgets/widgets/figure/figure.py +++ b/bec_widgets/widgets/figure/figure.py @@ -122,6 +122,7 @@ class BECFigure(BECWidget, pg.GraphicsLayoutWidget): "remove", "change_layout", "change_theme", + "export", "clear_all", "widget_list", ] @@ -228,6 +229,17 @@ class BECFigure(BECWidget, pg.GraphicsLayoutWidget): """ self._widgets = value + def export(self): + """Export the plot widget.""" + try: + plot_item = self.widget_list[0] + except: + raise ValueError("No plot widget available to export.") + + scene = plot_item.scene() + scene.contextMenuItem = plot_item + scene.showExportDialog() + @typechecked def plot( self, diff --git a/bec_widgets/widgets/figure/plots/image/image.py b/bec_widgets/widgets/figure/plots/image/image.py index b10e02c5..151b64bf 100644 --- a/bec_widgets/widgets/figure/plots/image/image.py +++ b/bec_widgets/widgets/figure/plots/image/image.py @@ -55,6 +55,7 @@ class BECImageShow(BECPlotBase): "set_y_lim", "set_grid", "lock_aspect_ratio", + "export", "remove", "images", ] diff --git a/bec_widgets/widgets/figure/plots/motor_map/motor_map.py b/bec_widgets/widgets/figure/plots/motor_map/motor_map.py index 1c708da0..b896cb0b 100644 --- a/bec_widgets/widgets/figure/plots/motor_map/motor_map.py +++ b/bec_widgets/widgets/figure/plots/motor_map/motor_map.py @@ -58,6 +58,7 @@ class BECMotorMap(BECPlotBase): "set_background_value", "set_scatter_size", "get_data", + "export", "remove", "reset_history", ] diff --git a/bec_widgets/widgets/figure/plots/plot_base.py b/bec_widgets/widgets/figure/plots/plot_base.py index 3260712c..40569167 100644 --- a/bec_widgets/widgets/figure/plots/plot_base.py +++ b/bec_widgets/widgets/figure/plots/plot_base.py @@ -4,6 +4,7 @@ from typing import Literal, Optional import pyqtgraph as pg from pydantic import BaseModel, Field +from pyqtgraph.GraphicsScene.exportDialog import ExportDialog from qtpy.QtWidgets import QWidget from bec_widgets.utils import BECConnector, ConnectionConfig @@ -54,6 +55,7 @@ class BECPlotBase(BECConnector, pg.GraphicsLayout): "set_y_lim", "set_grid", "lock_aspect_ratio", + "export", "remove", "set_legend_label_size", ] @@ -290,6 +292,12 @@ class BECPlotBase(BECConnector, pg.GraphicsLayout): """ self.plot_item.setAspectLocked(lock) + def export(self): + """Show the Export Dialog of the plot widget.""" + scene = self.plot_item.scene() + scene.contextMenuItem = self.plot_item + scene.showExportDialog() + def remove(self): """Remove the plot widget from the figure.""" if self.figure is not None: diff --git a/bec_widgets/widgets/figure/plots/waveform/waveform.py b/bec_widgets/widgets/figure/plots/waveform/waveform.py index 3a538677..47f3f7e6 100644 --- a/bec_widgets/widgets/figure/plots/waveform/waveform.py +++ b/bec_widgets/widgets/figure/plots/waveform/waveform.py @@ -66,6 +66,7 @@ class BECWaveform(BECPlotBase): "set_grid", "set_colormap", "lock_aspect_ratio", + "export", "remove", "clear_all", "set_legend_label_size", diff --git a/bec_widgets/widgets/motor_map/motor_map_widget.py b/bec_widgets/widgets/motor_map/motor_map_widget.py index 1b5211a1..cea70cad 100644 --- a/bec_widgets/widgets/motor_map/motor_map_widget.py +++ b/bec_widgets/widgets/motor_map/motor_map_widget.py @@ -28,6 +28,7 @@ class BECMotorMapWidget(BECWidget, QWidget): "set_scatter_size", "get_data", "reset_history", + "export", ] def __init__( @@ -202,6 +203,12 @@ class BECMotorMapWidget(BECWidget, QWidget): """ self.map.set_scatter_size(scatter_size) + def export(self): + """ + Show the export dialog for the motor map. + """ + self.map.export() + def cleanup(self): self.fig.cleanup() self.toolbar.widgets["motor_x"].device_combobox.cleanup() diff --git a/bec_widgets/widgets/waveform/waveform_toolbar/waveform_toolbar.py b/bec_widgets/widgets/waveform/waveform_toolbar/waveform_toolbar.py index 92df5bb5..1012e2ac 100644 --- a/bec_widgets/widgets/waveform/waveform_toolbar/waveform_toolbar.py +++ b/bec_widgets/widgets/waveform/waveform_toolbar/waveform_toolbar.py @@ -9,6 +9,16 @@ from bec_widgets.qt_utils.toolbar import ToolBarAction MODULE_PATH = os.path.dirname(bec_widgets.__file__) +class SaveAction(ToolBarAction): + def add_to_toolbar(self, toolbar, target): + icon = QIcon() + icon.addFile( + os.path.join(MODULE_PATH, "assets", "toolbar_icons", "save.svg"), size=QSize(20, 20) + ) + self.action = QAction(icon, "Open Export Dialog", target) + toolbar.addAction(self.action) + + class CurveAction(ToolBarAction): def add_to_toolbar(self, toolbar, target): icon = QIcon() diff --git a/bec_widgets/widgets/waveform/waveform_widget.py b/bec_widgets/widgets/waveform/waveform_widget.py index 6d0720bd..02143365 100644 --- a/bec_widgets/widgets/waveform/waveform_widget.py +++ b/bec_widgets/widgets/waveform/waveform_widget.py @@ -43,6 +43,7 @@ class BECWaveformWidget(BECConnector, QWidget): "set_legend_label_size", "set_grid", "lock_aspect_ratio", + "export", ] def __init__( @@ -67,6 +68,7 @@ class BECWaveformWidget(BECConnector, QWidget): self.fig = BECFigure() self.toolbar = ModularToolBar( actions={ + "save": SaveAction(), "separator_1": SeparatorAction(), "curves": CurveAction(), "axis_settings": SettingsAction(), @@ -93,6 +95,7 @@ class BECWaveformWidget(BECConnector, QWidget): self.plot(x_name="samx", y_name="bpm6i") def _hook_actions(self): + self.toolbar.widgets["save"].action.triggered.connect(self.export) self.toolbar.widgets["curves"].action.triggered.connect(self.show_curve_settings) self.toolbar.widgets["axis_settings"].action.triggered.connect(self.show_axis_settings) self.toolbar.widgets["import"].action.triggered.connect( @@ -458,6 +461,12 @@ class BECWaveformWidget(BECConnector, QWidget): """ self.waveform.lock_aspect_ratio(lock) + def export(self): + """ + Show the export dialog for the plot widget. + """ + self.waveform.export() + ####################################### # User Access Methods from BECConnector ######################################