bec-widgets 0.76.0__py3-none-any.whl → 0.77.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 (40) hide show
  1. CHANGELOG.md +42 -44
  2. PKG-INFO +2 -1
  3. bec_widgets/cli/client.py +73 -196
  4. bec_widgets/examples/jupyter_console/jupyter_console_window.py +25 -4
  5. bec_widgets/utils/bec_connector.py +66 -8
  6. bec_widgets/utils/colors.py +38 -0
  7. bec_widgets/utils/generate_designer_plugin.py +15 -14
  8. bec_widgets/utils/yaml_dialog.py +27 -3
  9. bec_widgets/widgets/console/console.py +496 -0
  10. bec_widgets/widgets/dock/dock.py +2 -2
  11. bec_widgets/widgets/dock/dock_area.py +2 -2
  12. bec_widgets/widgets/figure/figure.py +149 -195
  13. bec_widgets/widgets/figure/plots/image/image.py +62 -49
  14. bec_widgets/widgets/figure/plots/image/image_item.py +4 -3
  15. bec_widgets/widgets/figure/plots/motor_map/motor_map.py +98 -29
  16. bec_widgets/widgets/figure/plots/plot_base.py +1 -1
  17. bec_widgets/widgets/figure/plots/waveform/waveform.py +7 -8
  18. bec_widgets/widgets/figure/plots/waveform/waveform_curve.py +2 -2
  19. bec_widgets/widgets/ring_progress_bar/ring.py +3 -3
  20. bec_widgets/widgets/ring_progress_bar/ring_progress_bar.py +3 -3
  21. {bec_widgets-0.76.0.dist-info → bec_widgets-0.77.0.dist-info}/METADATA +2 -1
  22. {bec_widgets-0.76.0.dist-info → bec_widgets-0.77.0.dist-info}/RECORD +40 -38
  23. pyproject.toml +2 -1
  24. tests/end-2-end/test_bec_dock_rpc_e2e.py +16 -16
  25. tests/end-2-end/test_bec_figure_rpc_e2e.py +7 -7
  26. tests/end-2-end/test_rpc_register_e2e.py +8 -8
  27. tests/unit_tests/client_mocks.py +1 -0
  28. tests/unit_tests/test_bec_figure.py +49 -26
  29. tests/unit_tests/test_bec_motor_map.py +179 -41
  30. tests/unit_tests/test_color_validation.py +15 -0
  31. tests/unit_tests/test_device_input_base.py +1 -1
  32. tests/unit_tests/test_device_input_widgets.py +2 -0
  33. tests/unit_tests/test_generate_plugin.py +155 -0
  34. tests/unit_tests/test_motor_control.py +5 -4
  35. tests/unit_tests/test_plot_base.py +3 -3
  36. tests/unit_tests/test_waveform1d.py +18 -17
  37. tests/unit_tests/test_yaml_dialog.py +7 -7
  38. {bec_widgets-0.76.0.dist-info → bec_widgets-0.77.0.dist-info}/WHEEL +0 -0
  39. {bec_widgets-0.76.0.dist-info → bec_widgets-0.77.0.dist-info}/entry_points.txt +0 -0
  40. {bec_widgets-0.76.0.dist-info → bec_widgets-0.77.0.dist-info}/licenses/LICENSE +0 -0
@@ -5,7 +5,7 @@ from typing import Any, Literal, Optional
5
5
 
6
6
  import numpy as np
7
7
  from bec_lib.endpoints import MessageEndpoints
8
- from pydantic import Field, ValidationError
8
+ from pydantic import BaseModel, Field, ValidationError
9
9
  from qtpy.QtCore import QThread
10
10
  from qtpy.QtCore import Slot as pyqtSlot
11
11
  from qtpy.QtWidgets import QWidget
@@ -29,11 +29,9 @@ class ImageConfig(SubplotConfig):
29
29
 
30
30
  class BECImageShow(BECPlotBase):
31
31
  USER_ACCESS = [
32
- "rpc_id",
33
- "config_dict",
32
+ "_rpc_id",
33
+ "_config_dict",
34
34
  "add_image_by_config",
35
- "get_image_config",
36
- "get_image_dict",
37
35
  "add_monitor_image",
38
36
  "add_custom_image",
39
37
  "set_vrange",
@@ -47,7 +45,6 @@ class BECImageShow(BECPlotBase):
47
45
  "set_log",
48
46
  "set_rotation",
49
47
  "set_transpose",
50
- "toggle_threading",
51
48
  "set",
52
49
  "set_title",
53
50
  "set_x_label",
@@ -138,7 +135,8 @@ class BECImageShow(BECPlotBase):
138
135
  self.apply_axis_config()
139
136
  self._images = defaultdict(dict)
140
137
 
141
- # TODO extend by adding image by config
138
+ for image_id, image_config in config.images.items():
139
+ self.add_image_by_config(image_config)
142
140
 
143
141
  def change_gui_id(self, new_gui_id: str):
144
142
  """
@@ -226,7 +224,7 @@ class BECImageShow(BECPlotBase):
226
224
  self,
227
225
  monitor: str,
228
226
  color_map: Optional[str] = "magma",
229
- color_bar: Optional[Literal["simple", "full"]] = "simple",
227
+ color_bar: Optional[Literal["simple", "full"]] = "full",
230
228
  downsample: Optional[bool] = True,
231
229
  opacity: Optional[float] = 1.0,
232
230
  vrange: Optional[tuple[int, int]] = None,
@@ -241,7 +239,7 @@ class BECImageShow(BECPlotBase):
241
239
  f"Monitor with ID '{monitor}' already exists in widget '{self.gui_id}'."
242
240
  )
243
241
 
244
- monitor = self.entry_validator.validate_monitor(monitor)
242
+ # monitor = self.entry_validator.validate_monitor(monitor)
245
243
 
246
244
  image_config = ImageItemConfig(
247
245
  widget_class="BECImageItem",
@@ -251,12 +249,13 @@ class BECImageShow(BECPlotBase):
251
249
  downsample=downsample,
252
250
  opacity=opacity,
253
251
  vrange=vrange,
252
+ source=image_source,
253
+ monitor=monitor,
254
254
  # post_processing=post_processing,
255
255
  **kwargs,
256
256
  )
257
257
 
258
258
  image = self._add_image_object(source=image_source, name=monitor, config=image_config)
259
- self._connect_device_monitor(monitor)
260
259
  return image
261
260
 
262
261
  def add_custom_image(
@@ -264,16 +263,17 @@ class BECImageShow(BECPlotBase):
264
263
  name: str,
265
264
  data: Optional[np.ndarray] = None,
266
265
  color_map: Optional[str] = "magma",
267
- color_bar: Optional[Literal["simple", "full"]] = "simple",
266
+ color_bar: Optional[Literal["simple", "full"]] = "full",
268
267
  downsample: Optional[bool] = True,
269
268
  opacity: Optional[float] = 1.0,
270
269
  vrange: Optional[tuple[int, int]] = None,
271
270
  # post_processing: Optional[PostProcessingConfig] = None,
272
271
  **kwargs,
273
272
  ):
274
- image_source = "device_monitor"
273
+ image_source = "custom"
274
+ # image_source = "device_monitor"
275
275
 
276
- image_exits = self._check_curve_id(name, self._images)
276
+ image_exits = self._check_image_id(name, self._images)
277
277
  if image_exits:
278
278
  raise ValueError(f"Monitor with ID '{name}' already exists in widget '{self.gui_id}'.")
279
279
 
@@ -290,7 +290,9 @@ class BECImageShow(BECPlotBase):
290
290
  **kwargs,
291
291
  )
292
292
 
293
- image = self._add_image_object(source=image_source, config=image_config, data=data)
293
+ image = self._add_image_object(
294
+ source=image_source, name=name, config=image_config, data=data
295
+ )
294
296
  return image
295
297
 
296
298
  def apply_setting_to_images(
@@ -313,6 +315,7 @@ class BECImageShow(BECPlotBase):
313
315
  for source, images in self._images.items():
314
316
  for _, image in images.items():
315
317
  getattr(image, setting_method_name)(*args, **kwargs)
318
+ self.refresh_image()
316
319
 
317
320
  def set_vrange(self, vmin: float, vmax: float, name: str = None):
318
321
  """
@@ -460,18 +463,19 @@ class BECImageShow(BECPlotBase):
460
463
  if self.use_threading is False and self.thread.isRunning():
461
464
  self.cleanup()
462
465
 
463
- @pyqtSlot(dict)
464
- def on_image_update(self, msg: dict):
466
+ def process_image(self, device: str, image: BECImageItem, data: np.ndarray):
465
467
  """
466
- Update the image of the device monitor from bec.
468
+ Process the image data.
467
469
 
468
470
  Args:
469
- msg(dict): The message from bec.
471
+ device(str): The name of the device - image_id of image.
472
+ image(np.ndarray): The image data to be processed.
473
+ data(np.ndarray): The image data to be processed.
474
+
475
+ Returns:
476
+ np.ndarray: The processed image data.
470
477
  """
471
- data = msg["data"]
472
- device = msg["device"]
473
- image_to_update = self._images["device_monitor"][device]
474
- processing_config = image_to_update.config.processing
478
+ processing_config = image.config.processing
475
479
  self.processor.set_config(processing_config)
476
480
  if self.use_threading:
477
481
  self._create_thread_worker(device, data)
@@ -480,6 +484,19 @@ class BECImageShow(BECPlotBase):
480
484
  self.update_image(device, data)
481
485
  self.update_vrange(device, self.processor.config.stats)
482
486
 
487
+ @pyqtSlot(dict)
488
+ def on_image_update(self, msg: dict):
489
+ """
490
+ Update the image of the device monitor from bec.
491
+
492
+ Args:
493
+ msg(dict): The message from bec.
494
+ """
495
+ data = msg["data"]
496
+ device = msg["device"]
497
+ image = self._images["device_monitor"][device]
498
+ self.process_image(device, image, data)
499
+
483
500
  @pyqtSlot(str, np.ndarray)
484
501
  def update_image(self, device: str, data: np.ndarray):
485
502
  """
@@ -504,6 +521,15 @@ class BECImageShow(BECPlotBase):
504
521
  if image_to_update.config.autorange:
505
522
  image_to_update.auto_update_vrange(stats)
506
523
 
524
+ def refresh_image(self):
525
+ """
526
+ Refresh the image.
527
+ """
528
+ for source, images in self._images.items():
529
+ for image_id, image in images.items():
530
+ data = image.get_data()
531
+ self.process_image(image_id, image, data)
532
+
507
533
  def _connect_device_monitor(self, monitor: str):
508
534
  """
509
535
  Connect to the device monitor.
@@ -516,16 +542,18 @@ class BECImageShow(BECPlotBase):
516
542
  previous_monitor = image_item.config.monitor
517
543
  except AttributeError:
518
544
  previous_monitor = None
519
- if previous_monitor != monitor:
520
- if previous_monitor:
521
- self.bec_dispatcher.disconnect_slot(
522
- self.on_image_update, MessageEndpoints.device_monitor(previous_monitor)
523
- )
524
- if monitor:
525
- self.bec_dispatcher.connect_slot(
526
- self.on_image_update, MessageEndpoints.device_monitor(monitor)
527
- )
528
- image_item.set_monitor(monitor)
545
+ if previous_monitor and image_item.connected is True:
546
+ self.bec_dispatcher.disconnect_slot(
547
+ self.on_image_update, MessageEndpoints.device_monitor(previous_monitor)
548
+ )
549
+ image_item.connected = False
550
+ if monitor and image_item.connected is False:
551
+ self.entry_validator.validate_monitor(monitor)
552
+ self.bec_dispatcher.connect_slot(
553
+ self.on_image_update, MessageEndpoints.device_monitor(monitor)
554
+ )
555
+ image_item.set_monitor(monitor)
556
+ image_item.connected = True
529
557
 
530
558
  def _add_image_object(
531
559
  self, source: str, name: str, config: ImageItemConfig, data=None
@@ -534,6 +562,8 @@ class BECImageShow(BECPlotBase):
534
562
  image = BECImageItem(config=config, parent_image=self)
535
563
  self.plot_item.addItem(image)
536
564
  self._images[source][name] = image
565
+ if source == "device_monitor":
566
+ self._connect_device_monitor(config.monitor)
537
567
  self.config.images[name] = config
538
568
  if data is not None:
539
569
  image.setImage(data)
@@ -558,23 +588,6 @@ class BECImageShow(BECPlotBase):
558
588
  return True
559
589
  return False
560
590
 
561
- def _validate_monitor(self, monitor: str, validate_bec: bool = True):
562
- """
563
- Validate the monitor name.
564
-
565
- Args:
566
- monitor(str): The name of the monitor.
567
- validate_bec(bool): Whether to validate the monitor name with BEC.
568
-
569
- Returns:
570
- bool: True if the monitor name is valid, False otherwise.
571
- """
572
- if not monitor or monitor == "":
573
- return False
574
- if validate_bec:
575
- return monitor in self.dev
576
- return True
577
-
578
591
  def cleanup(self):
579
592
  """
580
593
  Clean up the widget.
@@ -20,7 +20,7 @@ class ImageItemConfig(ConnectionConfig):
20
20
  color_map: Optional[str] = Field("magma", description="The color map of the image.")
21
21
  downsample: Optional[bool] = Field(True, description="Whether to downsample the image.")
22
22
  opacity: Optional[float] = Field(1.0, description="The opacity of the image.")
23
- vrange: Optional[tuple[float, float]] = Field(
23
+ vrange: Optional[tuple[float | int, float | int]] = Field(
24
24
  None, description="The range of the color bar. If None, the range is automatically set."
25
25
  )
26
26
  color_bar: Optional[Literal["simple", "full"]] = Field(
@@ -37,8 +37,8 @@ class ImageItemConfig(ConnectionConfig):
37
37
 
38
38
  class BECImageItem(BECConnector, pg.ImageItem):
39
39
  USER_ACCESS = [
40
- "rpc_id",
41
- "config_dict",
40
+ "_rpc_id",
41
+ "_config_dict",
42
42
  "set",
43
43
  "set_fft",
44
44
  "set_log",
@@ -78,6 +78,7 @@ class BECImageItem(BECConnector, pg.ImageItem):
78
78
  self.apply_config()
79
79
  if kwargs:
80
80
  self.set(**kwargs)
81
+ self.connected = False
81
82
 
82
83
  def apply_config(self):
83
84
  """
@@ -6,22 +6,23 @@ from typing import Optional, Union
6
6
  import numpy as np
7
7
  import pyqtgraph as pg
8
8
  from bec_lib.endpoints import MessageEndpoints
9
- from pydantic import Field
9
+ from pydantic import Field, ValidationError, field_validator
10
+ from pydantic_core import PydanticCustomError
10
11
  from qtpy import QtCore, QtGui
11
12
  from qtpy.QtCore import Signal as pyqtSignal
12
13
  from qtpy.QtCore import Slot as pyqtSlot
13
14
  from qtpy.QtWidgets import QWidget
14
15
 
15
- from bec_widgets.utils import EntryValidator
16
+ from bec_widgets.utils import Colors, EntryValidator
16
17
  from bec_widgets.widgets.figure.plots.plot_base import BECPlotBase, SubplotConfig
17
18
  from bec_widgets.widgets.figure.plots.waveform.waveform import Signal, SignalData
18
19
 
19
20
 
20
21
  class MotorMapConfig(SubplotConfig):
21
22
  signals: Optional[Signal] = Field(None, description="Signals of the motor map")
22
- color_map: Optional[str] = Field(
23
- "Greys", description="Color scheme of the motor position gradient."
24
- ) # TODO decide if useful for anything, or just keep GREYS always
23
+ color: Optional[str | tuple] = Field(
24
+ (255, 255, 255, 255), description="The color of the last point of current position."
25
+ )
25
26
  scatter_size: Optional[int] = Field(5, description="Size of the scatter points.")
26
27
  max_points: Optional[int] = Field(1000, description="Maximum number of points to display.")
27
28
  num_dim_points: Optional[int] = Field(
@@ -30,14 +31,26 @@ class MotorMapConfig(SubplotConfig):
30
31
  )
31
32
  precision: Optional[int] = Field(2, description="Decimal precision of the motor position.")
32
33
  background_value: Optional[int] = Field(
33
- 25, description="Background value of the motor map."
34
- ) # TODO can be percentage from 255 calculated
34
+ 25, description="Background value of the motor map. Has to be between 0 and 255."
35
+ )
36
+
37
+ model_config: dict = {"validate_assignment": True}
38
+
39
+ _validate_color = field_validator("color")(Colors.validate_color)
40
+
41
+ @field_validator("background_value")
42
+ def validate_background_value(cls, value):
43
+ if not 0 <= value <= 255:
44
+ raise PydanticCustomError(
45
+ "wrong_value", f"'{value}' hs to be between 0 and 255.", {"wrong_value": value}
46
+ )
47
+ return value
35
48
 
36
49
 
37
50
  class BECMotorMap(BECPlotBase):
38
51
  USER_ACCESS = [
39
- "rpc_id",
40
- "config_dict",
52
+ "_rpc_id",
53
+ "_config_dict",
41
54
  "change_motors",
42
55
  "set_max_points",
43
56
  "set_precision",
@@ -69,29 +82,43 @@ class BECMotorMap(BECPlotBase):
69
82
  self.get_bec_shortcuts()
70
83
  self.entry_validator = EntryValidator(self.dev)
71
84
 
85
+ # connect update signal to update plot
86
+ self.proxy_update_plot = pg.SignalProxy(
87
+ self.update_signal, rateLimit=25, slot=self._update_plot
88
+ )
89
+ self.apply_config(self.config)
90
+
91
+ def apply_config(self, config: dict | MotorMapConfig):
92
+ """
93
+ Apply the config to the motor map.
94
+
95
+ Args:
96
+ config(dict|MotorMapConfig): Config to be applied.
97
+ """
98
+ if isinstance(config, dict):
99
+ try:
100
+ config = MotorMapConfig(**config)
101
+ except ValidationError as e:
102
+ print(f"Error in applying config: {e}")
103
+ return
104
+
105
+ self.config = config
106
+ self.plot_item.clear()
107
+
72
108
  self.motor_x = None
73
109
  self.motor_y = None
74
110
  self.database_buffer = {"x": [], "y": []}
75
111
  self.plot_components = defaultdict(dict) # container for plot components
76
112
 
77
- # connect update signal to update plot
78
- self.proxy_update_plot = pg.SignalProxy(
79
- self.update_signal, rateLimit=25, slot=self._update_plot
80
- )
113
+ self.apply_axis_config()
81
114
 
82
- # TODO decide if needed to implement, maybe there will be no children widgets for motormap for now...
83
- # def find_widget_by_id(self, item_id: str) -> BECCurve:
84
- # """
85
- # Find the curve by its ID.
86
- # Args:
87
- # item_id(str): ID of the curve.
88
- #
89
- # Returns:
90
- # BECCurve: The curve object.
91
- # """
92
- # for curve in self.plot_item.curves:
93
- # if curve.gui_id == item_id:
94
- # return curve
115
+ if self.config.signals is not None:
116
+ self.change_motors(
117
+ motor_x=self.config.signals.x.name,
118
+ motor_y=self.config.signals.y.name,
119
+ motor_x_entry=self.config.signals.x.entry,
120
+ motor_y_entry=self.config.signals.y.entry,
121
+ )
95
122
 
96
123
  @pyqtSlot(str, str, str, str, bool)
97
124
  def change_motors(
@@ -129,6 +156,8 @@ class BECMotorMap(BECPlotBase):
129
156
  # reconnect the signals
130
157
  self._connect_motor_to_slots()
131
158
 
159
+ self.database_buffer = {"x": [], "y": []}
160
+
132
161
  # Redraw the motor map
133
162
  self._make_motor_map()
134
163
 
@@ -141,7 +170,19 @@ class BECMotorMap(BECPlotBase):
141
170
  data = {"x": self.database_buffer["x"], "y": self.database_buffer["y"]}
142
171
  return data
143
172
 
144
- # TODO setup all visual properties
173
+ def set_color(self, color: [str | tuple]):
174
+ """
175
+ Set color of the motor trace.
176
+
177
+ Args:
178
+ color(str|tuple): Color of the motor trace. Can be HEX(str) or RGBA(tuple).
179
+ """
180
+ if isinstance(color, str):
181
+ color = Colors.validate_color(color)
182
+ color = Colors.hex_to_rgba(color, 255)
183
+ self.config.color = color
184
+ self.update_signal.emit()
185
+
145
186
  def set_max_points(self, max_points: int) -> None:
146
187
  """
147
188
  Set the maximum number of points to display.
@@ -150,6 +191,7 @@ class BECMotorMap(BECPlotBase):
150
191
  max_points(int): Maximum number of points to display.
151
192
  """
152
193
  self.config.max_points = max_points
194
+ self.update_signal.emit()
153
195
 
154
196
  def set_precision(self, precision: int) -> None:
155
197
  """
@@ -159,6 +201,7 @@ class BECMotorMap(BECPlotBase):
159
201
  precision(int): Decimal precision of the motor position.
160
202
  """
161
203
  self.config.precision = precision
204
+ self.update_signal.emit()
162
205
 
163
206
  def set_num_dim_points(self, num_dim_points: int) -> None:
164
207
  """
@@ -168,6 +211,7 @@ class BECMotorMap(BECPlotBase):
168
211
  num_dim_points(int): Number of dim points.
169
212
  """
170
213
  self.config.num_dim_points = num_dim_points
214
+ self.update_signal.emit()
171
215
 
172
216
  def set_background_value(self, background_value: int) -> None:
173
217
  """
@@ -177,6 +221,7 @@ class BECMotorMap(BECPlotBase):
177
221
  background_value(int): Background value of the motor map.
178
222
  """
179
223
  self.config.background_value = background_value
224
+ self._swap_limit_map()
180
225
 
181
226
  def set_scatter_size(self, scatter_size: int) -> None:
182
227
  """
@@ -186,6 +231,7 @@ class BECMotorMap(BECPlotBase):
186
231
  scatter_size(int): Size of the scatter points.
187
232
  """
188
233
  self.config.scatter_size = scatter_size
234
+ self.update_signal.emit()
189
235
 
190
236
  def _disconnect_current_motors(self):
191
237
  """Disconnect the current motors from the slots."""
@@ -210,6 +256,15 @@ class BECMotorMap(BECPlotBase):
210
256
 
211
257
  self.bec_dispatcher.connect_slot(self.on_device_readback, endpoints)
212
258
 
259
+ def _swap_limit_map(self):
260
+ """Swap the limit map."""
261
+ self.plot_item.removeItem(self.plot_components["limit_map"])
262
+ self.plot_components["limit_map"] = self._make_limit_map(
263
+ self.config.signals.x.limits, self.config.signals.y.limits
264
+ )
265
+ self.plot_components["limit_map"].setZValue(-1)
266
+ self.plot_item.addItem(self.plot_components["limit_map"])
267
+
213
268
  def _make_motor_map(self):
214
269
  """
215
270
  Create the motor map plot.
@@ -249,6 +304,8 @@ class BECMotorMap(BECPlotBase):
249
304
  # Set default labels for the plot
250
305
  self.set(x_label=f"Motor X ({self.motor_x})", y_label=f"Motor Y ({self.motor_y})")
251
306
 
307
+ self.update_signal.emit()
308
+
252
309
  def _add_coordinantes_crosshair(self, x: float, y: float) -> None:
253
310
  """
254
311
  Add crosshair to the plot to highlight the current position.
@@ -373,19 +430,31 @@ class BECMotorMap(BECPlotBase):
373
430
 
374
431
  def _update_plot(self):
375
432
  """Update the motor map plot."""
433
+ # If the number of points exceeds max_points, delete the oldest points
434
+ if len(self.database_buffer["x"]) > self.config.max_points:
435
+ self.database_buffer["x"] = self.database_buffer["x"][-self.config.max_points :]
436
+ self.database_buffer["y"] = self.database_buffer["y"][-self.config.max_points :]
437
+
376
438
  x = self.database_buffer["x"]
377
439
  y = self.database_buffer["y"]
378
440
 
379
441
  # Setup gradient brush for history
380
442
  brushes = [pg.mkBrush(50, 50, 50, 255)] * len(x)
381
443
 
444
+ # RGB color
445
+ r, g, b, a = self.config.color
446
+
382
447
  # Calculate the decrement step based on self.num_dim_points
383
448
  num_dim_points = self.config.num_dim_points
384
449
  decrement_step = (255 - 50) / num_dim_points
450
+
385
451
  for i in range(1, min(num_dim_points + 1, len(x) + 1)):
386
452
  brightness = max(60, 255 - decrement_step * (i - 1))
387
- brushes[-i] = pg.mkBrush(brightness, brightness, brightness, 255)
388
- brushes[-1] = pg.mkBrush(255, 255, 255, 255) # Newest point is always full brightness
453
+ dim_r = int(r * (brightness / 255))
454
+ dim_g = int(g * (brightness / 255))
455
+ dim_b = int(b * (brightness / 255))
456
+ brushes[-i] = pg.mkBrush(dim_r, dim_g, dim_b, a)
457
+ brushes[-1] = pg.mkBrush(r, g, b, a) # Newest point is always full brightness
389
458
  scatter_size = self.config.scatter_size
390
459
 
391
460
  # Update the scatter plot
@@ -46,7 +46,7 @@ class SubplotConfig(ConnectionConfig):
46
46
 
47
47
  class BECPlotBase(BECConnector, pg.GraphicsLayout):
48
48
  USER_ACCESS = [
49
- "config_dict",
49
+ "_config_dict",
50
50
  "set",
51
51
  "set_title",
52
52
  "set_x_label",
@@ -35,8 +35,8 @@ class Waveform1DConfig(SubplotConfig):
35
35
 
36
36
  class BECWaveform(BECPlotBase):
37
37
  USER_ACCESS = [
38
- "rpc_id",
39
- "config_dict",
38
+ "_rpc_id",
39
+ "_config_dict",
40
40
  "plot",
41
41
  "add_dap",
42
42
  "get_dap_params",
@@ -44,8 +44,6 @@ class BECWaveform(BECPlotBase):
44
44
  "scan_history",
45
45
  "curves",
46
46
  "get_curve",
47
- "get_curve_config",
48
- "apply_config",
49
47
  "get_all_data",
50
48
  "set",
51
49
  "set_title",
@@ -705,14 +703,15 @@ class BECWaveform(BECPlotBase):
705
703
  data_y = data[y_name][y_entry].val
706
704
  if curve.config.signals.z:
707
705
  data_z = data[z_name][z_entry].val
708
- color_z = self._make_z_gradient(
709
- data_z, curve.config.color_map_z
710
- ) # TODO decide how to implement custom gradient
706
+ color_z = self._make_z_gradient(data_z, curve.config.color_map_z)
711
707
  except TypeError:
712
708
  continue
713
709
 
714
710
  if data_z is not None and color_z is not None:
715
- curve.setData(x=data_x, y=data_y, symbolBrush=color_z)
711
+ try:
712
+ curve.setData(x=data_x, y=data_y, symbolBrush=color_z)
713
+ except:
714
+ return
716
715
  else:
717
716
  curve.setData(data_x, data_y)
718
717
 
@@ -65,8 +65,8 @@ class BECCurve(BECConnector, pg.PlotDataItem):
65
65
  USER_ACCESS = [
66
66
  "remove",
67
67
  "dap_params",
68
- "rpc_id",
69
- "config_dict",
68
+ "_rpc_id",
69
+ "_config_dict",
70
70
  "set",
71
71
  "set_data",
72
72
  "set_color",
@@ -79,9 +79,9 @@ class RingConfig(ProgressbarConfig):
79
79
 
80
80
  class Ring(BECConnector):
81
81
  USER_ACCESS = [
82
- "get_all_rpc",
83
- "rpc_id",
84
- "config_dict",
82
+ "_get_all_rpc",
83
+ "_rpc_id",
84
+ "_config_dict",
85
85
  "set_value",
86
86
  "set_color",
87
87
  "set_background",
@@ -68,9 +68,9 @@ class RingProgressBarConfig(ConnectionConfig):
68
68
 
69
69
  class RingProgressBar(BECConnector, QWidget):
70
70
  USER_ACCESS = [
71
- "get_all_rpc",
72
- "rpc_id",
73
- "config_dict",
71
+ "_get_all_rpc",
72
+ "_rpc_id",
73
+ "_config_dict",
74
74
  "rings",
75
75
  "update_config",
76
76
  "add_ring",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bec_widgets
3
- Version: 0.76.0
3
+ Version: 0.77.0
4
4
  Summary: BEC Widgets
5
5
  Project-URL: Bug Tracker, https://gitlab.psi.ch/bec/bec_widgets/issues
6
6
  Project-URL: Homepage, https://gitlab.psi.ch/bec/bec_widgets
@@ -16,6 +16,7 @@ Requires-Dist: isort>=5.13.2,~=5.13
16
16
  Requires-Dist: pydantic~=2.0
17
17
  Requires-Dist: pyqtdarktheme~=2.1
18
18
  Requires-Dist: pyqtgraph~=0.13
19
+ Requires-Dist: pyte
19
20
  Requires-Dist: qtconsole>=5.5.1,~=5.5
20
21
  Requires-Dist: qtpy~=2.4
21
22
  Provides-Extra: dev