bec-widgets 1.25.1__py3-none-any.whl → 2.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- .gitlab-ci.yml +3 -5
- CHANGELOG.md +639 -0
- PKG-INFO +3 -3
- bec_widgets/__init__.py +4 -0
- bec_widgets/applications/bw_launch.py +23 -0
- bec_widgets/applications/launch_window.py +430 -0
- bec_widgets/assets/app_icons/auto_update.png +0 -0
- bec_widgets/assets/app_icons/ui_loader_tile.png +0 -0
- bec_widgets/cli/__init__.py +0 -1
- bec_widgets/cli/client.py +1779 -2064
- bec_widgets/cli/client_utils.py +346 -174
- bec_widgets/cli/generate_cli.py +143 -37
- bec_widgets/cli/rpc/rpc_base.py +152 -21
- bec_widgets/cli/rpc/rpc_register.py +113 -6
- bec_widgets/cli/rpc/rpc_widget_handler.py +13 -11
- bec_widgets/cli/server.py +125 -239
- bec_widgets/examples/jupyter_console/jupyter_console_window.py +97 -145
- bec_widgets/examples/plugin_example_pyside/tictactoetaskmenu.py +1 -1
- bec_widgets/utils/bec_connector.py +190 -21
- bec_widgets/utils/bec_designer.py +7 -0
- bec_widgets/utils/bec_dispatcher.py +71 -4
- bec_widgets/utils/bec_plugin_helper.py +89 -0
- bec_widgets/utils/bec_signal_proxy.py +1 -1
- bec_widgets/utils/bec_widget.py +26 -10
- bec_widgets/utils/colors.py +1 -1
- bec_widgets/{qt_utils → utils}/compact_popup.py +2 -0
- bec_widgets/utils/container_utils.py +37 -12
- bec_widgets/utils/crosshair.py +25 -8
- bec_widgets/utils/entry_validator.py +3 -1
- bec_widgets/{qt_utils → utils}/error_popups.py +18 -0
- bec_widgets/{qt_utils → utils}/expandable_frame.py +2 -2
- bec_widgets/utils/forms_from_types/forms.py +182 -0
- bec_widgets/{widgets/editors/scan_metadata/_metadata_widgets.py → utils/forms_from_types/items.py} +41 -30
- bec_widgets/utils/generate_designer_plugin.py +40 -36
- bec_widgets/utils/linear_region_selector.py +2 -0
- bec_widgets/utils/name_utils.py +16 -0
- bec_widgets/{qt_utils → utils}/palette_viewer.py +2 -2
- bec_widgets/utils/plot_indicator_items.py +2 -5
- bec_widgets/utils/plugin_utils.py +47 -1
- bec_widgets/{qt_utils → utils}/round_frame.py +14 -14
- bec_widgets/utils/rpc_server.py +277 -0
- bec_widgets/utils/serialization.py +44 -0
- bec_widgets/{qt_utils → utils}/settings_dialog.py +26 -1
- bec_widgets/{qt_utils → utils}/side_panel.py +17 -10
- bec_widgets/{qt_utils → utils}/toolbar.py +69 -25
- bec_widgets/utils/ui_loader.py +8 -8
- bec_widgets/utils/widget_io.py +166 -25
- bec_widgets/widgets/containers/auto_update/auto_updates.py +364 -0
- bec_widgets/widgets/containers/dock/dock.py +157 -49
- bec_widgets/widgets/containers/dock/dock_area.py +188 -138
- bec_widgets/widgets/containers/layout_manager/layout_manager.py +2 -1
- bec_widgets/widgets/containers/main_window/addons/web_links.py +15 -0
- bec_widgets/widgets/containers/main_window/main_window.py +189 -41
- bec_widgets/widgets/control/buttons/button_abort/button_abort.py +3 -4
- bec_widgets/widgets/control/buttons/button_reset/button_reset.py +3 -4
- bec_widgets/widgets/control/buttons/button_resume/button_resume.py +3 -3
- bec_widgets/widgets/control/buttons/stop_button/stop_button.py +18 -7
- bec_widgets/widgets/control/device_control/position_indicator/position_indicator.py +22 -3
- bec_widgets/widgets/control/device_control/positioner_box/_base/positioner_box_base.py +31 -13
- bec_widgets/widgets/control/device_control/positioner_box/positioner_box/positioner_box.py +3 -1
- bec_widgets/widgets/control/device_control/positioner_box/positioner_box/positioner_box.ui +27 -4
- bec_widgets/widgets/control/device_control/positioner_box/positioner_box_2d/positioner_box_2d.py +5 -2
- bec_widgets/widgets/control/device_control/positioner_box/positioner_box_2d/positioner_box_2d.ui +97 -31
- bec_widgets/widgets/control/device_control/positioner_box/positioner_control_line/positioner_control_line.ui +11 -4
- bec_widgets/widgets/control/device_control/positioner_group/positioner_group.py +2 -3
- bec_widgets/widgets/control/device_input/base_classes/device_input_base.py +29 -4
- bec_widgets/widgets/control/device_input/base_classes/device_signal_input_base.py +1 -0
- bec_widgets/widgets/control/device_input/device_combobox/device_combobox.py +2 -2
- bec_widgets/widgets/control/device_input/device_line_edit/device_line_edit.py +2 -2
- bec_widgets/widgets/control/device_input/signal_combobox/signal_combobox.py +1 -2
- bec_widgets/widgets/control/device_input/signal_line_edit/signal_line_edit.py +1 -2
- bec_widgets/widgets/control/scan_control/scan_control.py +7 -5
- bec_widgets/widgets/control/scan_control/scan_group_box.py +28 -5
- bec_widgets/widgets/dap/dap_combo_box/dap_combo_box.py +1 -2
- bec_widgets/widgets/dap/lmfit_dialog/lmfit_dialog.py +3 -4
- bec_widgets/widgets/dap/lmfit_dialog/lmfit_dialog_vertical.ui +14 -8
- bec_widgets/widgets/editors/console/console.py +1 -1
- bec_widgets/widgets/editors/{scan_metadata/additional_metadata_table.py → dict_backed_table.py} +29 -6
- bec_widgets/widgets/editors/scan_metadata/__init__.py +0 -7
- bec_widgets/widgets/editors/scan_metadata/_util.py +1 -1
- bec_widgets/widgets/{plots/motor_map/register_bec_motor_map_widget.py → editors/scan_metadata/register_scan_metadata.py} +2 -4
- bec_widgets/widgets/editors/scan_metadata/scan_metadata.py +42 -136
- bec_widgets/widgets/editors/scan_metadata/scan_metadata.pyproject +1 -0
- bec_widgets/widgets/{plots/multi_waveform/bec_multi_waveform_widget_plugin.py → editors/scan_metadata/scan_metadata_plugin.py} +9 -9
- bec_widgets/widgets/editors/text_box/text_box.py +2 -3
- bec_widgets/widgets/editors/website/website.py +2 -2
- bec_widgets/widgets/games/minesweeper.py +3 -2
- bec_widgets/widgets/plots/image/image.py +960 -0
- bec_widgets/widgets/plots/image/image.pyproject +1 -0
- bec_widgets/widgets/plots/image/image_item.py +279 -0
- bec_widgets/widgets/plots/{motor_map/bec_motor_map_widget_plugin.py → image/image_plugin.py} +11 -13
- bec_widgets/widgets/{containers/figure/plots → plots}/image/image_processor.py +31 -64
- bec_widgets/widgets/plots/image/{register_bec_image_widget.py → register_image.py} +2 -2
- bec_widgets/widgets/plots/image/toolbar_bundles/image_selection.py +59 -0
- bec_widgets/widgets/plots/image/toolbar_bundles/processing.py +79 -0
- bec_widgets/widgets/plots/motor_map/motor_map.py +832 -0
- bec_widgets/widgets/plots/motor_map/motor_map.pyproject +1 -0
- bec_widgets/widgets/plots/motor_map/motor_map_plugin.py +54 -0
- bec_widgets/widgets/plots/{multi_waveform/register_bec_multi_waveform_widget.py → motor_map/register_motor_map.py} +2 -4
- bec_widgets/widgets/plots/motor_map/settings/motor_map_settings.py +129 -0
- bec_widgets/widgets/plots/motor_map/settings/motor_map_settings.ui +120 -0
- bec_widgets/widgets/plots/motor_map/toolbar_bundles/motor_selection.py +70 -0
- bec_widgets/widgets/plots/multi_waveform/multi_waveform.py +508 -0
- bec_widgets/widgets/plots/multi_waveform/multi_waveform.pyproject +1 -0
- bec_widgets/widgets/plots/multi_waveform/multi_waveform_plugin.py +54 -0
- bec_widgets/widgets/plots/multi_waveform/register_multi_waveform.py +15 -0
- bec_widgets/widgets/plots/multi_waveform/settings/control_panel.py +144 -0
- bec_widgets/widgets/plots/multi_waveform/settings/multi_waveform_controls.ui +164 -0
- bec_widgets/widgets/plots/multi_waveform/toolbar_bundles/monitor_selection.py +65 -0
- bec_widgets/widgets/{plots_next_gen → plots}/plot_base.py +321 -40
- bec_widgets/widgets/plots/{waveform/register_bec_waveform_widget.py → scatter_waveform/register_scatter_waveform.py} +3 -3
- bec_widgets/widgets/plots/scatter_waveform/scatter_curve.py +197 -0
- bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.py +553 -0
- bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.pyproject +1 -0
- bec_widgets/widgets/plots/{image/bec_image_widget_plugin.py → scatter_waveform/scatter_waveform_plugin.py} +9 -13
- bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_setting.py +138 -0
- bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_horizontal.ui +195 -0
- bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_vertical.ui +204 -0
- bec_widgets/widgets/{plots_next_gen → plots}/setting_menus/axis_settings.py +8 -8
- bec_widgets/widgets/{plots_next_gen → plots}/toolbar_bundles/mouse_interactions.py +4 -18
- bec_widgets/widgets/{plots_next_gen → plots}/toolbar_bundles/plot_export.py +14 -3
- bec_widgets/widgets/{plots_next_gen → plots}/toolbar_bundles/roi_bundle.py +6 -1
- bec_widgets/widgets/{plots_next_gen → plots}/toolbar_bundles/save_state.py +2 -2
- bec_widgets/widgets/{containers/figure/plots/waveform/waveform_curve.py → plots/waveform/curve.py} +119 -49
- bec_widgets/widgets/plots/waveform/register_waveform.py +15 -0
- bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_setting.py +125 -0
- bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_tree.py +576 -0
- bec_widgets/widgets/plots/waveform/utils/__init__.py +0 -0
- bec_widgets/widgets/plots/waveform/utils/roi_manager.py +84 -0
- bec_widgets/widgets/plots/waveform/waveform.py +1794 -0
- bec_widgets/widgets/plots/waveform/waveform.pyproject +1 -0
- bec_widgets/widgets/plots/waveform/{bec_waveform_widget_plugin.py → waveform_plugin.py} +9 -13
- bec_widgets/widgets/progress/bec_progressbar/bec_progressbar.py +1 -2
- bec_widgets/widgets/progress/ring_progress_bar/ring.py +11 -10
- bec_widgets/widgets/progress/ring_progress_bar/ring_progress_bar.py +24 -14
- bec_widgets/widgets/services/bec_queue/bec_queue.py +13 -11
- bec_widgets/widgets/services/bec_status_box/bec_status_box.py +3 -4
- bec_widgets/widgets/services/device_browser/device_browser.py +5 -2
- bec_widgets/widgets/services/device_browser/device_item/device_item.py +1 -1
- bec_widgets/widgets/utility/logpanel/logpanel.py +36 -17
- bec_widgets/widgets/utility/spinbox/decimal_spinbox.py +3 -3
- bec_widgets/widgets/utility/visual/color_button/color_button.py +1 -1
- bec_widgets/widgets/utility/visual/colormap_widget/colormap_widget.py +4 -6
- bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.py +4 -8
- {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.dist-info}/METADATA +3 -3
- {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.dist-info}/RECORD +168 -153
- pyproject.toml +3 -3
- bec_widgets/applications/alignment/alignment_1d/alignment_1d.py +0 -198
- bec_widgets/applications/alignment/alignment_1d/alignment_1d.ui +0 -615
- bec_widgets/applications/bec_app.py +0 -84
- bec_widgets/cli/auto_updates.py +0 -168
- bec_widgets/widgets/containers/figure/__init__.py +0 -1
- bec_widgets/widgets/containers/figure/figure.py +0 -796
- bec_widgets/widgets/containers/figure/plots/axis_settings.py +0 -91
- bec_widgets/widgets/containers/figure/plots/axis_settings.ui +0 -256
- bec_widgets/widgets/containers/figure/plots/image/image.py +0 -772
- bec_widgets/widgets/containers/figure/plots/image/image_item.py +0 -337
- bec_widgets/widgets/containers/figure/plots/motor_map/motor_map.py +0 -525
- bec_widgets/widgets/containers/figure/plots/multi_waveform/multi_waveform.py +0 -340
- bec_widgets/widgets/containers/figure/plots/plot_base.py +0 -505
- bec_widgets/widgets/containers/figure/plots/waveform/waveform.py +0 -1563
- bec_widgets/widgets/plots/image/bec_image_widget.pyproject +0 -1
- bec_widgets/widgets/plots/image/image_widget.py +0 -515
- bec_widgets/widgets/plots/motor_map/bec_motor_map_widget.pyproject +0 -1
- bec_widgets/widgets/plots/motor_map/motor_map_dialog/motor_map_settings.py +0 -56
- bec_widgets/widgets/plots/motor_map/motor_map_dialog/motor_map_settings.ui +0 -108
- bec_widgets/widgets/plots/motor_map/motor_map_widget.py +0 -234
- bec_widgets/widgets/plots/multi_waveform/bec_multi_waveform_widget.pyproject +0 -1
- bec_widgets/widgets/plots/multi_waveform/multi_waveform_controls.ui +0 -99
- bec_widgets/widgets/plots/multi_waveform/multi_waveform_widget.py +0 -536
- bec_widgets/widgets/plots/waveform/bec_waveform_widget.pyproject +0 -1
- bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.py +0 -336
- bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.ui +0 -372
- bec_widgets/widgets/plots/waveform/waveform_popups/dap_summary_dialog/dap_summary_dialog.py +0 -25
- bec_widgets/widgets/plots/waveform/waveform_widget.py +0 -751
- /bec_widgets/{qt_utils → utils}/collapsible_panel_manager.py +0 -0
- /bec_widgets/{applications/alignment → utils/forms_from_types}/__init__.py +0 -0
- /bec_widgets/{qt_utils → utils}/redis_message_waiter.py +0 -0
- /bec_widgets/{applications/alignment/alignment_1d → widgets/containers/auto_update}/__init__.py +0 -0
- /bec_widgets/{qt_utils → widgets/containers/main_window/addons}/__init__.py +0 -0
- /bec_widgets/widgets/{containers/figure/plots → plots/image/toolbar_bundles}/__init__.py +0 -0
- /bec_widgets/widgets/{containers/figure/plots/image → plots/motor_map/settings}/__init__.py +0 -0
- /bec_widgets/widgets/{containers/figure/plots/motor_map → plots/motor_map/toolbar_bundles}/__init__.py +0 -0
- /bec_widgets/widgets/{containers/figure/plots/multi_waveform → plots/multi_waveform/settings}/__init__.py +0 -0
- /bec_widgets/widgets/{containers/figure/plots/waveform → plots/multi_waveform/toolbar_bundles}/__init__.py +0 -0
- /bec_widgets/widgets/plots/{motor_map/motor_map_dialog → scatter_waveform}/__init__.py +0 -0
- /bec_widgets/widgets/plots/{waveform/waveform_popups → scatter_waveform/settings}/__init__.py +0 -0
- /bec_widgets/widgets/plots/{waveform/waveform_popups/curve_dialog → setting_menus}/__init__.py +0 -0
- /bec_widgets/widgets/{plots_next_gen → plots}/setting_menus/axis_settings_horizontal.ui +0 -0
- /bec_widgets/widgets/{plots_next_gen → plots}/setting_menus/axis_settings_vertical.ui +0 -0
- /bec_widgets/widgets/plots/{waveform/waveform_popups/dap_summary_dialog → toolbar_bundles}/__init__.py +0 -0
- /bec_widgets/widgets/{plots_next_gen/setting_menus → plots/waveform/settings}/__init__.py +0 -0
- /bec_widgets/widgets/{plots_next_gen/toolbar_bundles → plots/waveform/settings/curve_settings}/__init__.py +0 -0
- {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.dist-info}/WHEEL +0 -0
- {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.dist-info}/entry_points.txt +0 -0
- {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,7 +1,9 @@
|
|
1
|
+
import traceback
|
2
|
+
|
1
3
|
from pyqtgraph.exporters import MatplotlibExporter
|
2
4
|
|
3
|
-
from bec_widgets.
|
4
|
-
from bec_widgets.
|
5
|
+
from bec_widgets.utils.error_popups import SafeSlot, WarningPopupUtility
|
6
|
+
from bec_widgets.utils.toolbar import MaterialIconAction, SwitchableToolBarAction, ToolbarBundle
|
5
7
|
|
6
8
|
|
7
9
|
class PlotExportBundle(ToolbarBundle):
|
@@ -60,7 +62,7 @@ class PlotExportBundle(ToolbarBundle):
|
|
60
62
|
import matplotlib as mpl
|
61
63
|
|
62
64
|
MatplotlibExporter(self.target_widget.plot_item).export()
|
63
|
-
except:
|
65
|
+
except ModuleNotFoundError:
|
64
66
|
warning_util = WarningPopupUtility()
|
65
67
|
warning_util.show_warning(
|
66
68
|
title="Matplotlib not installed",
|
@@ -68,3 +70,12 @@ class PlotExportBundle(ToolbarBundle):
|
|
68
70
|
detailed_text="Please install matplotlib in your Python environment by using 'pip install matplotlib'.",
|
69
71
|
)
|
70
72
|
return
|
73
|
+
except TypeError:
|
74
|
+
warning_util = WarningPopupUtility()
|
75
|
+
error_msg = traceback.format_exc()
|
76
|
+
warning_util.show_warning(
|
77
|
+
title="Matplotlib TypeError",
|
78
|
+
message="Matplotlib exporter could not resolve the plot item.",
|
79
|
+
detailed_text=error_msg,
|
80
|
+
)
|
81
|
+
return
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from bec_widgets.
|
1
|
+
from bec_widgets.utils.toolbar import MaterialIconAction, ToolbarBundle
|
2
2
|
|
3
3
|
|
4
4
|
class ROIBundle(ToolbarBundle):
|
@@ -18,9 +18,14 @@ class ROIBundle(ToolbarBundle):
|
|
18
18
|
crosshair = MaterialIconAction(
|
19
19
|
icon_name="point_scan", tooltip="Show Crosshair", checkable=True
|
20
20
|
)
|
21
|
+
reset_legend = MaterialIconAction(
|
22
|
+
icon_name="restart_alt", tooltip="Reset the position of legend.", checkable=False
|
23
|
+
)
|
21
24
|
|
22
25
|
# Add them to the bundle
|
23
26
|
self.add_action("crosshair", crosshair)
|
27
|
+
self.add_action("reset_legend", reset_legend)
|
24
28
|
|
25
29
|
# Immediately connect signals
|
26
30
|
crosshair.action.toggled.connect(self.target_widget.toggle_crosshair)
|
31
|
+
reset_legend.action.triggered.connect(self.target_widget.reset_legend)
|
@@ -1,5 +1,5 @@
|
|
1
|
-
from bec_widgets.
|
2
|
-
from bec_widgets.
|
1
|
+
from bec_widgets.utils.error_popups import SafeSlot
|
2
|
+
from bec_widgets.utils.toolbar import MaterialIconAction, ToolbarBundle
|
3
3
|
|
4
4
|
|
5
5
|
class SaveStateBundle(ToolbarBundle):
|
bec_widgets/widgets/{containers/figure/plots/waveform/waveform_curve.py → plots/waveform/curve.py}
RENAMED
@@ -1,75 +1,67 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
from typing import TYPE_CHECKING, Literal
|
3
|
+
from typing import TYPE_CHECKING, Literal
|
4
4
|
|
5
5
|
import numpy as np
|
6
6
|
import pyqtgraph as pg
|
7
|
-
from bec_lib
|
7
|
+
from bec_lib import bec_logger
|
8
8
|
from pydantic import BaseModel, Field, field_validator
|
9
9
|
from qtpy import QtCore
|
10
10
|
|
11
11
|
from bec_widgets.utils import BECConnector, Colors, ConnectionConfig
|
12
12
|
|
13
|
-
if TYPE_CHECKING:
|
14
|
-
from bec_widgets.widgets.
|
13
|
+
if TYPE_CHECKING: # pragma: no cover
|
14
|
+
from bec_widgets.widgets.plots.waveform.waveform import Waveform
|
15
15
|
|
16
16
|
logger = bec_logger.logger
|
17
17
|
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
# noinspection PyDataclass
|
20
|
+
class DeviceSignal(BaseModel):
|
21
|
+
"""The configuration of a signal in the 1D waveform widget."""
|
21
22
|
|
22
23
|
name: str
|
23
24
|
entry: str
|
24
|
-
|
25
|
-
|
26
|
-
limits: Optional[list[float]] = None # todo implement later
|
27
|
-
model_config: dict = {"validate_assignment": True}
|
25
|
+
dap: str | None = None
|
26
|
+
dap_oversample: int = 1
|
28
27
|
|
29
|
-
|
30
|
-
class Signal(BaseModel):
|
31
|
-
"""The configuration of a signal in the 1D waveform widget."""
|
32
|
-
|
33
|
-
source: str
|
34
|
-
x: Optional[SignalData] = None
|
35
|
-
y: SignalData
|
36
|
-
z: Optional[SignalData] = None
|
37
|
-
dap: Optional[str] = None
|
38
28
|
model_config: dict = {"validate_assignment": True}
|
39
29
|
|
40
30
|
|
31
|
+
# noinspection PyDataclass
|
41
32
|
class CurveConfig(ConnectionConfig):
|
42
|
-
parent_id:
|
43
|
-
label:
|
44
|
-
color:
|
45
|
-
symbol:
|
46
|
-
symbol_color:
|
33
|
+
parent_id: str | None = Field(None, description="The parent plot of the curve.")
|
34
|
+
label: str | None = Field(None, description="The label of the curve.")
|
35
|
+
color: str | tuple | None = Field(None, description="The color of the curve.")
|
36
|
+
symbol: str | None = Field("o", description="The symbol of the curve.")
|
37
|
+
symbol_color: str | tuple | None = Field(
|
47
38
|
None, description="The color of the symbol of the curve."
|
48
39
|
)
|
49
|
-
symbol_size:
|
50
|
-
pen_width:
|
51
|
-
pen_style:
|
40
|
+
symbol_size: int | None = Field(7, description="The size of the symbol of the curve.")
|
41
|
+
pen_width: int | None = Field(4, description="The width of the pen of the curve.")
|
42
|
+
pen_style: Literal["solid", "dash", "dot", "dashdot"] | None = Field(
|
52
43
|
"solid", description="The style of the pen of the curve."
|
53
44
|
)
|
54
|
-
source:
|
55
|
-
|
56
|
-
|
57
|
-
|
45
|
+
source: Literal["device", "dap", "custom"] = Field(
|
46
|
+
"custom", description="The source of the curve."
|
47
|
+
)
|
48
|
+
signal: DeviceSignal | None = Field(None, description="The signal of the curve.")
|
49
|
+
parent_label: str | None = Field(
|
50
|
+
None, description="The label of the parent plot, only relevant for dap curves."
|
58
51
|
)
|
59
52
|
|
60
53
|
model_config: dict = {"validate_assignment": True}
|
61
54
|
|
62
|
-
_validate_color_map_z = field_validator("color_map_z")(Colors.validate_color_map)
|
63
55
|
_validate_color = field_validator("color")(Colors.validate_color)
|
64
56
|
_validate_symbol_color = field_validator("symbol_color")(Colors.validate_color)
|
65
57
|
|
66
58
|
|
67
|
-
class
|
59
|
+
class Curve(BECConnector, pg.PlotDataItem):
|
68
60
|
USER_ACCESS = [
|
69
61
|
"remove",
|
70
|
-
"dap_params",
|
71
62
|
"_rpc_id",
|
72
63
|
"_config_dict",
|
64
|
+
"_get_displayed_data",
|
73
65
|
"set",
|
74
66
|
"set_data",
|
75
67
|
"set_color",
|
@@ -81,14 +73,17 @@ class BECCurve(BECConnector, pg.PlotDataItem):
|
|
81
73
|
"set_pen_style",
|
82
74
|
"get_data",
|
83
75
|
"dap_params",
|
76
|
+
"dap_summary",
|
77
|
+
"dap_oversample",
|
78
|
+
"dap_oversample.setter",
|
84
79
|
]
|
85
80
|
|
86
81
|
def __init__(
|
87
82
|
self,
|
88
|
-
name:
|
89
|
-
config:
|
90
|
-
gui_id:
|
91
|
-
parent_item:
|
83
|
+
name: str | None = None,
|
84
|
+
config: CurveConfig | None = None,
|
85
|
+
gui_id: str | None = None,
|
86
|
+
parent_item: Waveform | None = None,
|
92
87
|
**kwargs,
|
93
88
|
):
|
94
89
|
if config is None:
|
@@ -96,18 +91,35 @@ class BECCurve(BECConnector, pg.PlotDataItem):
|
|
96
91
|
self.config = config
|
97
92
|
else:
|
98
93
|
self.config = config
|
99
|
-
# config.widget_class = self.__class__.__name__
|
100
|
-
super().__init__(config=config, gui_id=gui_id, **kwargs)
|
101
|
-
pg.PlotDataItem.__init__(self, name=name)
|
102
|
-
|
103
94
|
self.parent_item = parent_item
|
95
|
+
object_name = name.replace("-", "_").replace(" ", "_") if name else None
|
96
|
+
super().__init__(name=name, object_name=object_name, config=config, gui_id=gui_id, **kwargs)
|
97
|
+
|
104
98
|
self.apply_config()
|
105
99
|
self.dap_params = None
|
106
100
|
self.dap_summary = None
|
101
|
+
self.slice_index = None
|
107
102
|
if kwargs:
|
108
103
|
self.set(**kwargs)
|
104
|
+
# Activate setClipToView, to boost performance for large datasets per default
|
105
|
+
self.setClipToView(True)
|
106
|
+
|
107
|
+
def parent(self):
|
108
|
+
return self.parent_item
|
109
|
+
|
110
|
+
def apply_config(self, config: dict | CurveConfig | None = None, **kwargs) -> None:
|
111
|
+
"""
|
112
|
+
Apply the configuration to the curve.
|
113
|
+
|
114
|
+
Args:
|
115
|
+
config(dict|CurveConfig, optional): The configuration to apply.
|
116
|
+
"""
|
117
|
+
|
118
|
+
if config is not None:
|
119
|
+
if isinstance(config, dict):
|
120
|
+
config = CurveConfig(**config)
|
121
|
+
self.config = config
|
109
122
|
|
110
|
-
def apply_config(self):
|
111
123
|
pen_style_map = {
|
112
124
|
"solid": QtCore.Qt.SolidLine,
|
113
125
|
"dash": QtCore.Qt.DashLine,
|
@@ -129,21 +141,64 @@ class BECCurve(BECConnector, pg.PlotDataItem):
|
|
129
141
|
|
130
142
|
@property
|
131
143
|
def dap_params(self):
|
144
|
+
"""
|
145
|
+
Get the dap parameters.
|
146
|
+
"""
|
132
147
|
return self._dap_params
|
133
148
|
|
134
149
|
@dap_params.setter
|
135
150
|
def dap_params(self, value):
|
151
|
+
"""
|
152
|
+
Set the dap parameters.
|
153
|
+
|
154
|
+
Args:
|
155
|
+
value(dict): The dap parameters.
|
156
|
+
"""
|
136
157
|
self._dap_params = value
|
137
158
|
|
138
159
|
@property
|
139
160
|
def dap_summary(self):
|
161
|
+
"""
|
162
|
+
Get the dap summary.
|
163
|
+
"""
|
140
164
|
return self._dap_report
|
141
165
|
|
142
166
|
@dap_summary.setter
|
143
167
|
def dap_summary(self, value):
|
168
|
+
"""
|
169
|
+
Set the dap summary.
|
170
|
+
"""
|
144
171
|
self._dap_report = value
|
145
172
|
|
146
|
-
|
173
|
+
@property
|
174
|
+
def dap_oversample(self):
|
175
|
+
"""
|
176
|
+
Get the dap oversample.
|
177
|
+
"""
|
178
|
+
return self.config.signal.dap_oversample
|
179
|
+
|
180
|
+
@dap_oversample.setter
|
181
|
+
def dap_oversample(self, value):
|
182
|
+
"""
|
183
|
+
Set the dap oversample.
|
184
|
+
|
185
|
+
Args:
|
186
|
+
value(int): The dap oversample.
|
187
|
+
"""
|
188
|
+
self.config.signal.dap_oversample = value
|
189
|
+
self.parent_item.request_dap() # do immediate request for dap update
|
190
|
+
|
191
|
+
def set_data(self, x: list | np.ndarray, y: list | np.ndarray):
|
192
|
+
"""
|
193
|
+
Set the data of the curve.
|
194
|
+
|
195
|
+
Args:
|
196
|
+
x(list|np.ndarray): The x data.
|
197
|
+
y(list|np.ndarray): The y data.
|
198
|
+
|
199
|
+
Raises:
|
200
|
+
ValueError: If the source is not custom.
|
201
|
+
"""
|
147
202
|
if self.config.source == "custom":
|
148
203
|
self.setData(x, y)
|
149
204
|
else:
|
@@ -181,7 +236,7 @@ class BECCurve(BECConnector, pg.PlotDataItem):
|
|
181
236
|
else:
|
182
237
|
logger.warning(f"Warning: '{key}' is not a recognized property.")
|
183
238
|
|
184
|
-
def set_color(self, color: str, symbol_color:
|
239
|
+
def set_color(self, color: str, symbol_color: str | None = None):
|
185
240
|
"""
|
186
241
|
Change the color of the curve.
|
187
242
|
|
@@ -253,25 +308,40 @@ class BECCurve(BECConnector, pg.PlotDataItem):
|
|
253
308
|
"""
|
254
309
|
self.config.color_map_z = colormap
|
255
310
|
self.apply_config()
|
256
|
-
self.parent_item.
|
311
|
+
self.parent_item.update_with_scan_history(-1)
|
257
312
|
|
258
|
-
def get_data(self) -> tuple[np.ndarray, np.ndarray]:
|
313
|
+
def get_data(self) -> tuple[np.ndarray | None, np.ndarray | None]:
|
259
314
|
"""
|
260
315
|
Get the data of the curve.
|
261
316
|
Returns:
|
262
317
|
tuple[np.ndarray,np.ndarray]: X and Y data of the curve.
|
263
318
|
"""
|
264
319
|
try:
|
265
|
-
x_data, y_data = self.
|
320
|
+
x_data, y_data = self.getOriginalDataset()
|
266
321
|
except TypeError:
|
267
322
|
x_data, y_data = np.array([]), np.array([])
|
268
323
|
return x_data, y_data
|
269
324
|
|
270
325
|
def clear_data(self):
|
326
|
+
"""
|
327
|
+
Clear the data of the curve.
|
328
|
+
"""
|
271
329
|
self.setData([], [])
|
272
330
|
|
273
331
|
def remove(self):
|
274
332
|
"""Remove the curve from the plot."""
|
275
333
|
# self.parent_item.removeItem(self)
|
276
334
|
self.parent_item.remove_curve(self.name())
|
277
|
-
|
335
|
+
super().remove()
|
336
|
+
|
337
|
+
def _get_displayed_data(self) -> tuple[np.ndarray, np.ndarray]:
|
338
|
+
"""
|
339
|
+
Get the displayed data of the curve.
|
340
|
+
|
341
|
+
Returns:
|
342
|
+
tuple[np.ndarray, np.ndarray]: The x and y data of the curve.
|
343
|
+
"""
|
344
|
+
x_data, y_data = self.getData()
|
345
|
+
if x_data is None or y_data is None:
|
346
|
+
return np.array([]), np.array([])
|
347
|
+
return x_data, y_data
|
@@ -0,0 +1,15 @@
|
|
1
|
+
def main(): # pragma: no cover
|
2
|
+
from qtpy import PYSIDE6
|
3
|
+
|
4
|
+
if not PYSIDE6:
|
5
|
+
print("PYSIDE6 is not available in the environment. Cannot patch designer.")
|
6
|
+
return
|
7
|
+
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
|
8
|
+
|
9
|
+
from bec_widgets.widgets.plots.waveform.waveform_plugin import WaveformPlugin
|
10
|
+
|
11
|
+
QPyDesignerCustomWidgetCollection.addCustomWidget(WaveformPlugin())
|
12
|
+
|
13
|
+
|
14
|
+
if __name__ == "__main__": # pragma: no cover
|
15
|
+
main()
|
@@ -0,0 +1,125 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from typing import TYPE_CHECKING
|
4
|
+
|
5
|
+
from qtpy.QtWidgets import (
|
6
|
+
QComboBox,
|
7
|
+
QGroupBox,
|
8
|
+
QHBoxLayout,
|
9
|
+
QLabel,
|
10
|
+
QLineEdit,
|
11
|
+
QSizePolicy,
|
12
|
+
QVBoxLayout,
|
13
|
+
QWidget,
|
14
|
+
)
|
15
|
+
|
16
|
+
from bec_widgets.utils.error_popups import SafeSlot
|
17
|
+
from bec_widgets.utils.settings_dialog import SettingWidget
|
18
|
+
from bec_widgets.widgets.control.device_input.device_line_edit.device_line_edit import (
|
19
|
+
DeviceLineEdit,
|
20
|
+
)
|
21
|
+
from bec_widgets.widgets.plots.waveform.settings.curve_settings.curve_tree import CurveTree
|
22
|
+
|
23
|
+
if TYPE_CHECKING: # pragma: no cover
|
24
|
+
from bec_widgets.widgets.plots.waveform.waveform import Waveform
|
25
|
+
|
26
|
+
|
27
|
+
class CurveSetting(SettingWidget):
|
28
|
+
def __init__(self, parent=None, target_widget: Waveform = None, *args, **kwargs):
|
29
|
+
super().__init__(parent=parent, *args, **kwargs)
|
30
|
+
self.setProperty("skip_settings", True)
|
31
|
+
self.target_widget = target_widget
|
32
|
+
|
33
|
+
self.layout = QVBoxLayout(self)
|
34
|
+
|
35
|
+
self._init_x_box()
|
36
|
+
self._init_y_box()
|
37
|
+
|
38
|
+
self.setFixedWidth(580) # TODO height is still debate
|
39
|
+
|
40
|
+
def _init_x_box(self):
|
41
|
+
self.x_axis_box = QGroupBox("X Axis")
|
42
|
+
self.x_axis_box.layout = QHBoxLayout(self.x_axis_box)
|
43
|
+
self.x_axis_box.layout.setContentsMargins(10, 10, 10, 10)
|
44
|
+
self.x_axis_box.layout.setSpacing(10)
|
45
|
+
|
46
|
+
self.mode_combo_label = QLabel("Mode")
|
47
|
+
self.mode_combo = QComboBox()
|
48
|
+
self.mode_combo.addItems(["auto", "index", "timestamp", "device"])
|
49
|
+
|
50
|
+
self.spacer = QWidget()
|
51
|
+
self.spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
52
|
+
|
53
|
+
self.device_x_label = QLabel("Device")
|
54
|
+
self.device_x = DeviceLineEdit(parent=self)
|
55
|
+
|
56
|
+
self.signal_x_label = QLabel("Signal")
|
57
|
+
self.signal_x = QLineEdit()
|
58
|
+
|
59
|
+
self._get_x_mode_from_waveform()
|
60
|
+
self.switch_x_device_selection()
|
61
|
+
|
62
|
+
self.mode_combo.currentTextChanged.connect(self.switch_x_device_selection)
|
63
|
+
|
64
|
+
self.x_axis_box.layout.addWidget(self.mode_combo_label)
|
65
|
+
self.x_axis_box.layout.addWidget(self.mode_combo)
|
66
|
+
self.x_axis_box.layout.addWidget(self.spacer)
|
67
|
+
self.x_axis_box.layout.addWidget(self.device_x_label)
|
68
|
+
self.x_axis_box.layout.addWidget(self.device_x)
|
69
|
+
self.x_axis_box.layout.addWidget(self.signal_x_label)
|
70
|
+
self.x_axis_box.layout.addWidget(self.signal_x)
|
71
|
+
|
72
|
+
self.x_axis_box.setFixedHeight(80)
|
73
|
+
self.layout.addWidget(self.x_axis_box)
|
74
|
+
|
75
|
+
def _get_x_mode_from_waveform(self):
|
76
|
+
if self.target_widget.x_mode in ["auto", "index", "timestamp"]:
|
77
|
+
self.mode_combo.setCurrentText(self.target_widget.x_mode)
|
78
|
+
else:
|
79
|
+
self.mode_combo.setCurrentText("device")
|
80
|
+
|
81
|
+
def switch_x_device_selection(self):
|
82
|
+
if self.mode_combo.currentText() == "device":
|
83
|
+
self.device_x.setEnabled(True)
|
84
|
+
self.device_x.setText(self.target_widget.x_axis_mode["name"])
|
85
|
+
self.signal_x.setText(self.target_widget.x_axis_mode["entry"])
|
86
|
+
else:
|
87
|
+
self.device_x.setEnabled(False)
|
88
|
+
|
89
|
+
def _init_y_box(self):
|
90
|
+
self.y_axis_box = QGroupBox("Y Axis")
|
91
|
+
self.y_axis_box.layout = QVBoxLayout(self.y_axis_box)
|
92
|
+
self.y_axis_box.layout.setContentsMargins(0, 0, 0, 0)
|
93
|
+
self.y_axis_box.layout.setSpacing(0)
|
94
|
+
|
95
|
+
self.curve_manager = CurveTree(self, waveform=self.target_widget)
|
96
|
+
self.y_axis_box.layout.addWidget(self.curve_manager)
|
97
|
+
|
98
|
+
self.layout.addWidget(self.y_axis_box)
|
99
|
+
|
100
|
+
@SafeSlot()
|
101
|
+
def accept_changes(self):
|
102
|
+
"""
|
103
|
+
Accepts the changes made in the settings widget and applies them to the target widget.
|
104
|
+
"""
|
105
|
+
if self.mode_combo.currentText() == "device":
|
106
|
+
self.target_widget.x_mode = self.device_x.text()
|
107
|
+
signal_x = self.signal_x.text()
|
108
|
+
if signal_x != "":
|
109
|
+
self.target_widget.x_entry = signal_x
|
110
|
+
else:
|
111
|
+
self.target_widget.x_mode = self.mode_combo.currentText()
|
112
|
+
self.curve_manager.send_curve_json()
|
113
|
+
|
114
|
+
@SafeSlot()
|
115
|
+
def refresh(self):
|
116
|
+
"""Refresh the curve tree and the x axis combo box in the case Waveform is modified from rpc."""
|
117
|
+
self.curve_manager.refresh_from_waveform()
|
118
|
+
self._get_x_mode_from_waveform()
|
119
|
+
|
120
|
+
def cleanup(self):
|
121
|
+
"""Cleanup the widget."""
|
122
|
+
self.device_x.close()
|
123
|
+
self.device_x.deleteLater()
|
124
|
+
self.curve_manager.close()
|
125
|
+
self.curve_manager.deleteLater()
|