bec-widgets 0.76.1__py3-none-any.whl → 0.78.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.
- CHANGELOG.md +42 -48
- PKG-INFO +2 -1
- bec_widgets/cli/client.py +73 -196
- bec_widgets/examples/jupyter_console/jupyter_console_window.py +25 -4
- bec_widgets/utils/bec_connector.py +66 -8
- bec_widgets/utils/colors.py +38 -0
- bec_widgets/utils/yaml_dialog.py +27 -3
- bec_widgets/widgets/buttons/color_button/__init__.py +0 -0
- bec_widgets/widgets/buttons/color_button/assets/color_button.png +0 -0
- bec_widgets/widgets/buttons/color_button/color_button.py +17 -0
- bec_widgets/widgets/buttons/color_button/color_button.pyproject +1 -0
- bec_widgets/widgets/buttons/color_button/color_button_plugin.py +55 -0
- bec_widgets/widgets/buttons/color_button/register_color_button.py +15 -0
- bec_widgets/widgets/console/console.py +496 -0
- bec_widgets/widgets/dock/dock.py +2 -2
- bec_widgets/widgets/dock/dock_area.py +2 -2
- bec_widgets/widgets/figure/figure.py +149 -195
- bec_widgets/widgets/figure/plots/image/image.py +62 -49
- bec_widgets/widgets/figure/plots/image/image_item.py +4 -3
- bec_widgets/widgets/figure/plots/motor_map/motor_map.py +98 -29
- bec_widgets/widgets/figure/plots/plot_base.py +1 -1
- bec_widgets/widgets/figure/plots/waveform/waveform.py +7 -8
- bec_widgets/widgets/figure/plots/waveform/waveform_curve.py +2 -2
- bec_widgets/widgets/ring_progress_bar/ring.py +3 -3
- bec_widgets/widgets/ring_progress_bar/ring_progress_bar.py +3 -3
- {bec_widgets-0.76.1.dist-info → bec_widgets-0.78.0.dist-info}/METADATA +2 -1
- {bec_widgets-0.76.1.dist-info → bec_widgets-0.78.0.dist-info}/RECORD +44 -37
- pyproject.toml +2 -1
- tests/end-2-end/test_bec_dock_rpc_e2e.py +16 -16
- tests/end-2-end/test_bec_figure_rpc_e2e.py +7 -7
- tests/end-2-end/test_rpc_register_e2e.py +8 -8
- tests/unit_tests/client_mocks.py +1 -0
- tests/unit_tests/test_bec_figure.py +49 -26
- tests/unit_tests/test_bec_motor_map.py +179 -41
- tests/unit_tests/test_color_validation.py +15 -0
- tests/unit_tests/test_device_input_base.py +1 -1
- tests/unit_tests/test_device_input_widgets.py +2 -0
- tests/unit_tests/test_motor_control.py +5 -4
- tests/unit_tests/test_plot_base.py +3 -3
- tests/unit_tests/test_waveform1d.py +18 -17
- tests/unit_tests/test_yaml_dialog.py +7 -7
- {bec_widgets-0.76.1.dist-info → bec_widgets-0.78.0.dist-info}/WHEEL +0 -0
- {bec_widgets-0.76.1.dist-info → bec_widgets-0.78.0.dist-info}/entry_points.txt +0 -0
- {bec_widgets-0.76.1.dist-info → bec_widgets-0.78.0.dist-info}/licenses/LICENSE +0 -0
@@ -8,7 +8,7 @@ from typing import Literal, Optional
|
|
8
8
|
import numpy as np
|
9
9
|
import pyqtgraph as pg
|
10
10
|
import qdarktheme
|
11
|
-
from pydantic import Field
|
11
|
+
from pydantic import Field, ValidationError, field_validator
|
12
12
|
from qtpy.QtCore import Signal as pyqtSignal
|
13
13
|
from qtpy.QtWidgets import QWidget
|
14
14
|
from typeguard import typechecked
|
@@ -30,16 +30,36 @@ class FigureConfig(ConnectionConfig):
|
|
30
30
|
{}, description="The list of widgets to be added to the figure widget."
|
31
31
|
)
|
32
32
|
|
33
|
+
@field_validator("widgets", mode="before")
|
34
|
+
@classmethod
|
35
|
+
def validate_widgets(cls, v):
|
36
|
+
"""Validate the widgets configuration."""
|
37
|
+
widget_class_map = {
|
38
|
+
"BECWaveform": Waveform1DConfig,
|
39
|
+
"BECImageShow": ImageConfig,
|
40
|
+
"BECMotorMap": MotorMapConfig,
|
41
|
+
}
|
42
|
+
validated_widgets = {}
|
43
|
+
for key, widget_config in v.items():
|
44
|
+
if "widget_class" not in widget_config:
|
45
|
+
raise ValueError(f"Widget config for {key} does not contain 'widget_class'.")
|
46
|
+
widget_class = widget_config["widget_class"]
|
47
|
+
if widget_class not in widget_class_map:
|
48
|
+
raise ValueError(f"Unknown widget_class '{widget_class}' for widget '{key}'.")
|
49
|
+
config_class = widget_class_map[widget_class]
|
50
|
+
validated_widgets[key] = config_class(**widget_config)
|
51
|
+
return validated_widgets
|
52
|
+
|
33
53
|
|
34
54
|
class WidgetHandler:
|
35
55
|
"""Factory for creating and configuring BEC widgets for BECFigure."""
|
36
56
|
|
37
57
|
def __init__(self):
|
38
58
|
self.widget_factory = {
|
39
|
-
"
|
40
|
-
"
|
41
|
-
"
|
42
|
-
"
|
59
|
+
"BECPlotBase": (BECPlotBase, SubplotConfig),
|
60
|
+
"BECWaveform": (BECWaveform, Waveform1DConfig),
|
61
|
+
"BECImageShow": (BECImageShow, ImageConfig),
|
62
|
+
"BECMotorMap": (BECMotorMap, MotorMapConfig),
|
43
63
|
}
|
44
64
|
|
45
65
|
def create_widget(
|
@@ -90,13 +110,11 @@ class WidgetHandler:
|
|
90
110
|
|
91
111
|
class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
92
112
|
USER_ACCESS = [
|
93
|
-
"
|
94
|
-
"
|
113
|
+
"_rpc_id",
|
114
|
+
"_config_dict",
|
115
|
+
"_get_all_rpc",
|
95
116
|
"axes",
|
96
117
|
"widgets",
|
97
|
-
"add_plot",
|
98
|
-
"add_image",
|
99
|
-
"add_motor_map",
|
100
118
|
"plot",
|
101
119
|
"image",
|
102
120
|
"motor_map",
|
@@ -104,9 +122,15 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
|
104
122
|
"change_layout",
|
105
123
|
"change_theme",
|
106
124
|
"clear_all",
|
107
|
-
"get_all_rpc",
|
108
125
|
"widget_list",
|
109
126
|
]
|
127
|
+
subplot_map = {
|
128
|
+
"PlotBase": BECPlotBase,
|
129
|
+
"BECWaveform": BECWaveform,
|
130
|
+
"BECImageShow": BECImageShow,
|
131
|
+
"BECMotorMap": BECMotorMap,
|
132
|
+
}
|
133
|
+
widget_method_map = {"BECWaveform": "plot", "BECImageShow": "image", "BECMotorMap": "motor_map"}
|
110
134
|
|
111
135
|
clean_signal = pyqtSignal()
|
112
136
|
|
@@ -122,8 +146,7 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
|
122
146
|
else:
|
123
147
|
if isinstance(config, dict):
|
124
148
|
config = FigureConfig(**config)
|
125
|
-
|
126
|
-
super().__init__(client=client, config=config, gui_id=gui_id)
|
149
|
+
super().__init__(client=client, gui_id=gui_id)
|
127
150
|
pg.GraphicsLayoutWidget.__init__(self, parent)
|
128
151
|
|
129
152
|
self.widget_handler = WidgetHandler()
|
@@ -133,6 +156,8 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
|
133
156
|
|
134
157
|
# Container to keep track of the grid
|
135
158
|
self.grid = []
|
159
|
+
# Create config and apply it
|
160
|
+
self.apply_config(config)
|
136
161
|
|
137
162
|
def __getitem__(self, key: tuple | str):
|
138
163
|
if isinstance(key, tuple) and len(key) == 2:
|
@@ -147,6 +172,24 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
|
147
172
|
"Key must be a string (widget id) or a tuple of two integers (grid coordinates)"
|
148
173
|
)
|
149
174
|
|
175
|
+
def apply_config(self, config: dict | FigureConfig): # ,generate_new_id: bool = False):
|
176
|
+
if isinstance(config, dict):
|
177
|
+
try:
|
178
|
+
config = FigureConfig(**config)
|
179
|
+
except ValidationError as e:
|
180
|
+
print(f"Error in applying config: {e}")
|
181
|
+
return
|
182
|
+
self.config = config
|
183
|
+
self.change_theme(self.config.theme)
|
184
|
+
|
185
|
+
# widget_config has to be reset for not have each widget config twice when added to the figure
|
186
|
+
widget_configs = [config for config in self.config.widgets.values()]
|
187
|
+
self.config.widgets = {}
|
188
|
+
for widget_config in widget_configs:
|
189
|
+
getattr(self, self.widget_method_map[widget_config.widget_class])(
|
190
|
+
config=widget_config.model_dump(), row=widget_config.row, col=widget_config.col
|
191
|
+
)
|
192
|
+
|
150
193
|
@property
|
151
194
|
def widget_list(self) -> list[BECPlotBase]:
|
152
195
|
"""
|
@@ -200,7 +243,7 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
|
200
243
|
label: str | None = None,
|
201
244
|
validate: bool = True,
|
202
245
|
dap: str | None = None,
|
203
|
-
):
|
246
|
+
) -> BECWaveform:
|
204
247
|
"""
|
205
248
|
Configure the waveform based on the provided parameters.
|
206
249
|
|
@@ -279,75 +322,6 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
|
279
322
|
|
280
323
|
return waveform
|
281
324
|
|
282
|
-
def add_plot(
|
283
|
-
self,
|
284
|
-
x: list | np.ndarray = None,
|
285
|
-
y: list | np.ndarray = None,
|
286
|
-
x_name: str = None,
|
287
|
-
y_name: str = None,
|
288
|
-
z_name: str = None,
|
289
|
-
x_entry: str = None,
|
290
|
-
y_entry: str = None,
|
291
|
-
z_entry: str = None,
|
292
|
-
color: Optional[str] = None,
|
293
|
-
color_map_z: Optional[str] = "plasma",
|
294
|
-
label: Optional[str] = None,
|
295
|
-
validate: bool = True,
|
296
|
-
row: int = None,
|
297
|
-
col: int = None,
|
298
|
-
config=None,
|
299
|
-
dap: str | None = None,
|
300
|
-
**axis_kwargs,
|
301
|
-
) -> BECWaveform:
|
302
|
-
"""
|
303
|
-
Add a Waveform1D plot to the figure at the specified position.
|
304
|
-
|
305
|
-
Args:
|
306
|
-
x(list | np.ndarray): Custom x data to plot.
|
307
|
-
y(list | np.ndarray): Custom y data to plot.
|
308
|
-
x_name(str): The name of the device for the x-axis.
|
309
|
-
y_name(str): The name of the device for the y-axis.
|
310
|
-
z_name(str): The name of the device for the z-axis.
|
311
|
-
x_entry(str): The name of the entry for the x-axis.
|
312
|
-
y_entry(str): The name of the entry for the y-axis.
|
313
|
-
z_entry(str): The name of the entry for the z-axis.
|
314
|
-
color(str): The color of the curve.
|
315
|
-
color_map_z(str): The color map to use for the z-axis.
|
316
|
-
label(str): The label of the curve.
|
317
|
-
validate(bool): If True, validate the device names and entries.
|
318
|
-
row(int): The row coordinate of the widget in the figure. If not provided, the next empty row will be used.
|
319
|
-
col(int): The column coordinate of the widget in the figure. If not provided, the next empty column will be used.
|
320
|
-
config(dict): Additional configuration for the widget.
|
321
|
-
**axis_kwargs(dict): Additional axis properties to set on the widget after creation.
|
322
|
-
"""
|
323
|
-
widget_id = str(uuid.uuid4())
|
324
|
-
waveform = self.add_widget(
|
325
|
-
widget_type="Waveform1D",
|
326
|
-
widget_id=widget_id,
|
327
|
-
row=row,
|
328
|
-
col=col,
|
329
|
-
config=config,
|
330
|
-
**axis_kwargs,
|
331
|
-
)
|
332
|
-
|
333
|
-
waveform = self._init_waveform(
|
334
|
-
waveform=waveform,
|
335
|
-
x=x,
|
336
|
-
y=y,
|
337
|
-
x_name=x_name,
|
338
|
-
y_name=y_name,
|
339
|
-
z_name=z_name,
|
340
|
-
x_entry=x_entry,
|
341
|
-
y_entry=y_entry,
|
342
|
-
z_entry=z_entry,
|
343
|
-
color=color,
|
344
|
-
color_map_z=color_map_z,
|
345
|
-
label=label,
|
346
|
-
validate=validate,
|
347
|
-
dap=dap,
|
348
|
-
)
|
349
|
-
return waveform
|
350
|
-
|
351
325
|
@typechecked
|
352
326
|
def plot(
|
353
327
|
self,
|
@@ -363,7 +337,11 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
|
363
337
|
color_map_z: str | None = "plasma",
|
364
338
|
label: str | None = None,
|
365
339
|
validate: bool = True,
|
340
|
+
new: bool = False,
|
341
|
+
row: int | None = None,
|
342
|
+
col: int | None = None,
|
366
343
|
dap: str | None = None,
|
344
|
+
config: dict | None = None, # TODO make logic more transparent
|
367
345
|
**axis_kwargs,
|
368
346
|
) -> BECWaveform:
|
369
347
|
"""
|
@@ -382,21 +360,23 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
|
382
360
|
color_map_z(str): The color map to use for the z-axis.
|
383
361
|
label(str): The label of the curve.
|
384
362
|
validate(bool): If True, validate the device names and entries.
|
363
|
+
new(bool): If True, create a new plot instead of using the first plot.
|
364
|
+
row(int): The row coordinate of the widget in the figure. If not provided, the next empty row will be used.
|
365
|
+
col(int): The column coordinate of the widget in the figure. If not provided, the next empty column will be used.
|
385
366
|
dap(str): The DAP model to use for the curve.
|
367
|
+
config(dict): Recreates the whole BECWaveform widget from provided configuration.
|
386
368
|
**axis_kwargs: Additional axis properties to set on the widget after creation.
|
387
369
|
|
388
370
|
Returns:
|
389
371
|
BECWaveform: The waveform plot widget.
|
390
372
|
"""
|
391
|
-
waveform =
|
392
|
-
|
373
|
+
waveform = self.subplot_factory(
|
374
|
+
widget_type="BECWaveform", config=config, row=row, col=col, new=new, **axis_kwargs
|
393
375
|
)
|
394
|
-
if
|
395
|
-
|
396
|
-
waveform.set(**axis_kwargs)
|
397
|
-
else:
|
398
|
-
waveform = self.add_plot(**axis_kwargs)
|
376
|
+
if config is not None:
|
377
|
+
return waveform
|
399
378
|
|
379
|
+
# Passing args to init_waveform
|
400
380
|
waveform = self._init_waveform(
|
401
381
|
waveform=waveform,
|
402
382
|
x=x,
|
@@ -413,7 +393,6 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
|
413
393
|
validate=validate,
|
414
394
|
dap=dap,
|
415
395
|
)
|
416
|
-
# TODO remove repetition from .plot method
|
417
396
|
return waveform
|
418
397
|
|
419
398
|
def _init_image(
|
@@ -460,6 +439,10 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
|
460
439
|
color_map: str = "magma",
|
461
440
|
data: np.ndarray = None,
|
462
441
|
vrange: tuple[float, float] = None,
|
442
|
+
new: bool = False,
|
443
|
+
row: int | None = None,
|
444
|
+
col: int | None = None,
|
445
|
+
config: dict | None = None,
|
463
446
|
**axis_kwargs,
|
464
447
|
) -> BECImageShow:
|
465
448
|
"""
|
@@ -471,78 +454,22 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
|
471
454
|
color_map(str): The color map to use for the image.
|
472
455
|
data(np.ndarray): Custom data to display.
|
473
456
|
vrange(tuple[float, float]): The range of values to display.
|
474
|
-
|
475
|
-
|
476
|
-
Returns:
|
477
|
-
BECImageShow: The image widget.
|
478
|
-
"""
|
479
|
-
image = WidgetContainerUtils.find_first_widget_by_class(
|
480
|
-
self._widgets, BECImageShow, can_fail=True
|
481
|
-
)
|
482
|
-
if image is not None:
|
483
|
-
if axis_kwargs:
|
484
|
-
image.set(**axis_kwargs)
|
485
|
-
else:
|
486
|
-
image = self.add_image(color_bar=color_bar, **axis_kwargs)
|
487
|
-
|
488
|
-
image = self._init_image(
|
489
|
-
image=image,
|
490
|
-
monitor=monitor,
|
491
|
-
color_bar=color_bar,
|
492
|
-
color_map=color_map,
|
493
|
-
data=data,
|
494
|
-
vrange=vrange,
|
495
|
-
)
|
496
|
-
return image
|
497
|
-
|
498
|
-
def add_image(
|
499
|
-
self,
|
500
|
-
monitor: str = None,
|
501
|
-
color_bar: Literal["simple", "full"] = "full",
|
502
|
-
color_map: str = "magma",
|
503
|
-
data: np.ndarray = None,
|
504
|
-
vrange: tuple[float, float] = None,
|
505
|
-
row: int = None,
|
506
|
-
col: int = None,
|
507
|
-
config=None,
|
508
|
-
**axis_kwargs,
|
509
|
-
) -> BECImageShow:
|
510
|
-
"""
|
511
|
-
Add an image to the figure at the specified position.
|
512
|
-
|
513
|
-
Args:
|
514
|
-
monitor(str): The name of the monitor to display.
|
515
|
-
color_bar(Literal["simple","full"]): The type of color bar to display.
|
516
|
-
color_map(str): The color map to use for the image.
|
517
|
-
data(np.ndarray): Custom data to display.
|
518
|
-
vrange(tuple[float, float]): The range of values to display.
|
457
|
+
new(bool): If True, create a new plot instead of using the first plot.
|
519
458
|
row(int): The row coordinate of the widget in the figure. If not provided, the next empty row will be used.
|
520
459
|
col(int): The column coordinate of the widget in the figure. If not provided, the next empty column will be used.
|
521
|
-
config(dict):
|
460
|
+
config(dict): Recreates the whole BECImageShow widget from provided configuration.
|
522
461
|
**axis_kwargs: Additional axis properties to set on the widget after creation.
|
523
462
|
|
524
463
|
Returns:
|
525
464
|
BECImageShow: The image widget.
|
526
465
|
"""
|
527
466
|
|
528
|
-
|
529
|
-
|
530
|
-
config = ImageConfig(
|
531
|
-
widget_class="BECImageShow",
|
532
|
-
gui_id=widget_id,
|
533
|
-
parent_id=self.gui_id,
|
534
|
-
color_map=color_map,
|
535
|
-
color_bar=color_bar,
|
536
|
-
vrange=vrange,
|
537
|
-
)
|
538
|
-
image = self.add_widget(
|
539
|
-
widget_type="ImShow",
|
540
|
-
widget_id=widget_id,
|
541
|
-
row=row,
|
542
|
-
col=col,
|
543
|
-
config=config,
|
544
|
-
**axis_kwargs,
|
467
|
+
image = self.subplot_factory(
|
468
|
+
widget_type="BECImageShow", config=config, row=row, col=col, new=new, **axis_kwargs
|
545
469
|
)
|
470
|
+
if config is not None:
|
471
|
+
return image
|
472
|
+
|
546
473
|
image = self._init_image(
|
547
474
|
image=image,
|
548
475
|
monitor=monitor,
|
@@ -553,76 +480,99 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
|
553
480
|
)
|
554
481
|
return image
|
555
482
|
|
556
|
-
def motor_map(
|
483
|
+
def motor_map(
|
484
|
+
self,
|
485
|
+
motor_x: str = None,
|
486
|
+
motor_y: str = None,
|
487
|
+
new: bool = False,
|
488
|
+
row: int | None = None,
|
489
|
+
col: int | None = None,
|
490
|
+
config: dict | None = None,
|
491
|
+
**axis_kwargs,
|
492
|
+
) -> BECMotorMap:
|
557
493
|
"""
|
558
494
|
Add a motor map to the figure. Always access the first motor map widget in the figure.
|
559
495
|
|
560
496
|
Args:
|
561
497
|
motor_x(str): The name of the motor for the X axis.
|
562
498
|
motor_y(str): The name of the motor for the Y axis.
|
499
|
+
new(bool): If True, create a new plot instead of using the first plot.
|
500
|
+
row(int): The row coordinate of the widget in the figure. If not provided, the next empty row will be used.
|
501
|
+
col(int): The column coordinate of the widget in the figure. If not provided, the next empty column will be used.
|
502
|
+
config(dict): Recreates the whole BECImageShow widget from provided configuration.
|
563
503
|
**axis_kwargs: Additional axis properties to set on the widget after creation.
|
564
504
|
|
565
505
|
Returns:
|
566
506
|
BECMotorMap: The motor map widget.
|
567
507
|
"""
|
568
|
-
motor_map =
|
569
|
-
|
508
|
+
motor_map = self.subplot_factory(
|
509
|
+
widget_type="BECMotorMap", config=config, row=row, col=col, new=new, **axis_kwargs
|
570
510
|
)
|
571
|
-
if
|
572
|
-
|
573
|
-
motor_map.set(**axis_kwargs)
|
574
|
-
else:
|
575
|
-
motor_map = self.add_motor_map(**axis_kwargs)
|
511
|
+
if config is not None:
|
512
|
+
return motor_map
|
576
513
|
|
577
514
|
if motor_x is not None and motor_y is not None:
|
578
515
|
motor_map.change_motors(motor_x, motor_y)
|
579
516
|
|
580
517
|
return motor_map
|
581
518
|
|
582
|
-
def
|
519
|
+
def subplot_factory(
|
583
520
|
self,
|
584
|
-
|
585
|
-
|
521
|
+
widget_type: Literal[
|
522
|
+
"BECPlotBase", "BECWaveform", "BECImageShow", "BECMotorMap"
|
523
|
+
] = "BECPlotBase",
|
586
524
|
row: int = None,
|
587
525
|
col: int = None,
|
588
526
|
config=None,
|
527
|
+
new: bool = False,
|
589
528
|
**axis_kwargs,
|
590
|
-
) ->
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
Returns:
|
602
|
-
BECMotorMap: The motor map widget.
|
603
|
-
"""
|
604
|
-
widget_id = str(uuid.uuid4())
|
605
|
-
if config is None:
|
606
|
-
config = MotorMapConfig(
|
607
|
-
widget_class="BECMotorMap", gui_id=widget_id, parent_id=self.gui_id
|
529
|
+
) -> BECPlotBase:
|
530
|
+
# Case 1 - config provided, new plot, possible to define coordinates
|
531
|
+
if config is not None:
|
532
|
+
widget_cls = config["widget_class"]
|
533
|
+
if widget_cls != widget_type:
|
534
|
+
raise ValueError(
|
535
|
+
f"Widget type '{widget_type}' does not match the provided configuration ({widget_cls})."
|
536
|
+
)
|
537
|
+
widget = self.add_widget(
|
538
|
+
widget_type=widget_type, config=config, row=row, col=col, **axis_kwargs
|
608
539
|
)
|
609
|
-
|
610
|
-
widget_type="MotorMap",
|
611
|
-
widget_id=widget_id,
|
612
|
-
row=row,
|
613
|
-
col=col,
|
614
|
-
config=config,
|
615
|
-
**axis_kwargs,
|
616
|
-
)
|
540
|
+
return widget
|
617
541
|
|
618
|
-
if
|
619
|
-
|
542
|
+
# Case 2 - find first plot or create first plot if no plot available, no config provided, no coordinates
|
543
|
+
if new is False and (row is None or col is None):
|
544
|
+
widget = WidgetContainerUtils.find_first_widget_by_class(
|
545
|
+
self._widgets, self.subplot_map[widget_type], can_fail=True
|
546
|
+
)
|
547
|
+
if widget is not None:
|
548
|
+
if axis_kwargs:
|
549
|
+
widget.set(**axis_kwargs)
|
550
|
+
else:
|
551
|
+
widget = self.add_widget(widget_type=widget_type, **axis_kwargs)
|
552
|
+
return widget
|
553
|
+
|
554
|
+
# Case 3 - modifying existing plot wit coordinates provided
|
555
|
+
if new is False and (row is not None and col is not None):
|
556
|
+
try:
|
557
|
+
widget = self.axes(row, col)
|
558
|
+
except ValueError:
|
559
|
+
widget = None
|
560
|
+
if widget is not None:
|
561
|
+
if axis_kwargs:
|
562
|
+
widget.set(**axis_kwargs)
|
563
|
+
else:
|
564
|
+
widget = self.add_widget(widget_type=widget_type, row=row, col=col, **axis_kwargs)
|
565
|
+
return widget
|
620
566
|
|
621
|
-
|
567
|
+
# Case 4 - no previous plot or new plot, no config provided, possible to define coordinates
|
568
|
+
widget = self.add_widget(widget_type=widget_type, row=row, col=col, **axis_kwargs)
|
569
|
+
return widget
|
622
570
|
|
623
571
|
def add_widget(
|
624
572
|
self,
|
625
|
-
widget_type: Literal[
|
573
|
+
widget_type: Literal[
|
574
|
+
"BECPlotBase", "BECWaveform", "BECImageShow", "BECMotorMap"
|
575
|
+
] = "BECPlotBase",
|
626
576
|
widget_id: str = None,
|
627
577
|
row: int = None,
|
628
578
|
col: int = None,
|
@@ -653,6 +603,9 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
|
653
603
|
config=config,
|
654
604
|
**axis_kwargs,
|
655
605
|
)
|
606
|
+
# has to be changed manually to ensure unique id, if config is copied from existing widget, the id could be
|
607
|
+
# used otherwise multiple times
|
608
|
+
widget.set_gui_id(widget_id)
|
656
609
|
|
657
610
|
# Check if position is occupied
|
658
611
|
if row is not None and col is not None:
|
@@ -756,6 +709,7 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
|
|
756
709
|
self._reindex_grid()
|
757
710
|
if widget_id in self.config.widgets:
|
758
711
|
self.config.widgets.pop(widget_id)
|
712
|
+
widget.deleteLater()
|
759
713
|
else:
|
760
714
|
raise ValueError(f"Widget with ID '{widget_id}' does not exist.")
|
761
715
|
|