bec-widgets 0.53.3__py3-none-any.whl → 0.55.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 (72) hide show
  1. CHANGELOG.md +24 -26
  2. PKG-INFO +1 -1
  3. bec_widgets/cli/client.py +265 -13
  4. bec_widgets/cli/client_utils.py +0 -3
  5. bec_widgets/cli/generate_cli.py +10 -5
  6. bec_widgets/cli/rpc_wigdet_handler.py +2 -1
  7. bec_widgets/cli/server.py +5 -7
  8. bec_widgets/examples/jupyter_console/jupyter_console_window.py +11 -5
  9. bec_widgets/examples/motor_movement/motor_control_compilations.py +17 -16
  10. bec_widgets/widgets/__init__.py +1 -10
  11. bec_widgets/widgets/figure/figure.py +40 -23
  12. bec_widgets/widgets/figure/plots/__init__.py +0 -0
  13. bec_widgets/widgets/figure/plots/image/__init__.py +0 -0
  14. bec_widgets/widgets/{plots → figure/plots/image}/image.py +6 -416
  15. bec_widgets/widgets/figure/plots/image/image_item.py +277 -0
  16. bec_widgets/widgets/figure/plots/image/image_processor.py +152 -0
  17. bec_widgets/widgets/figure/plots/motor_map/__init__.py +0 -0
  18. bec_widgets/widgets/{plots → figure/plots/motor_map}/motor_map.py +2 -2
  19. bec_widgets/widgets/figure/plots/waveform/__init__.py +0 -0
  20. bec_widgets/widgets/{plots → figure/plots/waveform}/waveform.py +9 -222
  21. bec_widgets/widgets/figure/plots/waveform/waveform_curve.py +227 -0
  22. bec_widgets/widgets/motor_control/__init__.py +0 -7
  23. bec_widgets/widgets/motor_control/motor_control.py +2 -948
  24. bec_widgets/widgets/motor_control/motor_table/__init__.py +0 -0
  25. bec_widgets/widgets/motor_control/motor_table/motor_table.py +483 -0
  26. bec_widgets/widgets/motor_control/movement_absolute/__init__.py +0 -0
  27. bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.py +157 -0
  28. bec_widgets/widgets/motor_control/movement_relative/__init__.py +0 -0
  29. bec_widgets/widgets/motor_control/movement_relative/movement_relative.py +227 -0
  30. bec_widgets/widgets/motor_control/selection/__init__.py +0 -0
  31. bec_widgets/widgets/motor_control/selection/selection.py +110 -0
  32. bec_widgets/widgets/spiral_progress_bar/__init__.py +1 -0
  33. bec_widgets/widgets/spiral_progress_bar/ring.py +184 -0
  34. bec_widgets/widgets/spiral_progress_bar/spiral_progress_bar.py +594 -0
  35. {bec_widgets-0.53.3.dist-info → bec_widgets-0.55.0.dist-info}/METADATA +1 -1
  36. {bec_widgets-0.53.3.dist-info → bec_widgets-0.55.0.dist-info}/RECORD +56 -53
  37. docs/requirements.txt +1 -0
  38. pyproject.toml +1 -1
  39. tests/end-2-end/test_bec_dock_rpc_e2e.py +82 -1
  40. tests/end-2-end/test_bec_figure_rpc_e2e.py +4 -4
  41. tests/end-2-end/test_rpc_register_e2e.py +1 -1
  42. tests/unit_tests/test_bec_dock.py +1 -1
  43. tests/unit_tests/test_bec_figure.py +6 -4
  44. tests/unit_tests/test_bec_motor_map.py +2 -3
  45. tests/unit_tests/test_motor_control.py +6 -5
  46. tests/unit_tests/test_spiral_progress_bar.py +338 -0
  47. tests/unit_tests/test_waveform1d.py +13 -1
  48. bec_widgets/validation/__init__.py +0 -2
  49. bec_widgets/validation/monitor_config_validator.py +0 -258
  50. bec_widgets/widgets/monitor/__init__.py +0 -1
  51. bec_widgets/widgets/monitor/config_dialog.py +0 -574
  52. bec_widgets/widgets/monitor/config_dialog.ui +0 -210
  53. bec_widgets/widgets/monitor/example_configs/config_device.yaml +0 -60
  54. bec_widgets/widgets/monitor/example_configs/config_scans.yaml +0 -92
  55. bec_widgets/widgets/monitor/monitor.py +0 -845
  56. bec_widgets/widgets/monitor/tab_template.ui +0 -180
  57. bec_widgets/widgets/motor_map/__init__.py +0 -1
  58. bec_widgets/widgets/motor_map/motor_map.py +0 -594
  59. bec_widgets/widgets/plots/__init__.py +0 -4
  60. tests/unit_tests/test_bec_monitor.py +0 -220
  61. tests/unit_tests/test_config_dialog.py +0 -178
  62. tests/unit_tests/test_motor_map.py +0 -171
  63. tests/unit_tests/test_validator_errors.py +0 -110
  64. /bec_widgets/{cli → assets}/bec_widgets_icon.png +0 -0
  65. /bec_widgets/{examples/jupyter_console → assets}/terminal_icon.png +0 -0
  66. /bec_widgets/widgets/{plots → figure/plots}/plot_base.py +0 -0
  67. /bec_widgets/widgets/motor_control/{motor_control_table.ui → motor_table/motor_table.ui} +0 -0
  68. /bec_widgets/widgets/motor_control/{motor_control_absolute.ui → movement_absolute/movement_absolute.ui} +0 -0
  69. /bec_widgets/widgets/motor_control/{motor_control_relative.ui → movement_relative/movement_relative.ui} +0 -0
  70. /bec_widgets/widgets/motor_control/{motor_control_selection.ui → selection/selection.ui} +0 -0
  71. {bec_widgets-0.53.3.dist-info → bec_widgets-0.55.0.dist-info}/WHEEL +0 -0
  72. {bec_widgets-0.53.3.dist-info → bec_widgets-0.55.0.dist-info}/licenses/LICENSE +0 -0
@@ -11,18 +11,13 @@ import qdarktheme
11
11
  from pydantic import Field
12
12
  from qtpy.QtCore import Signal as pyqtSignal
13
13
  from qtpy.QtWidgets import QWidget
14
+ from typeguard import typechecked
14
15
 
15
16
  from bec_widgets.utils import BECConnector, ConnectionConfig, WidgetContainerUtils
16
- from bec_widgets.widgets.plots import (
17
- BECImageShow,
18
- BECMotorMap,
19
- BECPlotBase,
20
- BECWaveform,
21
- SubplotConfig,
22
- Waveform1DConfig,
23
- )
24
- from bec_widgets.widgets.plots.image import ImageConfig
25
- from bec_widgets.widgets.plots.motor_map import MotorMapConfig
17
+ from bec_widgets.widgets.figure.plots.image.image import BECImageShow, ImageConfig
18
+ from bec_widgets.widgets.figure.plots.motor_map.motor_map import BECMotorMap, MotorMapConfig
19
+ from bec_widgets.widgets.figure.plots.plot_base import BECPlotBase, SubplotConfig
20
+ from bec_widgets.widgets.figure.plots.waveform.waveform import BECWaveform, Waveform1DConfig
26
21
 
27
22
 
28
23
  class FigureConfig(ConnectionConfig):
@@ -267,19 +262,20 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
267
262
 
268
263
  return waveform
269
264
 
265
+ @typechecked
270
266
  def plot(
271
267
  self,
272
- x_name: str = None,
273
- y_name: str = None,
274
- z_name: str = None,
275
- x_entry: str = None,
276
- y_entry: str = None,
277
- z_entry: str = None,
278
- x: list | np.ndarray = None,
279
- y: list | np.ndarray = None,
280
- color: Optional[str] = None,
281
- color_map_z: Optional[str] = "plasma",
282
- label: Optional[str] = None,
268
+ x: list | np.ndarray | None = None,
269
+ y: list | np.ndarray | None = None,
270
+ x_name: str | None = None,
271
+ y_name: str | None = None,
272
+ z_name: str | None = None,
273
+ x_entry: str | None = None,
274
+ y_entry: str | None = None,
275
+ z_entry: str | None = None,
276
+ color: str | None = None,
277
+ color_map_z: str | None = "plasma",
278
+ label: str | None = None,
283
279
  validate: bool = True,
284
280
  **axis_kwargs,
285
281
  ) -> BECWaveform:
@@ -287,14 +283,14 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
287
283
  Add a 1D waveform plot to the figure. Always access the first waveform widget in the figure.
288
284
 
289
285
  Args:
286
+ x(list | np.ndarray): Custom x data to plot.
287
+ y(list | np.ndarray): Custom y data to plot.
290
288
  x_name(str): The name of the device for the x-axis.
291
289
  y_name(str): The name of the device for the y-axis.
292
290
  z_name(str): The name of the device for the z-axis.
293
291
  x_entry(str): The name of the entry for the x-axis.
294
292
  y_entry(str): The name of the entry for the y-axis.
295
293
  z_entry(str): The name of the entry for the z-axis.
296
- x(list | np.ndarray): Custom x data to plot.
297
- y(list | np.ndarray): Custom y data to plot.
298
294
  color(str): The color of the curve.
299
295
  color_map_z(str): The color map to use for the z-axis.
300
296
  label(str): The label of the curve.
@@ -313,6 +309,27 @@ class BECFigure(BECConnector, pg.GraphicsLayoutWidget):
313
309
  else:
314
310
  waveform = self.add_plot(**axis_kwargs)
315
311
 
312
+ if x is not None and y is None:
313
+ if isinstance(x, np.ndarray):
314
+ if x.ndim == 1:
315
+ y = np.arange(x.size)
316
+ waveform.add_curve_custom(x=np.arange(x.size), y=x, color=color, label=label)
317
+ return waveform
318
+ if x.ndim == 2:
319
+ waveform.add_curve_custom(x=x[:, 0], y=x[:, 1], color=color, label=label)
320
+ return waveform
321
+ elif isinstance(x, list):
322
+ y = np.arange(len(x))
323
+ waveform.add_curve_custom(x=np.arange(len(x)), y=x, color=color, label=label)
324
+ return waveform
325
+ else:
326
+ raise ValueError(
327
+ "Invalid input. Provide either device names (x_name, y_name) or custom data."
328
+ )
329
+ if x is not None and y is not None:
330
+ waveform.add_curve_custom(x=x, y=y, color=color, label=label)
331
+ return waveform
332
+
316
333
  # User wants to add scan curve -> 1D Waveform
317
334
  if x_name is not None and y_name is not None and z_name is None and x is None and y is None:
318
335
  waveform.add_curve_scan(
File without changes
File without changes
@@ -4,50 +4,16 @@ from collections import defaultdict
4
4
  from typing import Any, Literal, Optional
5
5
 
6
6
  import numpy as np
7
- import pyqtgraph as pg
8
7
  from bec_lib.endpoints import MessageEndpoints
9
- from pydantic import BaseModel, Field, ValidationError
10
- from qtpy.QtCore import QObject, QThread
11
- from qtpy.QtCore import Signal as pyqtSignal
8
+ from pydantic import Field, ValidationError
9
+ from qtpy.QtCore import QThread
12
10
  from qtpy.QtCore import Slot as pyqtSlot
13
11
  from qtpy.QtWidgets import QWidget
14
12
 
15
- from bec_widgets.utils import BECConnector, ConnectionConfig, EntryValidator
16
-
17
- from .plot_base import BECPlotBase, SubplotConfig
18
-
19
-
20
- class ProcessingConfig(BaseModel):
21
- fft: Optional[bool] = Field(False, description="Whether to perform FFT on the monitor data.")
22
- log: Optional[bool] = Field(False, description="Whether to perform log on the monitor data.")
23
- center_of_mass: Optional[bool] = Field(
24
- False, description="Whether to calculate the center of mass of the monitor data."
25
- )
26
- transpose: Optional[bool] = Field(
27
- False, description="Whether to transpose the monitor data before displaying."
28
- )
29
- rotation: Optional[int] = Field(
30
- None, description="The rotation angle of the monitor data before displaying."
31
- )
32
-
33
-
34
- class ImageItemConfig(ConnectionConfig):
35
- parent_id: Optional[str] = Field(None, description="The parent plot of the image.")
36
- monitor: Optional[str] = Field(None, description="The name of the monitor.")
37
- source: Optional[str] = Field(None, description="The source of the curve.")
38
- color_map: Optional[str] = Field("magma", description="The color map of the image.")
39
- downsample: Optional[bool] = Field(True, description="Whether to downsample the image.")
40
- opacity: Optional[float] = Field(1.0, description="The opacity of the image.")
41
- vrange: Optional[tuple[int, int]] = Field(
42
- None, description="The range of the color bar. If None, the range is automatically set."
43
- )
44
- color_bar: Optional[Literal["simple", "full"]] = Field(
45
- "simple", description="The type of the color bar."
46
- )
47
- autorange: Optional[bool] = Field(True, description="Whether to autorange the color bar.")
48
- processing: ProcessingConfig = Field(
49
- default_factory=ProcessingConfig, description="The post processing of the image."
50
- )
13
+ from bec_widgets.utils import EntryValidator
14
+ from bec_widgets.widgets.figure.plots.image.image_item import BECImageItem, ImageItemConfig
15
+ from bec_widgets.widgets.figure.plots.image.image_processor import ImageProcessor, ProcessorWorker
16
+ from bec_widgets.widgets.figure.plots.plot_base import BECPlotBase, SubplotConfig
51
17
 
52
18
 
53
19
  class ImageConfig(SubplotConfig):
@@ -57,251 +23,6 @@ class ImageConfig(SubplotConfig):
57
23
  )
58
24
 
59
25
 
60
- class BECImageItem(BECConnector, pg.ImageItem):
61
- USER_ACCESS = [
62
- "rpc_id",
63
- "config_dict",
64
- "set",
65
- "set_fft",
66
- "set_log",
67
- "set_rotation",
68
- "set_transpose",
69
- "set_opacity",
70
- "set_autorange",
71
- "set_color_map",
72
- "set_auto_downsample",
73
- "set_monitor",
74
- "set_vrange",
75
- "get_data",
76
- ]
77
-
78
- def __init__(
79
- self,
80
- config: Optional[ImageItemConfig] = None,
81
- gui_id: Optional[str] = None,
82
- parent_image: Optional[BECImageItem] = None,
83
- **kwargs,
84
- ):
85
- if config is None:
86
- config = ImageItemConfig(widget_class=self.__class__.__name__)
87
- self.config = config
88
- else:
89
- self.config = config
90
- super().__init__(config=config, gui_id=gui_id)
91
- pg.ImageItem.__init__(self)
92
-
93
- self.parent_image = parent_image
94
- self.colorbar_bar = None
95
-
96
- self._add_color_bar(
97
- self.config.color_bar, self.config.vrange
98
- ) # TODO can also support None to not have any colorbar
99
- self.apply_config()
100
- if kwargs:
101
- self.set(**kwargs)
102
-
103
- def apply_config(self):
104
- """
105
- Apply current configuration.
106
- """
107
- self.set_color_map(self.config.color_map)
108
- self.set_auto_downsample(self.config.downsample)
109
- if self.config.vrange is not None:
110
- self.set_vrange(vrange=self.config.vrange)
111
-
112
- def set(self, **kwargs):
113
- """
114
- Set the properties of the image.
115
-
116
- Args:
117
- **kwargs: Keyword arguments for the properties to be set.
118
-
119
- Possible properties:
120
- - downsample
121
- - color_map
122
- - monitor
123
- - opacity
124
- - vrange
125
- - fft
126
- - log
127
- - rot
128
- - transpose
129
- """
130
- method_map = {
131
- "downsample": self.set_auto_downsample,
132
- "color_map": self.set_color_map,
133
- "monitor": self.set_monitor,
134
- "opacity": self.set_opacity,
135
- "vrange": self.set_vrange,
136
- "fft": self.set_fft,
137
- "log": self.set_log,
138
- "rot": self.set_rotation,
139
- "transpose": self.set_transpose,
140
- }
141
- for key, value in kwargs.items():
142
- if key in method_map:
143
- method_map[key](value)
144
- else:
145
- print(f"Warning: '{key}' is not a recognized property.")
146
-
147
- def set_fft(self, enable: bool = False):
148
- """
149
- Set the FFT of the image.
150
-
151
- Args:
152
- enable(bool): Whether to perform FFT on the monitor data.
153
- """
154
- self.config.processing.fft = enable
155
-
156
- def set_log(self, enable: bool = False):
157
- """
158
- Set the log of the image.
159
-
160
- Args:
161
- enable(bool): Whether to perform log on the monitor data.
162
- """
163
- self.config.processing.log = enable
164
- if enable and self.color_bar and self.config.color_bar == "full":
165
- self.color_bar.autoHistogramRange()
166
-
167
- def set_rotation(self, deg_90: int = 0):
168
- """
169
- Set the rotation of the image.
170
-
171
- Args:
172
- deg_90(int): The rotation angle of the monitor data before displaying.
173
- """
174
- self.config.processing.rotation = deg_90
175
-
176
- def set_transpose(self, enable: bool = False):
177
- """
178
- Set the transpose of the image.
179
-
180
- Args:
181
- enable(bool): Whether to transpose the image.
182
- """
183
- self.config.processing.transpose = enable
184
-
185
- def set_opacity(self, opacity: float = 1.0):
186
- """
187
- Set the opacity of the image.
188
-
189
- Args:
190
- opacity(float): The opacity of the image.
191
- """
192
- self.setOpacity(opacity)
193
- self.config.opacity = opacity
194
-
195
- def set_autorange(self, autorange: bool = False):
196
- """
197
- Set the autorange of the color bar.
198
-
199
- Args:
200
- autorange(bool): Whether to autorange the color bar.
201
- """
202
- self.config.autorange = autorange
203
- if self.color_bar is not None:
204
- self.color_bar.autoHistogramRange()
205
-
206
- def set_color_map(self, cmap: str = "magma"):
207
- """
208
- Set the color map of the image.
209
-
210
- Args:
211
- cmap(str): The color map of the image.
212
- """
213
- self.setColorMap(cmap)
214
- if self.color_bar is not None:
215
- if self.config.color_bar == "simple":
216
- self.color_bar.setColorMap(cmap)
217
- elif self.config.color_bar == "full":
218
- self.color_bar.gradient.loadPreset(cmap)
219
- self.config.color_map = cmap
220
-
221
- def set_auto_downsample(self, auto: bool = True):
222
- """
223
- Set the auto downsample of the image.
224
-
225
- Args:
226
- auto(bool): Whether to downsample the image.
227
- """
228
- self.setAutoDownsample(auto)
229
- self.config.downsample = auto
230
-
231
- def set_monitor(self, monitor: str):
232
- """
233
- Set the monitor of the image.
234
-
235
- Args:
236
- monitor(str): The name of the monitor.
237
- """
238
- self.config.monitor = monitor
239
-
240
- def set_vrange(self, vmin: float = None, vmax: float = None, vrange: tuple[int, int] = None):
241
- """
242
- Set the range of the color bar.
243
-
244
- Args:
245
- vmin(float): Minimum value of the color bar.
246
- vmax(float): Maximum value of the color bar.
247
- """
248
- if vrange is not None:
249
- vmin, vmax = vrange
250
- self.setLevels([vmin, vmax])
251
- self.config.vrange = (vmin, vmax)
252
- self.config.autorange = False
253
- if self.color_bar is not None:
254
- if self.config.color_bar == "simple":
255
- self.color_bar.setLevels(low=vmin, high=vmax)
256
- elif self.config.color_bar == "full":
257
- self.color_bar.setLevels(min=vmin, max=vmax)
258
- self.color_bar.setHistogramRange(vmin - 0.1 * vmin, vmax + 0.1 * vmax)
259
-
260
- def get_data(self) -> np.ndarray:
261
- """
262
- Get the data of the image.
263
- Returns:
264
- np.ndarray: The data of the image.
265
- """
266
- return self.image
267
-
268
- def _add_color_bar(
269
- self, color_bar_style: str = "simple", vrange: Optional[tuple[int, int]] = None
270
- ):
271
- """
272
- Add color bar to the layout.
273
-
274
- Args:
275
- style(Literal["simple,full"]): The style of the color bar.
276
- vrange(tuple[int,int]): The range of the color bar.
277
- """
278
- if color_bar_style == "simple":
279
- self.color_bar = pg.ColorBarItem(colorMap=self.config.color_map)
280
- if vrange is not None:
281
- self.color_bar.setLevels(low=vrange[0], high=vrange[1])
282
- self.color_bar.setImageItem(self)
283
- self.parent_image.addItem(self.color_bar) # , row=0, col=1)
284
- self.config.color_bar = "simple"
285
- elif color_bar_style == "full":
286
- # Setting histogram
287
- self.color_bar = pg.HistogramLUTItem()
288
- self.color_bar.setImageItem(self)
289
- self.color_bar.gradient.loadPreset(self.config.color_map)
290
- if vrange is not None:
291
- self.color_bar.setLevels(min=vrange[0], max=vrange[1])
292
- self.color_bar.setHistogramRange(
293
- vrange[0] - 0.1 * vrange[0], vrange[1] + 0.1 * vrange[1]
294
- )
295
-
296
- # Adding histogram to the layout
297
- self.parent_image.addItem(self.color_bar) # , row=0, col=1)
298
-
299
- # save settings
300
- self.config.color_bar = "full"
301
- else:
302
- raise ValueError("style should be 'simple' or 'full'")
303
-
304
-
305
26
  class BECImageShow(BECPlotBase):
306
27
  USER_ACCESS = [
307
28
  "rpc_id",
@@ -837,134 +558,3 @@ class BECImageShow(BECPlotBase):
837
558
  image.cleanup()
838
559
 
839
560
  super().cleanup()
840
-
841
-
842
- class ImageProcessor:
843
- """
844
- Class for processing the image data.
845
- """
846
-
847
- def __init__(self, config: ProcessingConfig = None):
848
- if config is None:
849
- config = ProcessingConfig()
850
- self.config = config
851
-
852
- def set_config(self, config: ProcessingConfig):
853
- """
854
- Set the configuration of the processor.
855
-
856
- Args:
857
- config(ProcessingConfig): The configuration of the processor.
858
- """
859
- self.config = config
860
-
861
- def FFT(self, data: np.ndarray) -> np.ndarray:
862
- """
863
- Perform FFT on the data.
864
-
865
- Args:
866
- data(np.ndarray): The data to be processed.
867
-
868
- Returns:
869
- np.ndarray: The processed data.
870
- """
871
- return np.abs(np.fft.fftshift(np.fft.fft2(data)))
872
-
873
- def rotation(self, data: np.ndarray, rotate_90: int) -> np.ndarray:
874
- """
875
- Rotate the data by 90 degrees n times.
876
-
877
- Args:
878
- data(np.ndarray): The data to be processed.
879
- rotate_90(int): The number of 90 degree rotations.
880
-
881
- Returns:
882
- np.ndarray: The processed data.
883
- """
884
- return np.rot90(data, k=rotate_90, axes=(0, 1))
885
-
886
- def transpose(self, data: np.ndarray) -> np.ndarray:
887
- """
888
- Transpose the data.
889
-
890
- Args:
891
- data(np.ndarray): The data to be processed.
892
-
893
- Returns:
894
- np.ndarray: The processed data.
895
- """
896
- return np.transpose(data)
897
-
898
- def log(self, data: np.ndarray) -> np.ndarray:
899
- """
900
- Perform log on the data.
901
-
902
- Args:
903
- data(np.ndarray): The data to be processed.
904
-
905
- Returns:
906
- np.ndarray: The processed data.
907
- """
908
- # TODO this is not final solution -> data should stay as int16
909
- data = data.astype(np.float32)
910
- offset = 1e-6
911
- data_offset = data + offset
912
- return np.log10(data_offset)
913
-
914
- # def center_of_mass(self, data: np.ndarray) -> tuple: # TODO check functionality
915
- # return np.unravel_index(np.argmax(data), data.shape)
916
-
917
- def process_image(self, data: np.ndarray) -> np.ndarray:
918
- """
919
- Process the data according to the configuration.
920
-
921
- Args:
922
- data(np.ndarray): The data to be processed.
923
-
924
- Returns:
925
- np.ndarray: The processed data.
926
- """
927
- if self.config.fft:
928
- data = self.FFT(data)
929
- if self.config.rotation is not None:
930
- data = self.rotation(data, self.config.rotation)
931
- if self.config.transpose:
932
- data = self.transpose(data)
933
- if self.config.log:
934
- data = self.log(data)
935
- return data
936
-
937
-
938
- class ProcessorWorker(QObject):
939
- """
940
- Worker for processing the image data.
941
- """
942
-
943
- processed = pyqtSignal(str, np.ndarray)
944
- stopRequested = pyqtSignal()
945
- finished = pyqtSignal()
946
-
947
- def __init__(self, processor):
948
- super().__init__()
949
- self.processor = processor
950
- self._isRunning = False
951
- self.stopRequested.connect(self.stop)
952
-
953
- @pyqtSlot(str, np.ndarray)
954
- def process_image(self, device: str, image: np.ndarray):
955
- """
956
- Process the image data.
957
-
958
- Args:
959
- device(str): The name of the device.
960
- image(np.ndarray): The image data.
961
- """
962
- self._isRunning = True
963
- processed_image = self.processor.process_image(image)
964
- self._isRunning = False
965
- if not self._isRunning:
966
- self.processed.emit(device, processed_image)
967
- self.finished.emit()
968
-
969
- def stop(self):
970
- self._isRunning = False