bec-widgets 1.25.1__py3-none-any.whl → 2.0.0__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.
Files changed (196) hide show
  1. .gitlab-ci.yml +3 -5
  2. CHANGELOG.md +631 -0
  3. PKG-INFO +3 -3
  4. bec_widgets/__init__.py +4 -0
  5. bec_widgets/applications/bw_launch.py +23 -0
  6. bec_widgets/applications/launch_window.py +430 -0
  7. bec_widgets/assets/app_icons/auto_update.png +0 -0
  8. bec_widgets/assets/app_icons/ui_loader_tile.png +0 -0
  9. bec_widgets/cli/__init__.py +0 -1
  10. bec_widgets/cli/client.py +1779 -2064
  11. bec_widgets/cli/client_utils.py +346 -174
  12. bec_widgets/cli/generate_cli.py +143 -37
  13. bec_widgets/cli/rpc/rpc_base.py +152 -21
  14. bec_widgets/cli/rpc/rpc_register.py +113 -6
  15. bec_widgets/cli/rpc/rpc_widget_handler.py +13 -11
  16. bec_widgets/cli/server.py +125 -239
  17. bec_widgets/examples/jupyter_console/jupyter_console_window.py +97 -145
  18. bec_widgets/examples/plugin_example_pyside/tictactoetaskmenu.py +1 -1
  19. bec_widgets/utils/bec_connector.py +190 -21
  20. bec_widgets/utils/bec_designer.py +7 -0
  21. bec_widgets/utils/bec_dispatcher.py +71 -4
  22. bec_widgets/utils/bec_plugin_helper.py +89 -0
  23. bec_widgets/utils/bec_signal_proxy.py +1 -1
  24. bec_widgets/utils/bec_widget.py +26 -10
  25. bec_widgets/utils/colors.py +1 -1
  26. bec_widgets/{qt_utils → utils}/compact_popup.py +2 -0
  27. bec_widgets/utils/container_utils.py +37 -12
  28. bec_widgets/utils/crosshair.py +25 -8
  29. bec_widgets/utils/entry_validator.py +3 -1
  30. bec_widgets/{qt_utils → utils}/error_popups.py +18 -0
  31. bec_widgets/{qt_utils → utils}/expandable_frame.py +2 -2
  32. bec_widgets/utils/forms_from_types/forms.py +182 -0
  33. bec_widgets/{widgets/editors/scan_metadata/_metadata_widgets.py → utils/forms_from_types/items.py} +41 -30
  34. bec_widgets/utils/generate_designer_plugin.py +40 -36
  35. bec_widgets/utils/linear_region_selector.py +2 -0
  36. bec_widgets/utils/name_utils.py +16 -0
  37. bec_widgets/{qt_utils → utils}/palette_viewer.py +2 -2
  38. bec_widgets/utils/plot_indicator_items.py +2 -5
  39. bec_widgets/utils/plugin_utils.py +47 -1
  40. bec_widgets/{qt_utils → utils}/round_frame.py +14 -14
  41. bec_widgets/utils/rpc_server.py +277 -0
  42. bec_widgets/utils/serialization.py +44 -0
  43. bec_widgets/{qt_utils → utils}/settings_dialog.py +26 -1
  44. bec_widgets/{qt_utils → utils}/side_panel.py +17 -10
  45. bec_widgets/{qt_utils → utils}/toolbar.py +69 -25
  46. bec_widgets/utils/ui_loader.py +8 -8
  47. bec_widgets/utils/widget_io.py +166 -25
  48. bec_widgets/widgets/containers/auto_update/auto_updates.py +364 -0
  49. bec_widgets/widgets/containers/dock/dock.py +157 -49
  50. bec_widgets/widgets/containers/dock/dock_area.py +186 -138
  51. bec_widgets/widgets/containers/layout_manager/layout_manager.py +2 -1
  52. bec_widgets/widgets/containers/main_window/addons/web_links.py +15 -0
  53. bec_widgets/widgets/containers/main_window/main_window.py +189 -41
  54. bec_widgets/widgets/control/buttons/button_abort/button_abort.py +3 -4
  55. bec_widgets/widgets/control/buttons/button_reset/button_reset.py +3 -4
  56. bec_widgets/widgets/control/buttons/button_resume/button_resume.py +3 -3
  57. bec_widgets/widgets/control/buttons/stop_button/stop_button.py +18 -7
  58. bec_widgets/widgets/control/device_control/position_indicator/position_indicator.py +22 -3
  59. bec_widgets/widgets/control/device_control/positioner_box/_base/positioner_box_base.py +31 -13
  60. bec_widgets/widgets/control/device_control/positioner_box/positioner_box/positioner_box.py +3 -1
  61. bec_widgets/widgets/control/device_control/positioner_box/positioner_box/positioner_box.ui +27 -4
  62. bec_widgets/widgets/control/device_control/positioner_box/positioner_box_2d/positioner_box_2d.py +5 -2
  63. bec_widgets/widgets/control/device_control/positioner_box/positioner_box_2d/positioner_box_2d.ui +97 -31
  64. bec_widgets/widgets/control/device_control/positioner_box/positioner_control_line/positioner_control_line.ui +11 -4
  65. bec_widgets/widgets/control/device_control/positioner_group/positioner_group.py +2 -3
  66. bec_widgets/widgets/control/device_input/base_classes/device_input_base.py +29 -4
  67. bec_widgets/widgets/control/device_input/base_classes/device_signal_input_base.py +1 -0
  68. bec_widgets/widgets/control/device_input/device_combobox/device_combobox.py +2 -2
  69. bec_widgets/widgets/control/device_input/device_line_edit/device_line_edit.py +2 -2
  70. bec_widgets/widgets/control/device_input/signal_combobox/signal_combobox.py +1 -2
  71. bec_widgets/widgets/control/device_input/signal_line_edit/signal_line_edit.py +1 -2
  72. bec_widgets/widgets/control/scan_control/scan_control.py +7 -5
  73. bec_widgets/widgets/control/scan_control/scan_group_box.py +28 -5
  74. bec_widgets/widgets/dap/dap_combo_box/dap_combo_box.py +1 -2
  75. bec_widgets/widgets/dap/lmfit_dialog/lmfit_dialog.py +3 -4
  76. bec_widgets/widgets/dap/lmfit_dialog/lmfit_dialog_vertical.ui +14 -8
  77. bec_widgets/widgets/editors/console/console.py +1 -1
  78. bec_widgets/widgets/editors/{scan_metadata/additional_metadata_table.py → dict_backed_table.py} +29 -6
  79. bec_widgets/widgets/editors/scan_metadata/__init__.py +0 -7
  80. bec_widgets/widgets/editors/scan_metadata/_util.py +1 -1
  81. bec_widgets/widgets/{plots/motor_map/register_bec_motor_map_widget.py → editors/scan_metadata/register_scan_metadata.py} +2 -4
  82. bec_widgets/widgets/editors/scan_metadata/scan_metadata.py +42 -136
  83. bec_widgets/widgets/editors/scan_metadata/scan_metadata.pyproject +1 -0
  84. bec_widgets/widgets/{plots/multi_waveform/bec_multi_waveform_widget_plugin.py → editors/scan_metadata/scan_metadata_plugin.py} +9 -9
  85. bec_widgets/widgets/editors/text_box/text_box.py +2 -3
  86. bec_widgets/widgets/editors/website/website.py +2 -2
  87. bec_widgets/widgets/games/minesweeper.py +3 -2
  88. bec_widgets/widgets/plots/image/image.py +960 -0
  89. bec_widgets/widgets/plots/image/image.pyproject +1 -0
  90. bec_widgets/widgets/plots/image/image_item.py +279 -0
  91. bec_widgets/widgets/plots/{motor_map/bec_motor_map_widget_plugin.py → image/image_plugin.py} +11 -13
  92. bec_widgets/widgets/{containers/figure/plots → plots}/image/image_processor.py +31 -64
  93. bec_widgets/widgets/plots/image/{register_bec_image_widget.py → register_image.py} +2 -2
  94. bec_widgets/widgets/plots/image/toolbar_bundles/image_selection.py +59 -0
  95. bec_widgets/widgets/plots/image/toolbar_bundles/processing.py +79 -0
  96. bec_widgets/widgets/plots/motor_map/motor_map.py +832 -0
  97. bec_widgets/widgets/plots/motor_map/motor_map.pyproject +1 -0
  98. bec_widgets/widgets/plots/motor_map/motor_map_plugin.py +54 -0
  99. bec_widgets/widgets/plots/{multi_waveform/register_bec_multi_waveform_widget.py → motor_map/register_motor_map.py} +2 -4
  100. bec_widgets/widgets/plots/motor_map/settings/motor_map_settings.py +129 -0
  101. bec_widgets/widgets/plots/motor_map/settings/motor_map_settings.ui +120 -0
  102. bec_widgets/widgets/plots/motor_map/toolbar_bundles/motor_selection.py +70 -0
  103. bec_widgets/widgets/plots/multi_waveform/multi_waveform.py +508 -0
  104. bec_widgets/widgets/plots/multi_waveform/multi_waveform.pyproject +1 -0
  105. bec_widgets/widgets/plots/multi_waveform/multi_waveform_plugin.py +54 -0
  106. bec_widgets/widgets/plots/multi_waveform/register_multi_waveform.py +15 -0
  107. bec_widgets/widgets/plots/multi_waveform/settings/control_panel.py +144 -0
  108. bec_widgets/widgets/plots/multi_waveform/settings/multi_waveform_controls.ui +164 -0
  109. bec_widgets/widgets/plots/multi_waveform/toolbar_bundles/monitor_selection.py +65 -0
  110. bec_widgets/widgets/{plots_next_gen → plots}/plot_base.py +321 -40
  111. bec_widgets/widgets/plots/{waveform/register_bec_waveform_widget.py → scatter_waveform/register_scatter_waveform.py} +3 -3
  112. bec_widgets/widgets/plots/scatter_waveform/scatter_curve.py +197 -0
  113. bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.py +553 -0
  114. bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.pyproject +1 -0
  115. bec_widgets/widgets/plots/{image/bec_image_widget_plugin.py → scatter_waveform/scatter_waveform_plugin.py} +9 -13
  116. bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_setting.py +138 -0
  117. bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_horizontal.ui +195 -0
  118. bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_vertical.ui +204 -0
  119. bec_widgets/widgets/{plots_next_gen → plots}/setting_menus/axis_settings.py +8 -8
  120. bec_widgets/widgets/{plots_next_gen → plots}/toolbar_bundles/mouse_interactions.py +4 -18
  121. bec_widgets/widgets/{plots_next_gen → plots}/toolbar_bundles/plot_export.py +14 -3
  122. bec_widgets/widgets/{plots_next_gen → plots}/toolbar_bundles/roi_bundle.py +6 -1
  123. bec_widgets/widgets/{plots_next_gen → plots}/toolbar_bundles/save_state.py +2 -2
  124. bec_widgets/widgets/{containers/figure/plots/waveform/waveform_curve.py → plots/waveform/curve.py} +119 -49
  125. bec_widgets/widgets/plots/waveform/register_waveform.py +15 -0
  126. bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_setting.py +125 -0
  127. bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_tree.py +576 -0
  128. bec_widgets/widgets/plots/waveform/utils/__init__.py +0 -0
  129. bec_widgets/widgets/plots/waveform/utils/roi_manager.py +84 -0
  130. bec_widgets/widgets/plots/waveform/waveform.py +1794 -0
  131. bec_widgets/widgets/plots/waveform/waveform.pyproject +1 -0
  132. bec_widgets/widgets/plots/waveform/{bec_waveform_widget_plugin.py → waveform_plugin.py} +9 -13
  133. bec_widgets/widgets/progress/bec_progressbar/bec_progressbar.py +1 -2
  134. bec_widgets/widgets/progress/ring_progress_bar/ring.py +11 -10
  135. bec_widgets/widgets/progress/ring_progress_bar/ring_progress_bar.py +24 -14
  136. bec_widgets/widgets/services/bec_queue/bec_queue.py +13 -11
  137. bec_widgets/widgets/services/bec_status_box/bec_status_box.py +3 -4
  138. bec_widgets/widgets/services/device_browser/device_browser.py +5 -2
  139. bec_widgets/widgets/services/device_browser/device_item/device_item.py +1 -1
  140. bec_widgets/widgets/utility/logpanel/logpanel.py +36 -17
  141. bec_widgets/widgets/utility/spinbox/decimal_spinbox.py +3 -3
  142. bec_widgets/widgets/utility/visual/color_button/color_button.py +1 -1
  143. bec_widgets/widgets/utility/visual/colormap_widget/colormap_widget.py +4 -6
  144. bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.py +4 -8
  145. {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.0.dist-info}/METADATA +3 -3
  146. {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.0.dist-info}/RECORD +168 -153
  147. pyproject.toml +3 -3
  148. bec_widgets/applications/alignment/alignment_1d/alignment_1d.py +0 -198
  149. bec_widgets/applications/alignment/alignment_1d/alignment_1d.ui +0 -615
  150. bec_widgets/applications/bec_app.py +0 -84
  151. bec_widgets/cli/auto_updates.py +0 -168
  152. bec_widgets/widgets/containers/figure/__init__.py +0 -1
  153. bec_widgets/widgets/containers/figure/figure.py +0 -796
  154. bec_widgets/widgets/containers/figure/plots/axis_settings.py +0 -91
  155. bec_widgets/widgets/containers/figure/plots/axis_settings.ui +0 -256
  156. bec_widgets/widgets/containers/figure/plots/image/image.py +0 -772
  157. bec_widgets/widgets/containers/figure/plots/image/image_item.py +0 -337
  158. bec_widgets/widgets/containers/figure/plots/motor_map/motor_map.py +0 -525
  159. bec_widgets/widgets/containers/figure/plots/multi_waveform/multi_waveform.py +0 -340
  160. bec_widgets/widgets/containers/figure/plots/plot_base.py +0 -505
  161. bec_widgets/widgets/containers/figure/plots/waveform/waveform.py +0 -1563
  162. bec_widgets/widgets/plots/image/bec_image_widget.pyproject +0 -1
  163. bec_widgets/widgets/plots/image/image_widget.py +0 -515
  164. bec_widgets/widgets/plots/motor_map/bec_motor_map_widget.pyproject +0 -1
  165. bec_widgets/widgets/plots/motor_map/motor_map_dialog/motor_map_settings.py +0 -56
  166. bec_widgets/widgets/plots/motor_map/motor_map_dialog/motor_map_settings.ui +0 -108
  167. bec_widgets/widgets/plots/motor_map/motor_map_widget.py +0 -234
  168. bec_widgets/widgets/plots/multi_waveform/bec_multi_waveform_widget.pyproject +0 -1
  169. bec_widgets/widgets/plots/multi_waveform/multi_waveform_controls.ui +0 -99
  170. bec_widgets/widgets/plots/multi_waveform/multi_waveform_widget.py +0 -536
  171. bec_widgets/widgets/plots/waveform/bec_waveform_widget.pyproject +0 -1
  172. bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.py +0 -336
  173. bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.ui +0 -372
  174. bec_widgets/widgets/plots/waveform/waveform_popups/dap_summary_dialog/dap_summary_dialog.py +0 -25
  175. bec_widgets/widgets/plots/waveform/waveform_widget.py +0 -751
  176. /bec_widgets/{qt_utils → utils}/collapsible_panel_manager.py +0 -0
  177. /bec_widgets/{applications/alignment → utils/forms_from_types}/__init__.py +0 -0
  178. /bec_widgets/{qt_utils → utils}/redis_message_waiter.py +0 -0
  179. /bec_widgets/{applications/alignment/alignment_1d → widgets/containers/auto_update}/__init__.py +0 -0
  180. /bec_widgets/{qt_utils → widgets/containers/main_window/addons}/__init__.py +0 -0
  181. /bec_widgets/widgets/{containers/figure/plots → plots/image/toolbar_bundles}/__init__.py +0 -0
  182. /bec_widgets/widgets/{containers/figure/plots/image → plots/motor_map/settings}/__init__.py +0 -0
  183. /bec_widgets/widgets/{containers/figure/plots/motor_map → plots/motor_map/toolbar_bundles}/__init__.py +0 -0
  184. /bec_widgets/widgets/{containers/figure/plots/multi_waveform → plots/multi_waveform/settings}/__init__.py +0 -0
  185. /bec_widgets/widgets/{containers/figure/plots/waveform → plots/multi_waveform/toolbar_bundles}/__init__.py +0 -0
  186. /bec_widgets/widgets/plots/{motor_map/motor_map_dialog → scatter_waveform}/__init__.py +0 -0
  187. /bec_widgets/widgets/plots/{waveform/waveform_popups → scatter_waveform/settings}/__init__.py +0 -0
  188. /bec_widgets/widgets/plots/{waveform/waveform_popups/curve_dialog → setting_menus}/__init__.py +0 -0
  189. /bec_widgets/widgets/{plots_next_gen → plots}/setting_menus/axis_settings_horizontal.ui +0 -0
  190. /bec_widgets/widgets/{plots_next_gen → plots}/setting_menus/axis_settings_vertical.ui +0 -0
  191. /bec_widgets/widgets/plots/{waveform/waveform_popups/dap_summary_dialog → toolbar_bundles}/__init__.py +0 -0
  192. /bec_widgets/widgets/{plots_next_gen/setting_menus → plots/waveform/settings}/__init__.py +0 -0
  193. /bec_widgets/widgets/{plots_next_gen/toolbar_bundles → plots/waveform/settings/curve_settings}/__init__.py +0 -0
  194. {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.0.dist-info}/WHEEL +0 -0
  195. {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.0.dist-info}/entry_points.txt +0 -0
  196. {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,751 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import sys
4
- from typing import Literal
5
-
6
- import numpy as np
7
- import pyqtgraph as pg
8
- from bec_lib.logger import bec_logger
9
- from qtpy.QtCore import Property, Signal, Slot
10
- from qtpy.QtWidgets import QVBoxLayout, QWidget
11
-
12
- from bec_widgets.qt_utils.error_popups import SafeSlot, WarningPopupUtility
13
- from bec_widgets.qt_utils.settings_dialog import SettingsDialog
14
- from bec_widgets.qt_utils.toolbar import MaterialIconAction, ModularToolBar, SeparatorAction
15
- from bec_widgets.utils.bec_widget import BECWidget
16
- from bec_widgets.widgets.containers.figure import BECFigure
17
- from bec_widgets.widgets.containers.figure.plots.axis_settings import AxisSettings
18
- from bec_widgets.widgets.containers.figure.plots.waveform.waveform import Waveform1DConfig
19
- from bec_widgets.widgets.containers.figure.plots.waveform.waveform_curve import BECCurve
20
- from bec_widgets.widgets.plots.waveform.waveform_popups.curve_dialog.curve_dialog import (
21
- CurveSettings,
22
- )
23
- from bec_widgets.widgets.plots.waveform.waveform_popups.dap_summary_dialog.dap_summary_dialog import (
24
- FitSummaryWidget,
25
- )
26
-
27
- try:
28
- import pandas as pd
29
- except ImportError:
30
- pd = None
31
-
32
- logger = bec_logger.logger
33
-
34
-
35
- class BECWaveformWidget(BECWidget, QWidget):
36
- PLUGIN = True
37
- ICON_NAME = "show_chart"
38
- USER_ACCESS = [
39
- "curves",
40
- "plot",
41
- "add_dap",
42
- "get_dap_params",
43
- "remove_curve",
44
- "scan_history",
45
- "get_all_data",
46
- "set",
47
- "set_x",
48
- "set_title",
49
- "set_x_label",
50
- "set_y_label",
51
- "set_x_scale",
52
- "set_y_scale",
53
- "set_x_lim",
54
- "set_y_lim",
55
- "set_legend_label_size",
56
- "set_auto_range",
57
- "set_grid",
58
- "enable_fps_monitor",
59
- "enable_scatter",
60
- "lock_aspect_ratio",
61
- "export",
62
- "export_to_matplotlib",
63
- "toggle_roi",
64
- "select_roi",
65
- ]
66
- scan_signal_update = Signal()
67
- async_signal_update = Signal()
68
- dap_summary_update = Signal(dict, dict)
69
- dap_params_update = Signal(dict, dict)
70
- autorange_signal = Signal()
71
- new_scan = Signal()
72
- crosshair_position_changed = Signal(tuple)
73
- crosshair_position_changed_string = Signal(str)
74
- crosshair_position_clicked = Signal(tuple)
75
- crosshair_position_clicked_string = Signal(str)
76
- crosshair_coordinates_changed = Signal(tuple)
77
- crosshair_coordinates_changed_string = Signal(str)
78
- crosshair_coordinates_clicked = Signal(tuple)
79
- crosshair_coordinates_clicked_string = Signal(str)
80
- roi_changed = Signal(tuple)
81
- roi_active = Signal(bool)
82
-
83
- def __init__(
84
- self,
85
- parent: QWidget | None = None,
86
- config: Waveform1DConfig | dict = None,
87
- client=None,
88
- gui_id: str | None = None,
89
- **kwargs,
90
- ) -> None:
91
- if config is None:
92
- config = Waveform1DConfig(widget_class=self.__class__.__name__)
93
- else:
94
- if isinstance(config, dict):
95
- config = Waveform1DConfig(**config)
96
- super().__init__(client=client, gui_id=gui_id, **kwargs)
97
- QWidget.__init__(self, parent)
98
-
99
- self.layout = QVBoxLayout(self)
100
- self.layout.setSpacing(0)
101
- self.layout.setContentsMargins(0, 0, 0, 0)
102
-
103
- self.fig = BECFigure()
104
- self.toolbar = ModularToolBar(
105
- actions={
106
- "save": MaterialIconAction(icon_name="save", tooltip="Open Export Dialog"),
107
- "matplotlib": MaterialIconAction(
108
- icon_name="photo_library", tooltip="Open Matplotlib Plot"
109
- ),
110
- "separator_1": SeparatorAction(),
111
- "drag_mode": MaterialIconAction(
112
- icon_name="drag_pan", tooltip="Drag Mouse Mode", checkable=True
113
- ),
114
- "rectangle_mode": MaterialIconAction(
115
- icon_name="frame_inspect", tooltip="Rectangle Zoom Mode", checkable=True
116
- ),
117
- "auto_range": MaterialIconAction(
118
- icon_name="open_in_full", tooltip="Autorange Plot"
119
- ),
120
- "separator_2": SeparatorAction(),
121
- "curves": MaterialIconAction(
122
- icon_name="timeline", tooltip="Open Curves Configuration"
123
- ),
124
- "fit_params": MaterialIconAction(
125
- icon_name="monitoring", tooltip="Open Fitting Parameters"
126
- ),
127
- "separator_3": SeparatorAction(),
128
- "crosshair": MaterialIconAction(
129
- icon_name="point_scan", tooltip="Show Crosshair", checkable=True
130
- ),
131
- "roi_select": MaterialIconAction(
132
- icon_name="align_justify_space_between",
133
- tooltip="Add ROI region for DAP",
134
- checkable=True,
135
- ),
136
- "separator_4": SeparatorAction(),
137
- "fps_monitor": MaterialIconAction(
138
- icon_name="speed", tooltip="Show FPS Monitor", checkable=True
139
- ),
140
- "axis_settings": MaterialIconAction(
141
- icon_name="settings", tooltip="Open Configuration Dialog"
142
- ),
143
- },
144
- target_widget=self,
145
- )
146
-
147
- self.layout.addWidget(self.toolbar)
148
- self.layout.addWidget(self.fig)
149
-
150
- self.warning_util = WarningPopupUtility(self)
151
-
152
- self.waveform = self.fig.plot()
153
- self.waveform.apply_config(config)
154
-
155
- self.config = config
156
- self._clear_curves_on_plot_update = False
157
-
158
- self.hook_waveform_signals()
159
- self._hook_actions()
160
-
161
- def hook_waveform_signals(self):
162
- self.waveform.scan_signal_update.connect(self.scan_signal_update)
163
- self.waveform.async_signal_update.connect(self.async_signal_update)
164
- self.waveform.dap_params_update.connect(self.dap_params_update)
165
- self.waveform.dap_summary_update.connect(self.dap_summary_update)
166
- self.waveform.autorange_signal.connect(self.autorange_signal)
167
- self.waveform.new_scan.connect(self.new_scan)
168
- self.waveform.crosshair_coordinates_changed.connect(self.crosshair_coordinates_changed)
169
- self.waveform.crosshair_coordinates_clicked.connect(self.crosshair_coordinates_clicked)
170
- self.waveform.crosshair_coordinates_changed.connect(
171
- self._emit_crosshair_coordinates_changed_string
172
- )
173
- self.waveform.crosshair_coordinates_clicked.connect(
174
- self._emit_crosshair_coordinates_clicked_string
175
- )
176
- self.waveform.crosshair_position_changed.connect(self.crosshair_position_changed)
177
- self.waveform.crosshair_position_clicked.connect(self.crosshair_position_clicked)
178
- self.waveform.crosshair_position_changed.connect(
179
- self._emit_crosshair_position_changed_string
180
- )
181
- self.waveform.crosshair_position_clicked.connect(
182
- self._emit_crosshair_position_clicked_string
183
- )
184
- self.waveform.roi_changed.connect(self.roi_changed)
185
- self.waveform.roi_active.connect(self.roi_active)
186
-
187
- def _hook_actions(self):
188
- self.toolbar.widgets["save"].action.triggered.connect(self.export)
189
- self.toolbar.widgets["matplotlib"].action.triggered.connect(self.export_to_matplotlib)
190
- self.toolbar.widgets["drag_mode"].action.triggered.connect(self.enable_mouse_pan_mode)
191
- self.toolbar.widgets["rectangle_mode"].action.triggered.connect(
192
- self.enable_mouse_rectangle_mode
193
- )
194
- self.toolbar.widgets["auto_range"].action.triggered.connect(self._auto_range_from_toolbar)
195
- self.toolbar.widgets["curves"].action.triggered.connect(self.show_curve_settings)
196
- self.toolbar.widgets["fit_params"].action.triggered.connect(self.show_fit_summary_dialog)
197
- self.toolbar.widgets["axis_settings"].action.triggered.connect(self.show_axis_settings)
198
- self.toolbar.widgets["crosshair"].action.triggered.connect(self.waveform.toggle_crosshair)
199
- self.toolbar.widgets["roi_select"].action.toggled.connect(self.waveform.toggle_roi)
200
- self.toolbar.widgets["fps_monitor"].action.toggled.connect(self.enable_fps_monitor)
201
- # self.toolbar.widgets["import"].action.triggered.connect(
202
- # lambda: self.load_config(path=None, gui=True)
203
- # )
204
- # self.toolbar.widgets["export"].action.triggered.connect(
205
- # lambda: self.save_config(path=None, gui=True)
206
- # )
207
-
208
- @Slot(bool)
209
- def toogle_roi_select(self, checked: bool):
210
- """Toggle the linear region selector.
211
-
212
- Args:
213
- checked(bool): If True, enable the linear region selector.
214
- """
215
- self.toolbar.widgets["roi_select"].action.setChecked(checked)
216
-
217
- @Property(bool)
218
- def clear_curves_on_plot_update(self) -> bool:
219
- """If True, clear curves on plot update."""
220
- return self._clear_curves_on_plot_update
221
-
222
- @clear_curves_on_plot_update.setter
223
- def clear_curves_on_plot_update(self, value: bool):
224
- """Set the clear curves on plot update property.
225
-
226
- Args:
227
- value(bool): If True, clear curves on plot update.
228
- """
229
- self._clear_curves_on_plot_update = value
230
-
231
- @SafeSlot(tuple)
232
- def _emit_crosshair_coordinates_changed_string(self, coordinates):
233
- self.crosshair_coordinates_changed_string.emit(str(coordinates))
234
-
235
- @SafeSlot(tuple)
236
- def _emit_crosshair_coordinates_clicked_string(self, coordinates):
237
- self.crosshair_coordinates_clicked_string.emit(str(coordinates))
238
-
239
- @SafeSlot(tuple)
240
- def _emit_crosshair_position_changed_string(self, position):
241
- self.crosshair_position_changed_string.emit(str(position))
242
-
243
- @SafeSlot(tuple)
244
- def _emit_crosshair_position_clicked_string(self, position):
245
- self.crosshair_position_clicked_string.emit(str(position))
246
-
247
- ###################################
248
- # Dialog Windows
249
- ###################################
250
- def show_axis_settings(self):
251
- dialog = SettingsDialog(
252
- self,
253
- settings_widget=AxisSettings(),
254
- window_title="Axis Settings",
255
- config=self._config_dict["axis"],
256
- )
257
- dialog.exec()
258
-
259
- def show_curve_settings(self):
260
- dialog = SettingsDialog(
261
- self,
262
- settings_widget=CurveSettings(),
263
- window_title="Curve Settings",
264
- config=self.waveform._curves_data,
265
- )
266
- dialog.resize(800, 600)
267
- dialog.exec()
268
-
269
- def show_fit_summary_dialog(self):
270
- dialog = FitSummaryWidget(target_widget=self)
271
- dialog.resize(800, 600)
272
- dialog.exec()
273
-
274
- ###################################
275
- # User Access Methods from Waveform
276
- ###################################
277
- @property
278
- def curves(self) -> list[BECCurve]:
279
- """
280
- Get the curves of the plot widget as a list
281
- Returns:
282
- list: List of curves.
283
- """
284
- return self.waveform._curves
285
-
286
- @curves.setter
287
- def curves(self, value: list[BECCurve]):
288
- self.waveform._curves = value
289
-
290
- def get_curve(self, identifier) -> BECCurve:
291
- """
292
- Get the curve by its index or ID.
293
-
294
- Args:
295
- identifier(int|str): Identifier of the curve. Can be either an integer (index) or a string (curve_id).
296
-
297
- Returns:
298
- BECCurve: The curve object.
299
- """
300
- return self.waveform.get_curve(identifier)
301
-
302
- def set_colormap(self, colormap: str):
303
- """
304
- Set the colormap of the plot widget.
305
-
306
- Args:
307
- colormap(str, optional): Scale the colors of curves to colormap. If None, use the default color palette.
308
- """
309
- self.waveform.set_colormap(colormap)
310
-
311
- @Slot(str, str) # Slot for x_name, x_entry
312
- @SafeSlot(str, popup_error=True) # Slot for x_name and
313
- def set_x(self, x_name: str, x_entry: str | None = None):
314
- """
315
- Change the x axis of the plot widget.
316
-
317
- Args:
318
- x_name(str): Name of the x signal.
319
- - "best_effort": Use the best effort signal.
320
- - "timestamp": Use the timestamp signal.
321
- - "index": Use the index signal.
322
- - Custom signal name of device from BEC.
323
- x_entry(str): Entry of the x signal.
324
- """
325
- self.waveform.set_x(x_name, x_entry)
326
-
327
- @Slot(str) # Slot for y_name
328
- @SafeSlot(popup_error=True)
329
- def plot(
330
- self,
331
- arg1: list | np.ndarray | str | None = None,
332
- x: list | np.ndarray | None = None,
333
- y: list | np.ndarray | None = None,
334
- x_name: str | None = None,
335
- y_name: str | None = None,
336
- z_name: str | None = None,
337
- x_entry: str | None = None,
338
- y_entry: str | None = None,
339
- z_entry: str | None = None,
340
- color: str | None = None,
341
- color_map_z: str | None = "magma",
342
- label: str | None = None,
343
- validate: bool = True,
344
- dap: str | None = None, # TODO add dap custom curve wrapper
345
- **kwargs,
346
- ) -> BECCurve:
347
- """
348
- Plot a curve to the plot widget.
349
- Args:
350
- arg1(list | np.ndarray | str | None): First argument which can be x data(list | np.ndarray), y data(list | np.ndarray), or y_name(str).
351
- x(list | np.ndarray): Custom x data to plot.
352
- y(list | np.ndarray): Custom y data to plot.
353
- x_name(str): The name of the device for the x-axis.
354
- y_name(str): The name of the device for the y-axis.
355
- z_name(str): The name of the device for the z-axis.
356
- x_entry(str): The name of the entry for the x-axis.
357
- y_entry(str): The name of the entry for the y-axis.
358
- z_entry(str): The name of the entry for the z-axis.
359
- color(str): The color of the curve.
360
- color_map_z(str): The color map to use for the z-axis.
361
- label(str): The label of the curve.
362
- validate(bool): If True, validate the device names and entries.
363
- dap(str): The dap model to use for the curve. If not specified, none will be added.
364
-
365
- Returns:
366
- BECCurve: The curve object.
367
- """
368
- if self.clear_curves_on_plot_update is True:
369
- self.waveform.clear_source(source="scan_segment")
370
- return self.waveform.plot(
371
- arg1=arg1,
372
- x=x,
373
- y=y,
374
- x_name=x_name,
375
- y_name=y_name,
376
- z_name=z_name,
377
- x_entry=x_entry,
378
- y_entry=y_entry,
379
- z_entry=z_entry,
380
- color=color,
381
- color_map_z=color_map_z,
382
- label=label,
383
- validate=validate,
384
- dap=dap,
385
- **kwargs,
386
- )
387
-
388
- @Slot(
389
- str, str, str, str, str, str, bool
390
- ) # Slot for x_name, y_name, x_entry, y_entry, color, validate_bec
391
- @SafeSlot(str, str, str, popup_error=True)
392
- def add_dap(
393
- self,
394
- x_name: str,
395
- y_name: str,
396
- dap: str,
397
- x_entry: str | None = None,
398
- y_entry: str | None = None,
399
- color: str | None = None,
400
- validate_bec: bool = True,
401
- **kwargs,
402
- ) -> BECCurve:
403
- """
404
- Add LMFIT dap model curve to the plot widget.
405
-
406
- Args:
407
- x_name(str): Name of the x signal.
408
- x_entry(str): Entry of the x signal.
409
- y_name(str): Name of the y signal.
410
- y_entry(str): Entry of the y signal.
411
- color(str, optional): Color of the curve. Defaults to None.
412
- dap(str): The dap model to use for the curve.
413
- validate_bec(bool, optional): If True, validate the signal with BEC. Defaults to True.
414
- **kwargs: Additional keyword arguments for the curve configuration.
415
-
416
- Returns:
417
- BECCurve: The curve object.
418
- """
419
- if self.clear_curves_on_plot_update is True:
420
- self.waveform.clear_source(source="DAP")
421
- return self.waveform.add_dap(
422
- x_name=x_name,
423
- y_name=y_name,
424
- x_entry=x_entry,
425
- y_entry=y_entry,
426
- color=color,
427
- dap=dap,
428
- validate_bec=validate_bec,
429
- **kwargs,
430
- )
431
-
432
- def get_dap_params(self) -> dict:
433
- """
434
- Get the DAP parameters of all DAP curves.
435
-
436
- Returns:
437
- dict: DAP parameters of all DAP curves.
438
- """
439
-
440
- return self.waveform.get_dap_params()
441
-
442
- def get_dap_summary(self) -> dict:
443
- """
444
- Get the DAP summary of all DAP curves.
445
-
446
- Returns:
447
- dict: DAP summary of all DAP curves.
448
- """
449
- return self.waveform.get_dap_summary()
450
-
451
- def remove_curve(self, *identifiers):
452
- """
453
- Remove a curve from the plot widget.
454
-
455
- Args:
456
- *identifiers: Identifier of the curve to be removed. Can be either an integer (index) or a string (curve_id).
457
- """
458
- self.waveform.remove_curve(*identifiers)
459
-
460
- def scan_history(self, scan_index: int = None, scan_id: str = None):
461
- """
462
- Update the scan curves with the data from the scan storage.
463
- Provide only one of scan_id or scan_index.
464
-
465
- Args:
466
- scan_id(str, optional): ScanID of the scan to be updated. Defaults to None.
467
- scan_index(int, optional): Index of the scan to be updated. Defaults to None.
468
- """
469
- self.waveform.scan_history(scan_index, scan_id)
470
-
471
- def get_all_data(self, output: Literal["dict", "pandas"] = "dict") -> dict | pd.DataFrame:
472
- """
473
- Extract all curve data into a dictionary or a pandas DataFrame.
474
-
475
- Args:
476
- output (Literal["dict", "pandas"]): Format of the output data.
477
-
478
- Returns:
479
- dict | pd.DataFrame: Data of all curves in the specified format.
480
- """
481
- try:
482
- import pandas as pd
483
- except ImportError:
484
- pd = None
485
- if output == "pandas":
486
- logger.warning(
487
- "Pandas is not installed. "
488
- "Please install pandas using 'pip install pandas'."
489
- "Output will be dictionary instead."
490
- )
491
- output = "dict"
492
- return self.waveform.get_all_data(output)
493
-
494
- ###################################
495
- # User Access Methods from Plotbase
496
- ###################################
497
-
498
- def set(self, **kwargs):
499
- """
500
- Set the properties of the plot widget.
501
-
502
- Args:
503
- **kwargs: Keyword arguments for the properties to be set.
504
-
505
- Possible properties:
506
- - title: str
507
- - x_label: str
508
- - y_label: str
509
- - x_scale: Literal["linear", "log"]
510
- - y_scale: Literal["linear", "log"]
511
- - x_lim: tuple
512
- - y_lim: tuple
513
- - legend_label_size: int
514
- """
515
- self.waveform.set(**kwargs)
516
-
517
- def set_title(self, title: str):
518
- """
519
- Set the title of the plot widget.
520
-
521
- Args:
522
- title(str): Title of the plot.
523
- """
524
- self.waveform.set_title(title)
525
-
526
- def set_x_label(self, x_label: str):
527
- """
528
- Set the x-axis label of the plot widget.
529
-
530
- Args:
531
- x_label(str): Label of the x-axis.
532
- """
533
- self.waveform.set_x_label(x_label)
534
-
535
- def set_y_label(self, y_label: str):
536
- """
537
- Set the y-axis label of the plot widget.
538
-
539
- Args:
540
- y_label(str): Label of the y-axis.
541
- """
542
- self.waveform.set_y_label(y_label)
543
-
544
- def set_x_scale(self, x_scale: Literal["linear", "log"]):
545
- """
546
- Set the scale of the x-axis of the plot widget.
547
-
548
- Args:
549
- x_scale(Literal["linear", "log"]): Scale of the x-axis.
550
- """
551
- self.waveform.set_x_scale(x_scale)
552
-
553
- def set_y_scale(self, y_scale: Literal["linear", "log"]):
554
- """
555
- Set the scale of the y-axis of the plot widget.
556
-
557
- Args:
558
- y_scale(Literal["linear", "log"]): Scale of the y-axis.
559
- """
560
- self.waveform.set_y_scale(y_scale)
561
-
562
- def set_x_lim(self, x_lim: tuple):
563
- """
564
- Set the limits of the x-axis of the plot widget.
565
-
566
- Args:
567
- x_lim(tuple): Limits of the x-axis.
568
- """
569
- self.waveform.set_x_lim(x_lim)
570
-
571
- def set_y_lim(self, y_lim: tuple):
572
- """
573
- Set the limits of the y-axis of the plot widget.
574
-
575
- Args:
576
- y_lim(tuple): Limits of the y-axis.
577
- """
578
- self.waveform.set_y_lim(y_lim)
579
-
580
- def set_legend_label_size(self, legend_label_size: int):
581
- """
582
- Set the size of the legend labels of the plot widget.
583
-
584
- Args:
585
- legend_label_size(int): Size of the legend labels.
586
- """
587
- self.waveform.set_legend_label_size(legend_label_size)
588
-
589
- def set_auto_range(self, enabled: bool, axis: str = "xy"):
590
- """
591
- Set the auto range of the plot widget.
592
-
593
- Args:
594
- enabled(bool): If True, enable the auto range.
595
- axis(str, optional): The axis to enable the auto range.
596
- - "xy": Enable auto range for both x and y axis.
597
- - "x": Enable auto range for x axis.
598
- - "y": Enable auto range for y axis.
599
- """
600
- self.waveform.set_auto_range(enabled, axis)
601
-
602
- def toggle_roi(self, checked: bool):
603
- """Toggle the linear region selector.
604
-
605
- Args:
606
- checked(bool): If True, enable the linear region selector.
607
- """
608
- self.waveform.toggle_roi(checked)
609
- if self.toolbar.widgets["roi_select"].action.isChecked() != checked:
610
- self.toolbar.widgets["roi_select"].action.setChecked(checked)
611
-
612
- def select_roi(self, region: tuple):
613
- """
614
- Set the region of interest of the plot widget.
615
-
616
- Args:
617
- region(tuple): Region of interest.
618
- """
619
- self.waveform.select_roi(region)
620
-
621
- def enable_fps_monitor(self, enabled: bool):
622
- """
623
- Enable the FPS monitor of the plot widget.
624
-
625
- Args:
626
- enabled(bool): If True, enable the FPS monitor.
627
- """
628
- self.waveform.enable_fps_monitor(enabled)
629
- if self.toolbar.widgets["fps_monitor"].action.isChecked() != enabled:
630
- self.toolbar.widgets["fps_monitor"].action.setChecked(enabled)
631
-
632
- @SafeSlot()
633
- def _auto_range_from_toolbar(self):
634
- """
635
- Set the auto range of the plot widget from the toolbar.
636
- """
637
- self.waveform.set_auto_range(True, "xy")
638
-
639
- def set_grid(self, x_grid: bool, y_grid: bool):
640
- """
641
- Set the grid visibility of the plot widget.
642
-
643
- Args:
644
- x_grid(bool): Visibility of the x-axis grid.
645
- y_grid(bool): Visibility of the y-axis grid.
646
- """
647
- self.waveform.set_grid(x_grid, y_grid)
648
-
649
- def set_outer_axes(self, show: bool):
650
- """
651
- Set the outer axes visibility of the plot widget.
652
-
653
- Args:
654
- show(bool): Visibility of the outer axes.
655
- """
656
- self.waveform.set_outer_axes(show)
657
-
658
- def enable_scatter(self, enabled: bool):
659
- """
660
- Enable the scatter plot of the plot widget.
661
-
662
- Args:
663
- enabled(bool): If True, enable the scatter plot.
664
- """
665
- self.waveform.enable_scatter(enabled)
666
-
667
- def lock_aspect_ratio(self, lock: bool):
668
- """
669
- Lock the aspect ratio of the plot widget.
670
-
671
- Args:
672
- lock(bool): Lock the aspect ratio.
673
- """
674
- self.waveform.lock_aspect_ratio(lock)
675
-
676
- @SafeSlot()
677
- def enable_mouse_rectangle_mode(self):
678
- self.toolbar.widgets["rectangle_mode"].action.setChecked(True)
679
- self.toolbar.widgets["drag_mode"].action.setChecked(False)
680
- self.waveform.plot_item.getViewBox().setMouseMode(pg.ViewBox.RectMode)
681
-
682
- @SafeSlot()
683
- def enable_mouse_pan_mode(self):
684
- self.toolbar.widgets["drag_mode"].action.setChecked(True)
685
- self.toolbar.widgets["rectangle_mode"].action.setChecked(False)
686
- self.waveform.plot_item.getViewBox().setMouseMode(pg.ViewBox.PanMode)
687
-
688
- def export(self):
689
- """
690
- Show the export dialog for the plot widget.
691
- """
692
- self.waveform.export()
693
-
694
- def export_to_matplotlib(self):
695
- """
696
- Export the plot widget to Matplotlib.
697
- """
698
- try:
699
- import matplotlib as mpl
700
- except ImportError:
701
- self.warning_util.show_warning(
702
- title="Matplotlib not installed",
703
- message="Matplotlib is required for this feature.",
704
- detailed_text="Please install matplotlib in your Python environment by using 'pip install matplotlib'.",
705
- )
706
- return
707
- self.waveform.export_to_matplotlib()
708
-
709
- #######################################
710
- # User Access Methods from BECConnector
711
- ######################################
712
- def load_config(self, path: str | None = None, gui: bool = False):
713
- """
714
- Load the configuration of the widget from YAML.
715
-
716
- Args:
717
- path(str): Path to the configuration file for non-GUI dialog mode.
718
- gui(bool): If True, use the GUI dialog to load the configuration file.
719
- """
720
- self.fig.load_config(path=path, gui=gui)
721
-
722
- def save_config(self, path: str | None = None, gui: bool = False):
723
- """
724
- Save the configuration of the widget to YAML.
725
-
726
- Args:
727
- path(str): Path to save the configuration file for non-GUI dialog mode.
728
- gui(bool): If True, use the GUI dialog to save the configuration file.
729
- """
730
- self.fig.save_config(path=path, gui=gui)
731
-
732
- def cleanup(self):
733
- self.fig.cleanup()
734
- return super().cleanup()
735
-
736
-
737
- def main(): # pragma: no cover
738
- from qtpy.QtWidgets import QApplication
739
-
740
- app = QApplication(sys.argv)
741
- widget = BECWaveformWidget()
742
- widget.plot(x_name="samx", y_name="bpm4i")
743
- widget.plot(y_name="bpm3i")
744
- widget.plot(y_name="bpm4a")
745
- widget.plot(y_name="bpm5i")
746
- widget.show()
747
- sys.exit(app.exec_())
748
-
749
-
750
- if __name__ == "__main__": # pragma: no cover
751
- main()