bec-widgets 0.87.1__py3-none-any.whl → 0.88.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 (59) hide show
  1. CHANGELOG.md +58 -62
  2. PKG-INFO +1 -1
  3. bec_widgets/assets/designer_icons/BECWaveformWidget.png +0 -0
  4. bec_widgets/assets/designer_icons/colormap_selector.png +0 -0
  5. bec_widgets/assets/toolbar_icons/add.svg +3 -0
  6. bec_widgets/assets/toolbar_icons/auto_range.svg +3 -0
  7. bec_widgets/assets/toolbar_icons/drag_pan_mode.svg +3 -0
  8. bec_widgets/assets/toolbar_icons/export.svg +9 -0
  9. bec_widgets/assets/toolbar_icons/fitting_parameters.svg +3 -0
  10. bec_widgets/assets/toolbar_icons/import.svg +9 -0
  11. bec_widgets/assets/toolbar_icons/line_axis.svg +3 -0
  12. bec_widgets/assets/toolbar_icons/photo_library.svg +3 -0
  13. bec_widgets/assets/toolbar_icons/rectangle_mode.svg +3 -0
  14. bec_widgets/assets/toolbar_icons/remove.svg +5 -0
  15. bec_widgets/assets/toolbar_icons/save.svg +3 -0
  16. bec_widgets/assets/toolbar_icons/settings.svg +4 -0
  17. bec_widgets/cli/client.py +307 -5
  18. bec_widgets/cli/server.py +2 -1
  19. bec_widgets/examples/jupyter_console/jupyter_console_window.py +12 -5
  20. bec_widgets/examples/plugin_example_pyside/tictactoe.py +1 -0
  21. bec_widgets/widgets/{color_map_selector/color_map_selector.py → colormap_selector/colormap_selector.py} +3 -1
  22. bec_widgets/widgets/colormap_selector/colormap_selector.pyproject +1 -0
  23. bec_widgets/widgets/{color_map_selector/color_map_selector_plugin.py → colormap_selector/colormap_selector_plugin.py} +8 -6
  24. bec_widgets/widgets/{color_map_selector/register_color_map_selector.py → colormap_selector/register_colormap_selector.py} +1 -1
  25. bec_widgets/widgets/figure/figure.py +12 -0
  26. bec_widgets/widgets/figure/plots/axis_settings.py +38 -11
  27. bec_widgets/widgets/figure/plots/image/image.py +1 -0
  28. bec_widgets/widgets/figure/plots/motor_map/motor_map.py +1 -0
  29. bec_widgets/widgets/figure/plots/plot_base.py +7 -3
  30. bec_widgets/widgets/figure/plots/waveform/waveform.py +48 -50
  31. bec_widgets/widgets/figure/plots/waveform/waveform_curve.py +9 -0
  32. bec_widgets/widgets/motor_map/bec_motor_map_widget_plugin.py +1 -1
  33. bec_widgets/widgets/motor_map/motor_map_widget.py +7 -0
  34. bec_widgets/widgets/waveform/__init__.py +0 -0
  35. bec_widgets/widgets/waveform/bec_waveform_widget.pyproject +1 -0
  36. bec_widgets/widgets/waveform/bec_waveform_widget_plugin.py +59 -0
  37. bec_widgets/widgets/waveform/register_bec_waveform_widget.py +15 -0
  38. bec_widgets/widgets/waveform/waveform_toolbar/__init__.py +0 -0
  39. bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/__init__.py +0 -0
  40. bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/curve_dialog.py +341 -0
  41. bec_widgets/widgets/waveform/waveform_toolbar/curve_dialog/curve_dialog.ui +358 -0
  42. bec_widgets/widgets/waveform/waveform_toolbar/dap_summary_dialog/__init__.py +0 -0
  43. bec_widgets/widgets/waveform/waveform_toolbar/dap_summary_dialog/dap_summary.ui +127 -0
  44. bec_widgets/widgets/waveform/waveform_toolbar/dap_summary_dialog/dap_summary_dialog.py +69 -0
  45. bec_widgets/widgets/waveform/waveform_toolbar/waveform_toolbar.py +117 -0
  46. bec_widgets/widgets/waveform/waveform_widget.py +571 -0
  47. {bec_widgets-0.87.1.dist-info → bec_widgets-0.88.0.dist-info}/METADATA +1 -1
  48. {bec_widgets-0.87.1.dist-info → bec_widgets-0.88.0.dist-info}/RECORD +57 -30
  49. pyproject.toml +1 -1
  50. tests/unit_tests/test_color_map_selector.py +1 -1
  51. tests/unit_tests/test_waveform_widget.py +264 -0
  52. bec_widgets/widgets/color_map_selector/assets/color_map_selector_icon.png +0 -0
  53. bec_widgets/widgets/color_map_selector/color_map_selector.pyproject +0 -1
  54. /bec_widgets/assets/{bec_widgets_icon.png → app_icons/bec_widgets_icon.png} +0 -0
  55. /bec_widgets/assets/{terminal_icon.png → app_icons/terminal_icon.png} +0 -0
  56. /bec_widgets/widgets/{color_map_selector → colormap_selector}/__init__.py +0 -0
  57. {bec_widgets-0.87.1.dist-info → bec_widgets-0.88.0.dist-info}/WHEEL +0 -0
  58. {bec_widgets-0.87.1.dist-info → bec_widgets-0.88.0.dist-info}/entry_points.txt +0 -0
  59. {bec_widgets-0.87.1.dist-info → bec_widgets-0.88.0.dist-info}/licenses/LICENSE +0 -0
@@ -49,8 +49,9 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
49
49
  "d0": self.d0,
50
50
  "d1": self.d1,
51
51
  "d2": self.d2,
52
- "plt": self.plt,
52
+ "wave": self.wave,
53
53
  "bar": self.bar,
54
+ "cm": self.colormap,
54
55
  }
55
56
  )
56
57
 
@@ -165,12 +166,16 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
165
166
  self.fig1.plot(x_name="samx", y_name="bpm3a")
166
167
 
167
168
  self.d2 = self.dock.add_dock(name="dock_2", position="bottom")
168
- self.fig2 = self.d2.add_widget("BECFigure", row=0, col=0)
169
- self.plt = self.fig2.plot(x_name="samx", y_name="bpm3a")
170
- self.plt.plot(x_name="samx", y_name="bpm4i", dap="GaussianModel")
169
+ self.wave = self.d2.add_widget("BECWaveformWidget", row=0, col=0)
170
+ # self.wave.plot(x_name="samx", y_name="bpm3a")
171
+ # self.wave.plot(x_name="samx", y_name="bpm4i", dap="GaussianModel")
171
172
  self.bar = self.d2.add_widget("RingProgressBar", row=0, col=1)
172
173
  self.bar.set_diameter(200)
173
174
 
175
+ self.d3 = self.dock.add_dock(name="dock_3", position="bottom")
176
+ self.colormap = pg.GradientWidget()
177
+ self.d3.add_widget(self.colormap, row=0, col=0)
178
+
174
179
  self.dock.save_state()
175
180
 
176
181
  def closeEvent(self, event):
@@ -196,7 +201,9 @@ if __name__ == "__main__": # pragma: no cover
196
201
  app.setApplicationDisplayName("Jupyter Console")
197
202
  apply_theme("dark")
198
203
  icon = QIcon()
199
- icon.addFile(os.path.join(module_path, "assets", "terminal_icon.png"), size=QSize(48, 48))
204
+ icon.addFile(
205
+ os.path.join(module_path, "assets", "app_icons", "terminal_icon.png"), size=QSize(48, 48)
206
+ )
200
207
  app.setWindowIcon(icon)
201
208
 
202
209
  bec_dispatcher = BECDispatcher()
@@ -16,6 +16,7 @@ class TicTacToe(QWidget): # pragma: no cover
16
16
  super().__init__(parent)
17
17
  self._state = DEFAULT_STATE
18
18
  self._turn_number = 0
19
+ print("TicTac HERE !!!!!!")
19
20
 
20
21
  def minimumSizeHint(self):
21
22
  return QSize(200, 200)
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import pyqtgraph as pg
2
4
  from qtpy.QtCore import Property, Signal, Slot
3
5
  from qtpy.QtGui import QColor, QFontMetrics, QImage
@@ -46,7 +48,7 @@ class ColormapSelector(QWidget):
46
48
  colormap_changed_signal = Signal(str)
47
49
 
48
50
  def __init__(self, parent=None, default_colormaps=None):
49
- super().__init__(parent)
51
+ super().__init__(parent=parent)
50
52
  self._colormaps = []
51
53
  self.initUI(default_colormaps)
52
54
 
@@ -0,0 +1 @@
1
+ {'files': ['colormap_selector.py']}
@@ -5,15 +5,18 @@ import os
5
5
  from qtpy.QtDesigner import QDesignerCustomWidgetInterface
6
6
  from qtpy.QtGui import QIcon
7
7
 
8
- from bec_widgets.widgets.color_map_selector.color_map_selector import ColormapSelector
8
+ import bec_widgets
9
+ from bec_widgets.widgets.colormap_selector.colormap_selector import ColormapSelector
9
10
 
10
11
  DOM_XML = """
11
12
  <ui language='c++'>
12
- <widget class='ColormapSelector' name='color_map_selector'>
13
+ <widget class='ColormapSelector' name='colormap_selector'>
13
14
  </widget>
14
15
  </ui>
15
16
  """
16
17
 
18
+ MODULE_PATH = os.path.dirname(bec_widgets.__file__)
19
+
17
20
 
18
21
  class ColormapSelectorPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
19
22
  def __init__(self):
@@ -31,12 +34,11 @@ class ColormapSelectorPlugin(QDesignerCustomWidgetInterface): # pragma: no cove
31
34
  return "BEC Buttons"
32
35
 
33
36
  def icon(self):
34
- current_path = os.path.dirname(__file__)
35
- icon_path = os.path.join(current_path, "assets", "color_map_selector_icon.png")
37
+ icon_path = os.path.join(MODULE_PATH, "assets", "designer_icons", "colormap_selector.png")
36
38
  return QIcon(icon_path)
37
39
 
38
40
  def includeFile(self):
39
- return "color_map_selector"
41
+ return "colormap_selector"
40
42
 
41
43
  def initialize(self, form_editor):
42
44
  self._form_editor = form_editor
@@ -51,7 +53,7 @@ class ColormapSelectorPlugin(QDesignerCustomWidgetInterface): # pragma: no cove
51
53
  return "ColormapSelector"
52
54
 
53
55
  def toolTip(self):
54
- return "A custom QComboBox widget for selecting colormaps."
56
+ return ""
55
57
 
56
58
  def whatsThis(self):
57
59
  return self.toolTip()
@@ -6,7 +6,7 @@ def main(): # pragma: no cover
6
6
  return
7
7
  from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
8
8
 
9
- from bec_widgets.widgets.color_map_selector.color_map_selector_plugin import (
9
+ from bec_widgets.widgets.colormap_selector.colormap_selector_plugin import (
10
10
  ColormapSelectorPlugin,
11
11
  )
12
12
 
@@ -122,6 +122,7 @@ class BECFigure(BECWidget, pg.GraphicsLayoutWidget):
122
122
  "remove",
123
123
  "change_layout",
124
124
  "change_theme",
125
+ "export",
125
126
  "clear_all",
126
127
  "widget_list",
127
128
  ]
@@ -228,6 +229,17 @@ class BECFigure(BECWidget, pg.GraphicsLayoutWidget):
228
229
  """
229
230
  self._widgets = value
230
231
 
232
+ def export(self):
233
+ """Export the plot widget."""
234
+ try:
235
+ plot_item = self.widget_list[0]
236
+ except:
237
+ raise ValueError("No plot widget available to export.")
238
+
239
+ scene = plot_item.scene()
240
+ scene.contextMenuItem = plot_item
241
+ scene.showExportDialog()
242
+
231
243
  @typechecked
232
244
  def plot(
233
245
  self,
@@ -1,14 +1,14 @@
1
1
  import os
2
2
 
3
3
  from qtpy.QtCore import Slot
4
- from qtpy.QtWidgets import QVBoxLayout, QWidget
4
+ from qtpy.QtWidgets import QVBoxLayout
5
5
 
6
+ from bec_widgets.qt_utils.settings_dialog import SettingWidget
6
7
  from bec_widgets.utils import UILoader
7
- from bec_widgets.utils.colors import apply_theme
8
8
  from bec_widgets.utils.widget_io import WidgetIO
9
9
 
10
10
 
11
- class AxisSettings(QWidget):
11
+ class AxisSettings(SettingWidget):
12
12
  def __init__(self, parent=None, *args, **kwargs):
13
13
  super().__init__(parent=parent, *args, **kwargs)
14
14
 
@@ -25,6 +25,10 @@ class AxisSettings(QWidget):
25
25
 
26
26
  @Slot(dict)
27
27
  def display_current_settings(self, axis_config: dict):
28
+
29
+ if axis_config == {}:
30
+ return
31
+
28
32
  # Top Box
29
33
  WidgetIO.set_value(self.ui.plot_title, axis_config["title"])
30
34
 
@@ -37,6 +41,10 @@ class AxisSettings(QWidget):
37
41
  WidgetIO.check_and_adjust_limits(self.ui.x_max, axis_config["x_lim"][1])
38
42
  WidgetIO.set_value(self.ui.x_min, axis_config["x_lim"][0])
39
43
  WidgetIO.set_value(self.ui.x_max, axis_config["x_lim"][1])
44
+ if axis_config["x_lim"] is None:
45
+ x_range = self.target_widget.fig.widget_list[0].plot_item.viewRange()[0]
46
+ WidgetIO.set_value(self.ui.x_min, x_range[0])
47
+ WidgetIO.set_value(self.ui.x_max, x_range[1])
40
48
 
41
49
  # Y Axis Box
42
50
  WidgetIO.set_value(self.ui.y_label, axis_config["y_label"])
@@ -47,15 +55,34 @@ class AxisSettings(QWidget):
47
55
  WidgetIO.check_and_adjust_limits(self.ui.y_max, axis_config["y_lim"][1])
48
56
  WidgetIO.set_value(self.ui.y_min, axis_config["y_lim"][0])
49
57
  WidgetIO.set_value(self.ui.y_max, axis_config["y_lim"][1])
58
+ if axis_config["y_lim"] is None:
59
+ y_range = self.target_widget.fig.widget_list[0].plot_item.viewRange()[1]
60
+ WidgetIO.set_value(self.ui.y_min, y_range[0])
61
+ WidgetIO.set_value(self.ui.y_max, y_range[1])
50
62
 
63
+ @Slot()
64
+ def accept_changes(self):
65
+ title = WidgetIO.get_value(self.ui.plot_title)
51
66
 
52
- if __name__ == "__main__":
53
- import sys
67
+ # X Axis
68
+ x_label = WidgetIO.get_value(self.ui.x_label)
69
+ x_scale = self.ui.x_scale.currentText()
70
+ x_grid = WidgetIO.get_value(self.ui.x_grid)
71
+ x_lim = (WidgetIO.get_value(self.ui.x_min), WidgetIO.get_value(self.ui.x_max))
54
72
 
55
- from qtpy.QtWidgets import QApplication
73
+ # Y Axis
74
+ y_label = WidgetIO.get_value(self.ui.y_label)
75
+ y_scale = self.ui.y_scale.currentText()
76
+ y_grid = WidgetIO.get_value(self.ui.y_grid)
77
+ y_lim = (WidgetIO.get_value(self.ui.y_min), WidgetIO.get_value(self.ui.y_max))
56
78
 
57
- app = QApplication(sys.argv)
58
- apply_theme("dark")
59
- window = AxisSettings()
60
- window.show()
61
- sys.exit(app.exec_())
79
+ self.target_widget.set(
80
+ title=title,
81
+ x_label=x_label,
82
+ x_scale=x_scale,
83
+ x_lim=x_lim,
84
+ y_label=y_label,
85
+ y_scale=y_scale,
86
+ y_lim=y_lim,
87
+ )
88
+ self.target_widget.set_grid(x_grid, y_grid)
@@ -55,6 +55,7 @@ class BECImageShow(BECPlotBase):
55
55
  "set_y_lim",
56
56
  "set_grid",
57
57
  "lock_aspect_ratio",
58
+ "export",
58
59
  "remove",
59
60
  "images",
60
61
  ]
@@ -58,6 +58,7 @@ class BECMotorMap(BECPlotBase):
58
58
  "set_background_value",
59
59
  "set_scatter_size",
60
60
  "get_data",
61
+ "export",
61
62
  "remove",
62
63
  "reset_history",
63
64
  ]
@@ -2,11 +2,8 @@ from __future__ import annotations
2
2
 
3
3
  from typing import Literal, Optional
4
4
 
5
- import numpy as np
6
5
  import pyqtgraph as pg
7
6
  from pydantic import BaseModel, Field
8
- from qtpy import QT_VERSION
9
- from qtpy.QtGui import QFont, QFontDatabase, QFontInfo
10
7
  from qtpy.QtWidgets import QWidget
11
8
 
12
9
  from bec_widgets.utils import BECConnector, ConnectionConfig
@@ -57,6 +54,7 @@ class BECPlotBase(BECConnector, pg.GraphicsLayout):
57
54
  "set_y_lim",
58
55
  "set_grid",
59
56
  "lock_aspect_ratio",
57
+ "export",
60
58
  "remove",
61
59
  "set_legend_label_size",
62
60
  ]
@@ -293,6 +291,12 @@ class BECPlotBase(BECConnector, pg.GraphicsLayout):
293
291
  """
294
292
  self.plot_item.setAspectLocked(lock)
295
293
 
294
+ def export(self):
295
+ """Show the Export Dialog of the plot widget."""
296
+ scene = self.plot_item.scene()
297
+ scene.contextMenuItem = self.plot_item
298
+ scene.showExportDialog()
299
+
296
300
  def remove(self):
297
301
  """Remove the plot widget from the figure."""
298
302
  if self.figure is not None:
@@ -1,7 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import datetime
4
- import time
5
3
  from collections import defaultdict
6
4
  from typing import Any, Literal, Optional
7
5
 
@@ -10,7 +8,8 @@ import pyqtgraph as pg
10
8
  from bec_lib import messages
11
9
  from bec_lib.device import ReadoutPriority
12
10
  from bec_lib.endpoints import MessageEndpoints
13
- from pydantic import Field, ValidationError
11
+ from pydantic import Field, ValidationError, field_validator
12
+ from pyqtgraph.exporters import MatplotlibExporter
14
13
  from qtpy.QtCore import Signal as pyqtSignal
15
14
  from qtpy.QtCore import Slot as pyqtSlot
16
15
  from qtpy.QtWidgets import QWidget
@@ -26,13 +25,16 @@ from bec_widgets.widgets.figure.plots.waveform.waveform_curve import (
26
25
 
27
26
 
28
27
  class Waveform1DConfig(SubplotConfig):
29
- color_palette: Literal["plasma", "viridis", "inferno", "magma"] = Field(
30
- "plasma", description="The color palette of the figure widget."
28
+ color_palette: Optional[str] = Field(
29
+ "plasma", description="The color palette of the figure widget.", validate_default=True
31
30
  )
32
31
  curves: dict[str, CurveConfig] = Field(
33
32
  {}, description="The list of curves to be added to the 1D waveform widget."
34
33
  )
35
34
 
35
+ model_config: dict = {"validate_assignment": True}
36
+ _validate_color_map_z = field_validator("color_palette")(Colors.validate_color_map)
37
+
36
38
 
37
39
  class BECWaveform(BECPlotBase):
38
40
  READOUT_PRIORITY_HANDLER = {
@@ -63,7 +65,9 @@ class BECWaveform(BECPlotBase):
63
65
  "set_x_lim",
64
66
  "set_y_lim",
65
67
  "set_grid",
68
+ "set_colormap",
66
69
  "lock_aspect_ratio",
70
+ "export",
67
71
  "remove",
68
72
  "clear_all",
69
73
  "set_legend_label_size",
@@ -71,6 +75,7 @@ class BECWaveform(BECPlotBase):
71
75
  scan_signal_update = pyqtSignal()
72
76
  async_signal_update = pyqtSignal()
73
77
  dap_params_update = pyqtSignal(dict)
78
+ dap_summary_update = pyqtSignal(dict)
74
79
  autorange_signal = pyqtSignal()
75
80
 
76
81
  def __init__(
@@ -385,7 +390,6 @@ class BECWaveform(BECPlotBase):
385
390
 
386
391
  self.async_signal_update.emit()
387
392
  self.scan_signal_update.emit()
388
- # self.autorange_timer.start(200)
389
393
 
390
394
  @pyqtSlot()
391
395
  def auto_range(self):
@@ -651,6 +655,19 @@ class BECWaveform(BECPlotBase):
651
655
  params[curve_id] = curve.dap_params
652
656
  return params
653
657
 
658
+ @pyqtSlot()
659
+ def get_dap_summary(self) -> dict:
660
+ """
661
+ Get the DAP summary of all DAP curves.
662
+
663
+ Returns:
664
+ dict: DAP summary of all DAP curves.
665
+ """
666
+ summary = {}
667
+ for curve_id, curve in self._curves_data["DAP"].items():
668
+ summary[curve_id] = curve.dap_summary
669
+ return summary
670
+
654
671
  def _add_curve_object(
655
672
  self,
656
673
  name: str,
@@ -954,6 +971,22 @@ class BECWaveform(BECPlotBase):
954
971
  current_label = "" if self.config.axis.x_label is None else self.config.axis.x_label
955
972
  self.plot_item.setLabel("bottom", f"{current_label}{self._x_axis_mode['label_suffix']}")
956
973
 
974
+ def set_colormap(self, colormap: str | None = None):
975
+ """
976
+ Set the colormap of the plot widget.
977
+
978
+ Args:
979
+ colormap(str, optional): Scale the colors of curves to colormap. If None, use the default color palette.
980
+ """
981
+ if colormap is not None:
982
+ self.config.color_palette = colormap
983
+
984
+ colors = Colors.golden_angle_color(
985
+ colormap=self.config.color_palette, num=len(self.plot_item.curves) + 1, format="HEX"
986
+ )
987
+ for curve, color in zip(self.curves, colors):
988
+ curve.set_color(color)
989
+
957
990
  def setup_dap(self, old_scan_id: str | None, new_scan_id: str | None):
958
991
  """
959
992
  Setup DAP for the new scan.
@@ -1051,7 +1084,9 @@ class BECWaveform(BECPlotBase):
1051
1084
  y = msg["data"][0]["y"]
1052
1085
  curve.setData(x, y)
1053
1086
  curve.dap_params = msg["data"][1]["fit_parameters"]
1087
+ curve.dap_summary = msg["data"][1]["fit_summary"]
1054
1088
  self.dap_params_update.emit(curve.dap_params)
1089
+ self.dap_summary_update.emit(curve.dap_summary)
1055
1090
  break
1056
1091
 
1057
1092
  @pyqtSlot(dict, dict)
@@ -1180,7 +1215,6 @@ class BECWaveform(BECPlotBase):
1180
1215
  timestamps = self.scan_item.data[y_name][y_entry].timestamps
1181
1216
 
1182
1217
  x_data = timestamps
1183
- print(x_data)
1184
1218
  return x_data
1185
1219
  if self._x_axis_mode["name"] == "index":
1186
1220
  x_data = None
@@ -1214,49 +1248,6 @@ class BECWaveform(BECPlotBase):
1214
1248
  x_data = []
1215
1249
  return x_data
1216
1250
 
1217
- # def _get_x_data(self, curve: BECCurve, y_name: str, y_entry: str) -> list | np.ndarray | None:
1218
- # """
1219
- # Get the x data for the curve with the decision logic based on the curve configuration:
1220
- # - If x is called 'timestamp', use the timestamp data from the scan item.
1221
- # - If x is called 'index', use the rolling index.
1222
- # - If x is a custom signal, use the data from the scan item.
1223
- # - If x is not specified, use the first device from the scan report.
1224
- #
1225
- # Args:
1226
- # curve(BECCurve): The curve object.
1227
- #
1228
- # Returns:
1229
- # list|np.ndarray|None: X data for the curve.
1230
- # """
1231
- # x_data = None
1232
- # if curve.config.signals.x is not None:
1233
- # if curve.config.signals.x.name == "timestamp":
1234
- # timestamps = self.scan_item.data[y_name][y_entry].timestamps
1235
- # x_data = self.convert_timestamps(timestamps)
1236
- # elif curve.config.signals.x.name == "index":
1237
- # x_data = None
1238
- # else:
1239
- # x_name = curve.config.signals.x.name
1240
- # x_entry = curve.config.signals.x.entry
1241
- # try:
1242
- # x_data = self.scan_item.data[x_name][x_entry].val
1243
- # except TypeError:
1244
- # x_data = []
1245
- # else:
1246
- # if len(self._curves_data["async"]) > 0:
1247
- # x_data = None
1248
- # else:
1249
- # x_name = self.scan_item.status_message.info["scan_report_devices"][0]
1250
- # x_entry = self.entry_validator.validate_signal(x_name, None)
1251
- # x_data = self.scan_item.data[x_name][x_entry].val
1252
- # self._x_axis_mode["label_suffix"] = f" [auto: {x_name}-{x_entry}]"
1253
- # current_label = "" if self.config.axis.x_label is None else self.config.axis.x_label
1254
- # self.plot_item.setLabel(
1255
- # "bottom", f"{current_label}{self._x_axis_mode['label_suffix']}"
1256
- # )
1257
- #
1258
- # return x_data
1259
-
1260
1251
  def _make_z_gradient(self, data_z: list | np.ndarray, colormap: str) -> list | None:
1261
1252
  """
1262
1253
  Make a gradient color for the z values.
@@ -1349,6 +1340,13 @@ class BECWaveform(BECPlotBase):
1349
1340
  return combined_data
1350
1341
  return data
1351
1342
 
1343
+ def export_to_matplotlib(self):
1344
+ """
1345
+ Export current waveform to matplotlib gui. Available only if matplotlib is installed in the enviroment.
1346
+
1347
+ """
1348
+ MatplotlibExporter(self.plot_item).export()
1349
+
1352
1350
  def clear_all(self):
1353
1351
  curves_data = self._curves_data
1354
1352
  sources = list(curves_data.keys())
@@ -101,6 +101,7 @@ class BECCurve(BECConnector, pg.PlotDataItem):
101
101
  self.parent_item = parent_item
102
102
  self.apply_config()
103
103
  self.dap_params = None
104
+ self.dap_summary = None
104
105
  if kwargs:
105
106
  self.set(**kwargs)
106
107
 
@@ -132,6 +133,14 @@ class BECCurve(BECConnector, pg.PlotDataItem):
132
133
  def dap_params(self, value):
133
134
  self._dap_params = value
134
135
 
136
+ @property
137
+ def dap_summary(self):
138
+ return self._dap_report
139
+
140
+ @dap_summary.setter
141
+ def dap_summary(self, value):
142
+ self._dap_report = value
143
+
135
144
  def set_data(self, x, y):
136
145
  if self.config.source == "custom":
137
146
  self.setData(x, y)
@@ -26,7 +26,7 @@ class BECMotorMapWidgetPlugin(QDesignerCustomWidgetInterface): # pragma: no cov
26
26
  return DOM_XML
27
27
 
28
28
  def group(self):
29
- return "BEC Visualization Widgets"
29
+ return "BEC Plots"
30
30
 
31
31
  def icon(self):
32
32
  current_path = os.path.dirname(__file__)
@@ -28,6 +28,7 @@ class BECMotorMapWidget(BECWidget, QWidget):
28
28
  "set_scatter_size",
29
29
  "get_data",
30
30
  "reset_history",
31
+ "export",
31
32
  ]
32
33
 
33
34
  def __init__(
@@ -202,6 +203,12 @@ class BECMotorMapWidget(BECWidget, QWidget):
202
203
  """
203
204
  self.map.set_scatter_size(scatter_size)
204
205
 
206
+ def export(self):
207
+ """
208
+ Show the export dialog for the motor map.
209
+ """
210
+ self.map.export()
211
+
205
212
  def cleanup(self):
206
213
  self.fig.cleanup()
207
214
  self.toolbar.widgets["motor_x"].device_combobox.cleanup()
File without changes
@@ -0,0 +1 @@
1
+ {'files': ['waveform_widget.py']}
@@ -0,0 +1,59 @@
1
+ # Copyright (C) 2022 The Qt Company Ltd.
2
+ # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
3
+ import os
4
+
5
+ from qtpy.QtDesigner import QDesignerCustomWidgetInterface
6
+ from qtpy.QtGui import QIcon
7
+
8
+ import bec_widgets
9
+ from bec_widgets.widgets.waveform.waveform_widget import BECWaveformWidget
10
+
11
+ DOM_XML = """
12
+ <ui language='c++'>
13
+ <widget class='BECWaveformWidget' name='bec_waveform_widget'>
14
+ </widget>
15
+ </ui>
16
+ """
17
+
18
+ MODULE_PATH = os.path.dirname(bec_widgets.__file__)
19
+
20
+
21
+ class BECWaveformWidgetPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
22
+ def __init__(self):
23
+ super().__init__()
24
+ self._form_editor = None
25
+
26
+ def createWidget(self, parent):
27
+ t = BECWaveformWidget(parent)
28
+ return t
29
+
30
+ def domXml(self):
31
+ return DOM_XML
32
+
33
+ def group(self):
34
+ return "BEC Plots"
35
+
36
+ def icon(self):
37
+ icon_path = os.path.join(MODULE_PATH, "assets", "designer_icons", "BECWaveformWidget.png")
38
+ return QIcon(icon_path)
39
+
40
+ def includeFile(self):
41
+ return "bec_waveform_widget"
42
+
43
+ def initialize(self, form_editor):
44
+ self._form_editor = form_editor
45
+
46
+ def isContainer(self):
47
+ return False
48
+
49
+ def isInitialized(self):
50
+ return self._form_editor is not None
51
+
52
+ def name(self):
53
+ return "BECWaveformWidget"
54
+
55
+ def toolTip(self):
56
+ return "BECWaveformWidget"
57
+
58
+ def whatsThis(self):
59
+ return self.toolTip()
@@ -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.waveform.bec_waveform_widget_plugin import BECWaveformWidgetPlugin
10
+
11
+ QPyDesignerCustomWidgetCollection.addCustomWidget(BECWaveformWidgetPlugin())
12
+
13
+
14
+ if __name__ == "__main__": # pragma: no cover
15
+ main()