pymodaq 4.1.5__py3-none-any.whl → 4.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pymodaq might be problematic. Click here for more details.

Files changed (80) hide show
  1. pymodaq/__init__.py +23 -4
  2. pymodaq/control_modules/daq_move.py +32 -73
  3. pymodaq/control_modules/daq_viewer.py +73 -98
  4. pymodaq/control_modules/daq_viewer_ui.py +2 -1
  5. pymodaq/control_modules/move_utility_classes.py +17 -7
  6. pymodaq/control_modules/utils.py +153 -5
  7. pymodaq/control_modules/viewer_utility_classes.py +31 -20
  8. pymodaq/dashboard.py +23 -5
  9. pymodaq/examples/tcp_client.py +97 -0
  10. pymodaq/extensions/__init__.py +4 -0
  11. pymodaq/extensions/bayesian/__init__.py +2 -0
  12. pymodaq/extensions/bayesian/bayesian_optimisation.py +673 -0
  13. pymodaq/extensions/bayesian/utils.py +403 -0
  14. pymodaq/extensions/daq_scan.py +4 -4
  15. pymodaq/extensions/daq_scan_ui.py +2 -1
  16. pymodaq/extensions/pid/pid_controller.py +12 -7
  17. pymodaq/extensions/pid/utils.py +9 -26
  18. pymodaq/extensions/utils.py +3 -0
  19. pymodaq/post_treatment/load_and_plot.py +42 -19
  20. pymodaq/resources/VERSION +1 -1
  21. pymodaq/resources/config_template.toml +9 -24
  22. pymodaq/resources/setup_plugin.py +1 -1
  23. pymodaq/utils/config.py +103 -5
  24. pymodaq/utils/daq_utils.py +35 -134
  25. pymodaq/utils/data.py +614 -95
  26. pymodaq/utils/enums.py +17 -1
  27. pymodaq/utils/factory.py +2 -2
  28. pymodaq/utils/gui_utils/custom_app.py +5 -2
  29. pymodaq/utils/gui_utils/dock.py +33 -4
  30. pymodaq/utils/gui_utils/utils.py +14 -1
  31. pymodaq/utils/h5modules/backends.py +9 -1
  32. pymodaq/utils/h5modules/data_saving.py +254 -57
  33. pymodaq/utils/h5modules/saving.py +1 -0
  34. pymodaq/utils/leco/__init__.py +25 -0
  35. pymodaq/utils/leco/daq_move_LECODirector.py +172 -0
  36. pymodaq/utils/leco/daq_xDviewer_LECODirector.py +170 -0
  37. pymodaq/utils/leco/desktop.ini +2 -0
  38. pymodaq/utils/leco/director_utils.py +58 -0
  39. pymodaq/utils/leco/leco_director.py +88 -0
  40. pymodaq/utils/leco/pymodaq_listener.py +279 -0
  41. pymodaq/utils/leco/utils.py +41 -0
  42. pymodaq/utils/managers/action_manager.py +20 -6
  43. pymodaq/utils/managers/parameter_manager.py +6 -4
  44. pymodaq/utils/managers/roi_manager.py +63 -54
  45. pymodaq/utils/math_utils.py +1 -1
  46. pymodaq/utils/plotting/data_viewers/__init__.py +3 -1
  47. pymodaq/utils/plotting/data_viewers/base.py +286 -0
  48. pymodaq/utils/plotting/data_viewers/viewer.py +29 -202
  49. pymodaq/utils/plotting/data_viewers/viewer0D.py +94 -47
  50. pymodaq/utils/plotting/data_viewers/viewer1D.py +341 -174
  51. pymodaq/utils/plotting/data_viewers/viewer1Dbasic.py +1 -1
  52. pymodaq/utils/plotting/data_viewers/viewer2D.py +271 -181
  53. pymodaq/utils/plotting/data_viewers/viewerND.py +26 -22
  54. pymodaq/utils/plotting/items/crosshair.py +3 -3
  55. pymodaq/utils/plotting/items/image.py +2 -1
  56. pymodaq/utils/plotting/plotter/plotter.py +94 -0
  57. pymodaq/utils/plotting/plotter/plotters/__init__.py +0 -0
  58. pymodaq/utils/plotting/plotter/plotters/matplotlib_plotters.py +134 -0
  59. pymodaq/utils/plotting/plotter/plotters/qt_plotters.py +78 -0
  60. pymodaq/utils/plotting/utils/axes_viewer.py +1 -1
  61. pymodaq/utils/plotting/utils/filter.py +194 -147
  62. pymodaq/utils/plotting/utils/lineout.py +13 -11
  63. pymodaq/utils/plotting/utils/plot_utils.py +89 -12
  64. pymodaq/utils/scanner/__init__.py +0 -3
  65. pymodaq/utils/scanner/scan_config.py +1 -9
  66. pymodaq/utils/scanner/scan_factory.py +10 -36
  67. pymodaq/utils/scanner/scanner.py +3 -2
  68. pymodaq/utils/scanner/scanners/_1d_scanners.py +7 -5
  69. pymodaq/utils/scanner/scanners/_2d_scanners.py +36 -49
  70. pymodaq/utils/scanner/scanners/sequential.py +10 -4
  71. pymodaq/utils/scanner/scanners/tabular.py +10 -5
  72. pymodaq/utils/slicing.py +1 -1
  73. pymodaq/utils/tcp_ip/serializer.py +38 -5
  74. pymodaq/utils/tcp_ip/tcp_server_client.py +25 -17
  75. {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/METADATA +4 -2
  76. {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/RECORD +79 -63
  77. pymodaq/resources/config_scan_template.toml +0 -42
  78. {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/WHEEL +0 -0
  79. {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/entry_points.txt +0 -0
  80. {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,403 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created the 31/08/2023
4
+
5
+ @author: Sebastien Weber
6
+ """
7
+ from abc import ABC, abstractproperty, abstractmethod
8
+ from typing import List, TYPE_CHECKING, Union, Dict, Tuple, Iterable
9
+ from pathlib import Path
10
+ import importlib
11
+ import pkgutil
12
+ import inspect
13
+ import numpy as np
14
+ from qtpy import QtWidgets
15
+ import tempfile
16
+ from collections import namedtuple
17
+
18
+ from bayes_opt import BayesianOptimization
19
+ from bayes_opt import UtilityFunction
20
+
21
+
22
+ from pymodaq.utils.h5modules.saving import H5Saver
23
+ from pymodaq.utils.data import (DataToExport, DataActuator, DataToActuators, DataCalculated,
24
+ DataRaw, Axis)
25
+ from pymodaq.utils.managers.modules_manager import ModulesManager
26
+ from pymodaq.utils.daq_utils import find_dict_in_list_from_key_val, get_entrypoints
27
+ from pymodaq.utils.logger import set_logger, get_module_name
28
+ from pymodaq.utils.plotting.data_viewers.viewer import ViewersEnum
29
+ from pymodaq.utils.enums import BaseEnum
30
+ from pymodaq.utils.parameter import Parameter
31
+ from pymodaq.utils.config import BaseConfig
32
+
33
+
34
+ if TYPE_CHECKING:
35
+ from pymodaq.extensions.bayesian.bayesian_optimisation import BayesianOptimisation
36
+
37
+ logger = set_logger(get_module_name(__file__))
38
+
39
+
40
+ class StopType(BaseEnum):
41
+ Predict = 0
42
+
43
+
44
+ class UtilityKind(BaseEnum):
45
+ ucb = 'Upper Confidence Bound'
46
+ ei = 'Expected Improvement'
47
+ poi = 'Probability of Improvement'
48
+
49
+
50
+ UtilityParameters = namedtuple('UtilityParameters',
51
+ ['kind', 'kappa', 'xi', 'kappa_decay', 'kappa_decay_delay'])
52
+
53
+
54
+ StoppingParameters = namedtuple('StoppingParameters',
55
+ ['niter', 'stop_type', 'tolerance', 'npoints'])
56
+
57
+
58
+ class BayesianAlgorithm:
59
+
60
+ def __init__(self, ini_random: int, bounds: dict, **kwargs):
61
+
62
+ self._algo = BayesianOptimization(f=None,
63
+ pbounds=bounds,
64
+ **kwargs
65
+ )
66
+ self._next_point: np.ndarray = None
67
+ self._suggested_coordinates: List[np.ndarray] = []
68
+ self.ini_random_points = ini_random
69
+ self.kappa = 2.5
70
+
71
+ self._utility = UtilityFunction(kind="ucb", kappa=self.kappa, xi=0.0)
72
+
73
+ def set_utility_function(self, kind: str, **kwargs):
74
+ if kind in UtilityKind.names():
75
+ self._utility = UtilityFunction(kind, **kwargs)
76
+
77
+ def update_utility_function(self):
78
+ """ Update the parameters of the Utility function (kappa decay for instance)"""
79
+ self._utility.update_params()
80
+ self.kappa = self._utility.kappa
81
+
82
+ @property
83
+ def bounds(self) -> List[np.ndarray]:
84
+ return [bound for bound in self._algo._space.bounds]
85
+
86
+ @bounds.setter
87
+ def bounds(self, bounds: Union[Dict[str, Tuple[float, float]], Iterable[np.ndarray]]):
88
+ if isinstance(bounds, dict):
89
+ self._algo.set_bounds(bounds)
90
+ else:
91
+ self._algo.set_bounds(self._algo._space.array_to_params(np.array(bounds)))
92
+
93
+ def get_random_point(self) -> np.ndarray:
94
+ """ Get a random point coordinates in the defined bounds"""
95
+ point = []
96
+ for bound in self.bounds:
97
+ point.append((np.max(bound) - np.min(bound)) * np.random.random_sample() +
98
+ np.min(bound))
99
+ return np.array(point)
100
+
101
+ def ask(self) -> np.ndarray:
102
+ if self.ini_random_points > 0:
103
+ self.ini_random_points -= 1
104
+ self._next_point = self.get_random_point()
105
+ else:
106
+ self._next_point = self._algo.space.params_to_array(self._algo.suggest(self._utility))
107
+ self._suggested_coordinates.append(self._next_point)
108
+ return self._next_point
109
+
110
+ def tell(self, function_value: float):
111
+ self._algo.register(params=self._next_point, target=function_value)
112
+
113
+ @property
114
+ def best_fitness(self) -> float:
115
+ return self._algo.max['target']
116
+
117
+ @property
118
+ def best_individual(self) -> Union[np.ndarray, None]:
119
+ max_param = self._algo.max.get('params', None)
120
+ if max_param is None:
121
+ return None
122
+ return self._algo.space.params_to_array(max_param)
123
+
124
+ def stopping(self, ind_iter: int, stopping_parameters: StoppingParameters):
125
+ if ind_iter >= stopping_parameters.niter:
126
+ return True
127
+ if ind_iter > stopping_parameters.npoints and stopping_parameters.stop_type == 'Predict':
128
+ coordinates = np.array(self._suggested_coordinates[-stopping_parameters.npoints:]).T
129
+ return np.all(np.std(coordinates, axis=1)
130
+ < stopping_parameters.tolerance)
131
+ return False
132
+
133
+ def _posterior(self, x_obs, y_obs, grid):
134
+
135
+ if len(x_obs.shape) == 1:
136
+ x_obs = x_obs.reshape(-1, 1)
137
+ y_obs = y_obs.reshape(-1, 1)
138
+ grid = grid.reshape(-1, 1)
139
+
140
+ self._algo._gp.fit(x_obs, y_obs)
141
+
142
+ mu, sigma = self._algo._gp.predict(grid, return_std=True)
143
+ return mu, sigma
144
+
145
+ def get_dwa_obervations(self, actuators_name):
146
+ try:
147
+ axes = [Axis(act, data=np.array([res['params'][act] for res in self._algo.res])) for
148
+ act in actuators_name]
149
+ data_arrays = [np.array([res['target'] for res in self._algo.res])]
150
+
151
+ return DataRaw('Observations', data=data_arrays, labels=actuators_name,
152
+ axes=axes)
153
+
154
+ except Exception as e:
155
+ pass
156
+
157
+ def get_1D_dwa_gp(self, x: np.ndarray, actuator_name: str):
158
+ """ Get Measurements and predictions as DataWithAxes
159
+
160
+ Parameters
161
+ ----------
162
+ x: np.ndarray
163
+ linear grid to get the Bayesian Optimisation On
164
+ """
165
+
166
+ dwa_obervation = self.get_dwa_obervations([actuator_name])
167
+
168
+ mu, sigma = self._posterior(dwa_obervation.axes[0].get_data(),
169
+ dwa_obervation.data[0], x)
170
+
171
+ dwa_measured = DataCalculated('Measurements', data=[dwa_obervation.data[0]],
172
+ axes=[Axis('measured_axis',
173
+ data=dwa_obervation.axes[0].get_data())],
174
+ labels=['Sampled'])
175
+ dwa_prediction = DataCalculated('Prediction', data=[mu],
176
+ axes=[Axis('tested_pos', data=x)],
177
+ errors=[1.96 * sigma])
178
+ return dwa_measured, dwa_prediction
179
+
180
+
181
+ class BayesianModelGeneric(ABC):
182
+
183
+ optimisation_algorithm: BayesianAlgorithm = BayesianAlgorithm
184
+
185
+ actuators_name: List[str] = []
186
+ detectors_name: List[str] = []
187
+
188
+ observables_dim: List[ViewersEnum] = []
189
+
190
+ params = [] # to be subclassed
191
+
192
+ def __init__(self, optimisation_controller: 'BayesianOptimisation'):
193
+ self.optimisation_controller = optimisation_controller # instance of the pid_controller using this model
194
+ self.modules_manager: ModulesManager = optimisation_controller.modules_manager
195
+
196
+ self.settings = self.optimisation_controller.settings.child('models', 'model_params') # set of parameters
197
+ self.check_modules(self.modules_manager)
198
+
199
+ def check_modules(self, modules_manager):
200
+ for act in self.actuators_name:
201
+ if act not in modules_manager.actuators_name:
202
+ logger.warning(f'The actuator {act} defined in the model is'
203
+ f' not present in the Dashboard')
204
+ return False
205
+ for det in self.detectors_name:
206
+ if det not in modules_manager.detectors_name:
207
+ logger.warning(f'The detector {det} defined in the model is'
208
+ f' not present in the Dashboard')
209
+
210
+ def update_detector_names(self):
211
+ names = self.optimisation_controller.settings.child(
212
+ 'main_settings', 'detector_modules').value()['selected']
213
+ self.data_names = []
214
+ for name in names:
215
+ name = name.split('//')
216
+ self.data_names.append(name)
217
+
218
+ def update_settings(self, param: Parameter):
219
+ """
220
+ Get a parameter instance whose value has been modified by a user on the UI
221
+ To be overwritten in child class
222
+ """
223
+ ...
224
+
225
+ def update_plots(self):
226
+ """ Called when updating the live plots """
227
+ pass
228
+
229
+ def ini_model_base(self):
230
+ self.modules_manager.selected_actuators_name = self.actuators_name
231
+ self.modules_manager.selected_detectors_name = self.detectors_name
232
+
233
+ self.ini_model()
234
+
235
+ def ini_model(self):
236
+ """ To be subclassed
237
+
238
+ Initialize whatever is needed by your custom model
239
+ """
240
+ raise NotImplementedError
241
+
242
+ def runner_initialized(self):
243
+ """ To be subclassed
244
+
245
+ Initialize whatever is needed by your custom model after the optimization runner is
246
+ initialized
247
+ """
248
+ pass
249
+
250
+ def convert_input(self, measurements: DataToExport) -> float:
251
+ """
252
+ Convert the measurements in the units to be fed to the Optimisation Controller
253
+ Parameters
254
+ ----------
255
+ measurements: DataToExport
256
+ data object exported from the detectors from which the model extract a float value
257
+ (fitness) to be fed to the algorithm
258
+
259
+ Returns
260
+ -------
261
+ float
262
+
263
+ """
264
+ raise NotImplementedError
265
+
266
+ def convert_output(self, outputs: List[np.ndarray], best_individual=None) -> DataToActuators:
267
+ """ Convert the output of the Optimisation Controller in units to be fed into the actuators
268
+ Parameters
269
+ ----------
270
+ outputs: list of numpy ndarray
271
+ output value from the controller from which the model extract a value of the same units as the actuators
272
+ best_individual: np.ndarray
273
+ the coordinates of the best individual so far
274
+ Returns
275
+ -------
276
+ DataToActuatorOpti: derived from DataToExport. Contains value to be fed to the actuators with a a mode
277
+ attribute, either 'rel' for relative or 'abs' for absolute.
278
+
279
+ """
280
+ raise NotImplementedError
281
+
282
+
283
+ class BayesianModelDefault(BayesianModelGeneric):
284
+
285
+ actuators_name: List[str] = [] # to be populated dynamically at instantiation
286
+ detectors_name: List[str] = [] # to be populated dynamically at instantiation
287
+
288
+ params = [{'title': 'Optimizing signal', 'name': 'optimizing_signal', 'type': 'group',
289
+ 'children': [
290
+ {'title': 'Get data', 'name': 'data_probe', 'type': 'action'},
291
+ {'title': 'Optimize 0Ds:', 'name': 'optimize_0d', 'type': 'itemselect',
292
+ 'checkbox': True},
293
+ ]},]
294
+
295
+ def __init__(self, optimisation_controller: 'BayesianOptimisation'):
296
+ self.actuators_name = optimisation_controller.modules_manager.actuators_name
297
+ self.detectors_name = optimisation_controller.modules_manager.detectors_name
298
+ super().__init__(optimisation_controller)
299
+
300
+ self.settings.child('optimizing_signal', 'data_probe').sigActivated.connect(
301
+ self.optimize_from)
302
+
303
+ def ini_model(self):
304
+ pass
305
+
306
+ def optimize_from(self):
307
+ self.modules_manager.get_det_data_list()
308
+ data0D = self.modules_manager.settings['data_dimensions', 'det_data_list0D']
309
+ data0D['selected'] = data0D['all_items']
310
+ self.settings.child('optimizing_signal', 'optimize_0d').setValue(data0D)
311
+
312
+ def update_settings(self, param: Parameter):
313
+ pass
314
+
315
+ def convert_input(self, measurements: DataToExport) -> float:
316
+ """ Convert the measurements in the units to be fed to the Optimisation Controller
317
+
318
+ Parameters
319
+ ----------
320
+ measurements: DataToExport
321
+ data object exported from the detectors from which the model extract a float value
322
+ (fitness) to be fed to the algorithm
323
+
324
+ Returns
325
+ -------
326
+ float
327
+
328
+ """
329
+ data_name: str = self.settings['optimizing_signal', 'optimize_0d']['selected'][0]
330
+ origin, name = data_name.split('/')
331
+ return float(measurements.get_data_from_name_origin(name, origin).data[0][0])
332
+
333
+ def convert_output(self, outputs: List[np.ndarray], best_individual=None) -> DataToActuators:
334
+ """ Convert the output of the Optimisation Controller in units to be fed into the actuators
335
+ Parameters
336
+ ----------
337
+ outputs: list of numpy ndarray
338
+ output value from the controller from which the model extract a value of the same units as the actuators
339
+ best_individual: np.ndarray
340
+ the coordinates of the best individual so far
341
+
342
+ Returns
343
+ -------
344
+ DataToActuators: derived from DataToExport. Contains value to be fed to the actuators
345
+ with a mode attribute, either 'rel' for relative or 'abs' for absolute.
346
+
347
+ """
348
+ return DataToActuators('outputs', mode='abs',
349
+ data=[DataActuator(self.modules_manager.actuators_name[ind],
350
+ data=float(outputs[ind])) for ind in
351
+ range(len(outputs))])
352
+
353
+
354
+ def get_bayesian_models(model_name=None):
355
+ """
356
+ Get PID Models as a list to instantiate Control Actuators per degree of liberty in the model
357
+
358
+ Returns
359
+ -------
360
+ list: list of disct containting the name and python module of the found models
361
+ """
362
+ models_import = []
363
+ discovered_models = get_entrypoints(group='pymodaq.models')
364
+ if len(discovered_models) > 0:
365
+ for pkg in discovered_models:
366
+ try:
367
+ module = importlib.import_module(pkg.value)
368
+ module_name = pkg.value
369
+
370
+ for mod in pkgutil.iter_modules([
371
+ str(Path(module.__file__).parent.joinpath('models'))]):
372
+ try:
373
+ model_module = importlib.import_module(f'{module_name}.models.{mod.name}',
374
+ module)
375
+ classes = inspect.getmembers(model_module, inspect.isclass)
376
+ for name, klass in classes:
377
+ if issubclass(klass, BayesianModelGeneric):
378
+ if find_dict_in_list_from_key_val(models_import, 'name', mod.name)\
379
+ is None:
380
+ models_import.append({'name': klass.__name__,
381
+ 'module': model_module,
382
+ 'class': klass})
383
+
384
+ except Exception as e:
385
+ logger.warning(str(e))
386
+
387
+ except Exception as e:
388
+ logger.warning(f'Impossible to import the {pkg.value} bayesian model: {str(e)}')
389
+ if find_dict_in_list_from_key_val(models_import, 'name', 'BayesianModelDefault') \
390
+ is None:
391
+ models_import.append({'name': 'BayesianModelDefault',
392
+ 'module': inspect.getmodule(BayesianModelDefault),
393
+ 'class': BayesianModelDefault})
394
+ if model_name is None:
395
+ return models_import
396
+ else:
397
+ return find_dict_in_list_from_key_val(models_import, 'name', model_name)
398
+
399
+
400
+ class BayesianConfig(BaseConfig):
401
+ """Main class to deal with configuration values for this plugin"""
402
+ config_template_path = None
403
+ config_name = f"bayesian_settings"
@@ -22,7 +22,7 @@ from pymodaq.utils import data as data_mod
22
22
  from pymodaq.utils.logger import set_logger, get_module_name
23
23
  from pymodaq.utils.config import Config, get_set_preset_path
24
24
  from pymodaq.utils.parameter import ioxml
25
- from pymodaq.utils.plotting.data_viewers.viewer import ViewersEnum
25
+ from pymodaq.utils.plotting.data_viewers import ViewersEnum
26
26
  from pymodaq.utils.managers.parameter_manager import ParameterManager, Parameter, ParameterTree
27
27
 
28
28
  from pymodaq.utils import exceptions
@@ -384,7 +384,8 @@ class DAQScan(QObject, ParameterManager):
384
384
 
385
385
  def show_file_content(self):
386
386
  try:
387
- self.h5saver.init_file(addhoc_file_path=self.h5saver.settings.child(('current_h5_file')).value())
387
+ self.h5saver.init_file(addhoc_file_path=
388
+ self.h5saver.settings.child('current_h5_file').value())
388
389
  self.h5saver.show_file_content()
389
390
  except Exception as e:
390
391
  logger.exception(str(e))
@@ -1122,8 +1123,7 @@ class DAQScanAcquisition(QObject):
1122
1123
  if self.Naverage > 1:
1123
1124
  for nav_axis in nav_axes:
1124
1125
  nav_axis.index += 1
1125
- nav_axes.append(data_mod.Axis('Average', data=np.linspace(0, self.Naverage - 1,
1126
- self.Naverage),
1126
+ nav_axes.append(data_mod.Axis('Average', data=np.linspace(0, self.Naverage - 1, self.Naverage),
1127
1127
  index=0))
1128
1128
  self.module_and_data_saver.add_nav_axes(nav_axes)
1129
1129
 
@@ -16,7 +16,8 @@ from pymodaq.utils.config import Config, get_set_preset_path
16
16
  from pymodaq.utils.gui_utils import DockArea, Dock
17
17
  from pymodaq.utils.gui_utils.widgets.spinbox import QSpinBox_ro
18
18
  from pymodaq.utils.parameter.pymodaq_ptypes.led import QLED
19
- from pymodaq.utils.plotting.data_viewers.viewer import ViewerDispatcher, ViewersEnum
19
+ from pymodaq.utils.plotting.data_viewers.viewer import ViewerDispatcher
20
+ from pymodaq.utils.plotting.data_viewers import ViewersEnum
20
21
  from pymodaq.utils.daq_utils import ThreadCommand
21
22
 
22
23
  if TYPE_CHECKING:
@@ -15,11 +15,11 @@ from pymodaq.utils.daq_utils import ThreadCommand, find_dict_in_list_from_key_va
15
15
  from pymodaq.utils.managers.modules_manager import ModulesManager
16
16
  from pymodaq.utils.plotting.data_viewers.viewer0D import Viewer0D
17
17
  from pymodaq.utils.gui_utils.widgets import QLED
18
- from pymodaq.extensions.pid.utils import DataToActuatorPID, get_models
18
+ from pymodaq.extensions.pid.utils import get_models
19
19
  from pymodaq.utils.gui_utils.dock import DockArea, Dock
20
20
  from pymodaq.utils.gui_utils.custom_app import CustomApp
21
21
  from pymodaq.utils.gui_utils.widgets.label import LabelWithFont
22
- from pymodaq.utils.data import DataToExport, DataCalculated, DataActuator, DataRaw
22
+ from pymodaq.utils.data import DataToExport, DataCalculated, DataActuator, DataRaw, DataToActuators
23
23
  from pymodaq.utils.config import Config
24
24
 
25
25
  config = Config()
@@ -479,7 +479,7 @@ class PIDRunner(QObject):
479
479
  data=[np.array([setpoints[ind]])])
480
480
  for ind in range(Nsetpoints)])
481
481
  self.outputs = [0. for _ in range(Nsetpoints)]
482
- self.outputs_to_actuators = DataToActuatorPID('pid',
482
+ self.outputs_to_actuators = DataToActuators('pid',
483
483
  mode='rel',
484
484
  data=[DataActuator(self.model_class.actuators_name[ind],
485
485
  data=self.outputs[ind])
@@ -505,8 +505,13 @@ class PIDRunner(QObject):
505
505
  # self.timeout_timer.timeout.connect(self.timeout)
506
506
  #
507
507
  def timerEvent(self, event):
508
- dte = DataToExport('toplot', data=[self.outputs_to_actuators.merge_as_dwa('Data0D', name='outputs')])
509
- dte.append(self.inputs_from_dets.merge_as_dwa('Data0D', name='inputs'))
508
+ outputs_dwa = self.outputs_to_actuators.merge_as_dwa('Data0D', name='outputs')
509
+ outputs_dwa.labels = self.modules_manager.selected_actuators_name
510
+ dte = DataToExport('toplot', data=[outputs_dwa])
511
+
512
+ inputs_dwa = self.inputs_from_dets.merge_as_dwa('Data0D', name='inputs')
513
+ inputs_dwa.labels = self.modules_manager.selected_actuators_name
514
+ dte.append(inputs_dwa)
510
515
  self.pid_output_signal.emit(dte)
511
516
 
512
517
  @Slot(ThreadCommand)
@@ -582,8 +587,8 @@ class PIDRunner(QObject):
582
587
  self.outputs = [pid.setpoint for pid in self.pids]
583
588
 
584
589
  dt = time.perf_counter() - self.current_time
585
- self.outputs_to_actuators: DataToActuatorPID = self.model_class.convert_output(self.outputs, dt,
586
- stab=True)
590
+ self.outputs_to_actuators: DataToActuators = (
591
+ self.model_class.convert_output(self.outputs, dt, stab=True))
587
592
 
588
593
  if not self.paused:
589
594
  self.modules_manager.move_actuators(self.outputs_to_actuators,
@@ -9,10 +9,12 @@ from pymodaq.utils.gui_utils.dock import DockArea
9
9
  from pymodaq.utils.daq_utils import get_plugins
10
10
  from pymodaq.utils.logger import get_module_name, set_logger
11
11
  from pymodaq.utils.daq_utils import find_dict_in_list_from_key_val, get_entrypoints
12
- from pymodaq.utils.data import DataToExport, DataCalculated, DataActuator
12
+ from pymodaq.utils.data import DataToExport, DataCalculated, DataActuator, DataToActuators
13
+ from pymodaq.utils.messenger import deprecation_msg
13
14
 
14
15
  logger = set_logger(get_module_name(__file__))
15
16
 
17
+
16
18
  DAQ_Move_Stage_type = get_plugins('daq_move')
17
19
  DAQ_0DViewer_Det_types = get_plugins('daq_0Dviewer')
18
20
  DAQ_1DViewer_Det_types = get_plugins('daq_1Dviewer')
@@ -20,31 +22,11 @@ DAQ_2DViewer_Det_types = get_plugins('daq_2Dviewer')
20
22
  DAQ_NDViewer_Det_types = get_plugins('daq_NDviewer')
21
23
 
22
24
 
23
- class DataToActuatorPID(DataToExport):
24
- """ Particular case of a DataToExport adding one named parameter to indicate what kind of change should be applied
25
- to the actuators, absolute or relative
26
-
27
- Attributes
28
- ----------
29
- mode: str
30
- Adds an attribute called mode holding a string describing the type of change: relative or absolute
31
-
32
- Parameters
33
- ---------
34
- mode: str
35
- either 'rel' or 'abs' for a relative or absolute change of the actuator's values
36
- """
25
+ class DataToActuatorPID(DataToActuators):
37
26
 
38
- def __init__(self, *args, mode='rel', **kwargs):
39
- if mode not in ['rel', 'abs']:
40
- warnings.warn('Incorrect mode for the actuators, switching to default relative mode: rel')
41
- mode = 'rel'
42
- kwargs.update({'mode': mode})
27
+ def __init__(self, *args, **kwargs):
43
28
  super().__init__(*args, **kwargs)
44
-
45
- def __repr__(self):
46
- return f'{super().__repr__()}: {self.mode}'
47
-
29
+ deprecation_msg('DataToActuatorPID object is deprecated use: pymodaq.utils.data:DataToActuators')
48
30
 
49
31
  class PIDModelGeneric:
50
32
  limits = dict(max=dict(state=False, value=1),
@@ -130,7 +112,7 @@ class PIDModelGeneric:
130
112
  """
131
113
  raise NotImplementedError
132
114
 
133
- def convert_output(self, outputs: List[float], dt, stab=True) -> DataToActuatorPID:
115
+ def convert_output(self, outputs: List[float], dt, stab=True) -> DataToActuators:
134
116
  """
135
117
  Convert the output of the PID in units to be fed into the actuator
136
118
  Parameters
@@ -143,7 +125,7 @@ class PIDModelGeneric:
143
125
 
144
126
  """
145
127
  self.curr_output = outputs
146
- return DataToActuatorPID('pid', mode='rel',
128
+ return DataToActuators('pid', mode='rel',
147
129
  data=[DataActuator(self.actuators_name[ind], data=outputs[ind])
148
130
  for ind in range(len(outputs))])
149
131
 
@@ -195,6 +177,7 @@ def get_models(model_name=None):
195
177
  from pymodaq.extensions.pid.utils import PIDModelGeneric
196
178
  models_import = []
197
179
  discovered_models = get_entrypoints(group='pymodaq.pid_models')
180
+ discovered_models = get_entrypoints(group='pymodaq.models')
198
181
  if len(discovered_models) > 0:
199
182
  for pkg in discovered_models:
200
183
  try:
@@ -7,9 +7,11 @@ Created the 27/10/2022
7
7
  import importlib
8
8
  from pathlib import Path
9
9
  import pkgutil
10
+ import warnings
10
11
 
11
12
  from pymodaq.utils import logger as logger_module
12
13
  from pymodaq.utils.daq_utils import get_entrypoints
14
+ from pymodaq.utils.data import DataToExport
13
15
  logger = logger_module.set_logger(logger_module.get_module_name(__file__))
14
16
 
15
17
 
@@ -52,3 +54,4 @@ def get_extensions():
52
54
  logger.warning(f'Impossible to import the {pkg.value}.extensions.{mod} extension: {str(e)}')
53
55
 
54
56
  return extension_import
57
+