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.
Files changed (196) hide show
  1. .gitlab-ci.yml +3 -5
  2. CHANGELOG.md +639 -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 +188 -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.1.dist-info}/METADATA +3 -3
  146. {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.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.1.dist-info}/WHEEL +0 -0
  195. {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.dist-info}/entry_points.txt +0 -0
  196. {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.qt_utils.error_popups import SafeSlot, WarningPopupUtility
4
- from bec_widgets.qt_utils.toolbar import MaterialIconAction, SwitchableToolBarAction, ToolbarBundle
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.qt_utils.toolbar import MaterialIconAction, ToolbarBundle
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.qt_utils.error_popups import SafeSlot
2
- from bec_widgets.qt_utils.toolbar import MaterialIconAction, ToolbarBundle
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):
@@ -1,75 +1,67 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Literal, Optional
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.logger import bec_logger
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.containers.figure.plots.waveform import BECWaveform1D
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
- class SignalData(BaseModel):
20
- """The data configuration of a signal in the 1D waveform widget for x and y axis."""
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
- unit: Optional[str] = None # todo implement later
25
- modifier: Optional[str] = None # todo implement later
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: Optional[str] = Field(None, description="The parent plot of the curve.")
43
- label: Optional[str] = Field(None, description="The label of the curve.")
44
- color: Optional[str | tuple] = Field(None, description="The color of the curve.")
45
- symbol: Optional[str | None] = Field("o", description="The symbol of the curve.")
46
- symbol_color: Optional[str | tuple] = Field(
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: Optional[int] = Field(7, description="The size of the symbol of the curve.")
50
- pen_width: Optional[int] = Field(4, description="The width of the pen of the curve.")
51
- pen_style: Optional[Literal["solid", "dash", "dot", "dashdot"]] = Field(
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: Optional[str] = Field(None, description="The source of the curve.")
55
- signals: Optional[Signal] = Field(None, description="The signal of the curve.")
56
- color_map_z: Optional[str] = Field(
57
- "magma", description="The colormap of the curves z gradient.", validate_default=True
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 BECCurve(BECConnector, pg.PlotDataItem):
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: Optional[str] = None,
89
- config: Optional[CurveConfig] = None,
90
- gui_id: Optional[str] = None,
91
- parent_item: Optional[BECWaveform1D] = None,
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
- def set_data(self, x, y):
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: Optional[str] = None):
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.scan_history(-1)
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.getData()
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
- self.rpc_register.remove_rpc(self)
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()