pymodaq 4.1.5__py3-none-any.whl → 4.2.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.

Potentially problematic release.


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

Files changed (79) hide show
  1. pymodaq/__init__.py +41 -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/daq_move_LECODirector.py +172 -0
  35. pymodaq/utils/leco/daq_xDviewer_LECODirector.py +170 -0
  36. pymodaq/utils/leco/desktop.ini +2 -0
  37. pymodaq/utils/leco/director_utils.py +58 -0
  38. pymodaq/utils/leco/leco_director.py +88 -0
  39. pymodaq/utils/leco/pymodaq_listener.py +279 -0
  40. pymodaq/utils/leco/utils.py +41 -0
  41. pymodaq/utils/managers/action_manager.py +20 -6
  42. pymodaq/utils/managers/parameter_manager.py +6 -4
  43. pymodaq/utils/managers/roi_manager.py +63 -54
  44. pymodaq/utils/math_utils.py +1 -1
  45. pymodaq/utils/plotting/data_viewers/__init__.py +3 -1
  46. pymodaq/utils/plotting/data_viewers/base.py +286 -0
  47. pymodaq/utils/plotting/data_viewers/viewer.py +29 -202
  48. pymodaq/utils/plotting/data_viewers/viewer0D.py +94 -47
  49. pymodaq/utils/plotting/data_viewers/viewer1D.py +341 -174
  50. pymodaq/utils/plotting/data_viewers/viewer1Dbasic.py +1 -1
  51. pymodaq/utils/plotting/data_viewers/viewer2D.py +271 -181
  52. pymodaq/utils/plotting/data_viewers/viewerND.py +26 -22
  53. pymodaq/utils/plotting/items/crosshair.py +3 -3
  54. pymodaq/utils/plotting/items/image.py +2 -1
  55. pymodaq/utils/plotting/plotter/plotter.py +94 -0
  56. pymodaq/utils/plotting/plotter/plotters/__init__.py +0 -0
  57. pymodaq/utils/plotting/plotter/plotters/matplotlib_plotters.py +134 -0
  58. pymodaq/utils/plotting/plotter/plotters/qt_plotters.py +78 -0
  59. pymodaq/utils/plotting/utils/axes_viewer.py +1 -1
  60. pymodaq/utils/plotting/utils/filter.py +194 -147
  61. pymodaq/utils/plotting/utils/lineout.py +13 -11
  62. pymodaq/utils/plotting/utils/plot_utils.py +89 -12
  63. pymodaq/utils/scanner/__init__.py +0 -3
  64. pymodaq/utils/scanner/scan_config.py +1 -9
  65. pymodaq/utils/scanner/scan_factory.py +10 -36
  66. pymodaq/utils/scanner/scanner.py +3 -2
  67. pymodaq/utils/scanner/scanners/_1d_scanners.py +7 -5
  68. pymodaq/utils/scanner/scanners/_2d_scanners.py +36 -49
  69. pymodaq/utils/scanner/scanners/sequential.py +10 -4
  70. pymodaq/utils/scanner/scanners/tabular.py +10 -5
  71. pymodaq/utils/slicing.py +1 -1
  72. pymodaq/utils/tcp_ip/serializer.py +38 -5
  73. pymodaq/utils/tcp_ip/tcp_server_client.py +25 -17
  74. {pymodaq-4.1.5.dist-info → pymodaq-4.2.0.dist-info}/METADATA +4 -2
  75. {pymodaq-4.1.5.dist-info → pymodaq-4.2.0.dist-info}/RECORD +78 -63
  76. pymodaq/resources/config_scan_template.toml +0 -42
  77. {pymodaq-4.1.5.dist-info → pymodaq-4.2.0.dist-info}/WHEEL +0 -0
  78. {pymodaq-4.1.5.dist-info → pymodaq-4.2.0.dist-info}/entry_points.txt +0 -0
  79. {pymodaq-4.1.5.dist-info → pymodaq-4.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -19,7 +19,8 @@ from pymodaq.utils.gui_utils.widgets import PushButtonIcon, LabelWithFont, QLED
19
19
  from pymodaq.utils.gui_utils import Dock
20
20
  from pymodaq.utils.config import Config
21
21
  from pymodaq.control_modules.utils import DET_TYPES, DAQTypesEnum
22
- from pymodaq.utils.plotting.data_viewers.viewer import ViewerFactory, ViewersEnum, ViewerDispatcher
22
+ from pymodaq.utils.plotting.data_viewers.viewer import ViewerFactory, ViewerDispatcher
23
+ from pymodaq.utils.plotting.data_viewers import ViewersEnum
23
24
  from pymodaq.utils.enums import enum_checker
24
25
 
25
26
 
@@ -1,5 +1,5 @@
1
1
  from time import perf_counter
2
- from typing import Union, List, Dict, TYPE_CHECKING
2
+ from typing import Union, List, Dict, TYPE_CHECKING, Optional
3
3
  from numbers import Number
4
4
 
5
5
  from easydict import EasyDict as edict
@@ -122,6 +122,15 @@ params = [
122
122
  'value': config('network', 'tcp-server', 'ip')},
123
123
  {'title': 'Port:', 'name': 'port', 'type': 'int', 'value': config('network', 'tcp-server', 'port')},
124
124
  ]},
125
+ {'title': 'LECO options:', 'name': 'leco', 'type': 'group', 'visible': True, 'expanded': False,
126
+ 'children': [
127
+ {'title': 'Connect:', 'name': 'connect_leco_server', 'type': 'bool_push', 'label': 'Connect',
128
+ 'value': False},
129
+ {'title': 'Connected?:', 'name': 'leco_connected', 'type': 'led', 'value': False},
130
+ {'title': 'Name', 'name': 'leco_name', 'type': 'str', 'value': "", 'default': ""},
131
+ {'title': 'Host:', 'name': 'host', 'type': 'str', 'value': config('network', "leco-server", "host"), "default": "localhost"},
132
+ {'title': 'Port:', 'name': 'port', 'type': 'int', 'value': config('network', 'leco-server', 'port')},
133
+ ]},
125
134
  ]},
126
135
  {'title': 'Actuator Settings:', 'name': 'move_settings', 'type': 'group'}
127
136
  ]
@@ -197,7 +206,8 @@ class DAQ_Move_base(QObject):
197
206
  data_actuator_type = DataActuatorType['float']
198
207
  data_shape = (1, ) # expected shape of the underlying actuator's value (in general a float so shape = (1, ))
199
208
 
200
- def __init__(self, parent: 'DAQ_Move_Hardware' = None, params_state: dict = None):
209
+ def __init__(self, parent: Optional['DAQ_Move_Hardware'] = None,
210
+ params_state: Optional[dict] = None):
201
211
  QObject.__init__(self) # to make sure this is the parent class
202
212
  self.move_is_done = False
203
213
  self.parent = parent
@@ -280,7 +290,7 @@ class DAQ_Move_base(QObject):
280
290
  def ini_stage_init(self, old_controller=None, new_controller=None):
281
291
  """Manage the Master/Slave controller issue
282
292
 
283
- First initialize the status dictionnary
293
+ First initialize the status dictionary
284
294
  Then check whether this stage is controlled by a multiaxe controller (to be defined for each plugin)
285
295
  if it is a multiaxes controller then:
286
296
  * if it is Master: init the controller here
@@ -438,7 +448,7 @@ class DAQ_Move_base(QObject):
438
448
  def commit_common_settings(self, param):
439
449
  pass
440
450
 
441
- def move_done(self, position: DataActuator = None): # the position argument is just there to match some signature of child classes
451
+ def move_done(self, position: Optional[DataActuator] = None): # the position argument is just there to match some signature of child classes
442
452
  """
443
453
  | Emit a move done signal transmitting the float position to hardware.
444
454
  | The position argument is just there to match some signature of child classes.
@@ -494,7 +504,7 @@ class DAQ_Move_base(QObject):
494
504
  logger.debug(f'Check move_is_done: {self.move_is_done}')
495
505
  if self.move_is_done:
496
506
  self.emit_status(ThreadCommand('Move has been stopped', ))
497
- logger.info(f'Move has been stopped')
507
+ logger.info('Move has been stopped')
498
508
  self.current_value = self.get_actuator_value()
499
509
 
500
510
  self.emit_value(self._current_value)
@@ -503,7 +513,7 @@ class DAQ_Move_base(QObject):
503
513
  if perf_counter() - self.start_time >= self.settings['timeout']:
504
514
  self.poll_timer.stop()
505
515
  self.emit_status(ThreadCommand('raise_timeout', ))
506
- logger.info(f'Timeout activated')
516
+ logger.info('Timeout activated')
507
517
  else:
508
518
  self.poll_timer.stop()
509
519
  logger.debug(f'Current value: {self._current_value}')
@@ -661,7 +671,7 @@ class DAQ_Move_TCP_server(DAQ_Move_base, TCPServer):
661
671
 
662
672
  def ini_stage(self, controller=None):
663
673
  """
664
- | Initialisation procedure of the detector updating the status dictionnary.
674
+ | Initialisation procedure of the detector updating the status dictionary.
665
675
  |
666
676
  | Init axes from image , here returns only None values (to tricky to di it with the server and not really necessary for images anyway)
667
677
 
@@ -4,18 +4,24 @@ Created the 03/10/2022
4
4
 
5
5
  @author: Sebastien Weber
6
6
  """
7
+ from random import randint
8
+ from typing import Optional, Type
9
+
7
10
  from easydict import EasyDict as edict
8
11
 
9
12
  from qtpy import QtCore
10
- from qtpy.QtCore import Signal, QObject, Qt
13
+ from qtpy.QtCore import Signal, QObject, Qt, Slot, QThread
11
14
  from pymodaq.utils.gui_utils import CustomApp
12
15
  from pymodaq.utils.daq_utils import ThreadCommand, get_plugins, find_dict_in_list_from_key_val
13
16
  from pymodaq.utils.config import Config
14
- from pymodaq.utils.parameter import Parameter
17
+ from pymodaq.utils.tcp_ip.tcp_server_client import TCPClient
18
+ from pymodaq.utils.parameter import Parameter, ioxml
19
+ from pymodaq.utils.managers.parameter_manager import ParameterManager
15
20
  from pymodaq.utils.enums import BaseEnum, enum_checker
16
- from pymodaq.utils.plotting.data_viewers.viewer import ViewersEnum
21
+ from pymodaq.utils.plotting.data_viewers import ViewersEnum
17
22
  from pymodaq.utils.exceptions import DetectorError
18
23
  from pymodaq.utils import config as configmod
24
+ from pymodaq.utils.leco.pymodaq_listener import ActorListener, LECOClientCommands, LECOCommands
19
25
 
20
26
 
21
27
  class DAQTypesEnum(BaseEnum):
@@ -116,7 +122,7 @@ class ControlModule(QObject):
116
122
  self._tcpclient_thread = None
117
123
  self._hardware_thread = None
118
124
  self.module_and_data_saver = None
119
- self.plugin_config: configmod.Config = None
125
+ self.plugin_config: Optional[configmod.Config] = None
120
126
 
121
127
  def __repr__(self):
122
128
  return f'{self.__class__.__name__}: {self.title}'
@@ -253,7 +259,7 @@ class ControlModule(QObject):
253
259
  raise NotImplementedError
254
260
 
255
261
  def quit_fun(self):
256
- """Programmatic entry to quit the controle module"""
262
+ """Programmatic entry to quit the control module"""
257
263
  raise NotImplementedError
258
264
 
259
265
  def init_hardware(self, do_init=True):
@@ -343,6 +349,148 @@ class ControlModule(QObject):
343
349
  attr = value
344
350
 
345
351
 
352
+ class ParameterControlModule(ParameterManager, ControlModule):
353
+ """Base class for a control module with parameters."""
354
+
355
+ _update_settings_signal = Signal(edict)
356
+
357
+ listener_class: Type[ActorListener] = ActorListener
358
+
359
+ def __init__(self, **kwargs):
360
+ QObject.__init__(self)
361
+ ParameterManager.__init__(self, action_list=('save', 'update'))
362
+ ControlModule.__init__(self)
363
+
364
+ def value_changed(self, param: Parameter) -> Optional[Parameter]:
365
+ """ParameterManager subclassed method. Process events from value changed by user in the UI Settings
366
+
367
+ Parameters
368
+ ----------
369
+ param: Parameter
370
+ a given parameter whose value has been changed by user
371
+ """
372
+ if param.name() == 'plugin_config':
373
+ self.show_config(self.plugin_config)
374
+
375
+ elif param.name() == 'connect_server':
376
+ if param.value():
377
+ self.connect_tcp_ip()
378
+ else:
379
+ self._command_tcpip.emit(ThreadCommand('quit', ))
380
+
381
+ elif param.name() == 'ip_address' or param.name == 'port':
382
+ self._command_tcpip.emit(
383
+ ThreadCommand('update_connection',
384
+ dict(ipaddress=self.settings['main_settings', 'tcpip', 'ip_address'],
385
+ port=self.settings['main_settings', 'tcpip', 'port'])))
386
+
387
+ elif param.name() == 'connect_leco_server':
388
+ self.connect_leco(param.value())
389
+
390
+ elif param.name() == "name":
391
+ name = param.value()
392
+ try:
393
+ self._leco_client.name = name
394
+ except AttributeError:
395
+ pass
396
+
397
+ else:
398
+ # not handled
399
+ return param
400
+
401
+ def _update_settings(self, param: Parameter):
402
+ # I do not understand what it does
403
+ path = self.settings.childPath(param)
404
+ if path is not None:
405
+ if 'main_settings' not in path:
406
+ self._update_settings_signal.emit(edict(path=path, param=param, change='value'))
407
+ if self.settings.child('main_settings', 'tcpip', 'tcp_connected').value():
408
+ self._command_tcpip.emit(ThreadCommand('send_info', dict(path=path, param=param)))
409
+ if self.settings.child('main_settings', 'leco', 'leco_connected').value():
410
+ self._command_tcpip.emit(ThreadCommand('send_info', dict(path=path, param=param)))
411
+
412
+ def connect_tcp_ip(self, params_state=None, client_type: str = "GRABBER") -> None:
413
+ """Init a TCPClient in a separated thread to communicate with a distant TCp/IP Server
414
+
415
+ Use the settings: ip_address and port to specify the connection
416
+
417
+ See Also
418
+ --------
419
+ TCPServer
420
+ """
421
+ if self.settings.child('main_settings', 'tcpip', 'connect_server').value():
422
+ self._tcpclient_thread = QThread()
423
+
424
+ tcpclient = TCPClient(self.settings.child('main_settings', 'tcpip', 'ip_address').value(),
425
+ self.settings.child('main_settings', 'tcpip', 'port').value(),
426
+ params_state=params_state,
427
+ client_type=client_type)
428
+ tcpclient.moveToThread(self._tcpclient_thread)
429
+ self._tcpclient_thread.tcpclient = tcpclient
430
+ tcpclient.cmd_signal.connect(self.process_tcpip_cmds)
431
+
432
+ self._command_tcpip[ThreadCommand].connect(tcpclient.queue_command)
433
+ self._tcpclient_thread.started.connect(tcpclient.init_connection)
434
+
435
+ self._tcpclient_thread.start()
436
+
437
+ def get_leco_name(self) -> str:
438
+ name = self.settings["main_settings", "leco", "leco_name"]
439
+ if name == '':
440
+ # take the module name as alternative
441
+ name = self.settings["main_settings", "module_name"]
442
+ if name == '':
443
+ # a name is required, invent one
444
+ name = f"viewer_{randint(0, 10000)}"
445
+ name = self.settings.child("main_settings", "leco", "leco_name").setValue(name)
446
+ return name
447
+
448
+ def connect_leco(self, connect: bool) -> None:
449
+ if connect:
450
+ name = self.get_leco_name()
451
+ try:
452
+ self._leco_client.name = name
453
+ except AttributeError:
454
+ self._leco_client = self.listener_class(name=name)
455
+ self._leco_client.cmd_signal.connect(self.process_tcpip_cmds)
456
+ self._command_tcpip[ThreadCommand].connect(self._leco_client.queue_command)
457
+ self._leco_client.start_listen()
458
+ # self._leco_client.cmd_signal.emit(ThreadCommand("set_info", attribute=["detector_settings", ""]))
459
+ else:
460
+ self._command_tcpip.emit(ThreadCommand(LECOCommands.QUIT, ))
461
+ try:
462
+ self._command_tcpip[ThreadCommand].disconnect(self._leco_client.queue_command)
463
+ except TypeError:
464
+ pass # already disconnected
465
+
466
+ @Slot(ThreadCommand)
467
+ def process_tcpip_cmds(self, status: ThreadCommand) -> Optional[ThreadCommand]:
468
+ if status.command == 'connected':
469
+ self.settings.child('main_settings', 'tcpip', 'tcp_connected').setValue(True)
470
+
471
+ elif status.command == 'disconnected':
472
+ self.settings.child('main_settings', 'tcpip', 'tcp_connected').setValue(False)
473
+
474
+ elif status.command == LECOClientCommands.LECO_CONNECTED:
475
+ self.settings.child('main_settings', 'leco', 'leco_connected').setValue(True)
476
+
477
+ elif status.command == LECOClientCommands.LECO_DISCONNECTED:
478
+ self.settings.child('main_settings', 'leco', 'leco_connected').setValue(False)
479
+
480
+ elif status.command == 'Update_Status':
481
+ self.thread_status(status)
482
+
483
+ elif status.command == 'set_info':
484
+ param_dict = ioxml.XML_string_to_parameter(status.attribute[1])[0]
485
+ param_tmp = Parameter.create(**param_dict)
486
+ param = self.settings.child('move_settings', *status.attribute[0][1:])
487
+
488
+ param.restoreState(param_tmp.saveState())
489
+ else:
490
+ # not handled
491
+ return status
492
+
493
+
346
494
  class ControlModuleUI(CustomApp):
347
495
  """ Base Class for ControlModules UIs
348
496
 
@@ -57,6 +57,15 @@ params = [
57
57
  'value': config('network', 'tcp-server', 'ip')},
58
58
  {'title': 'Port:', 'name': 'port', 'type': 'int', 'value': config('network', 'tcp-server', 'port')},
59
59
  ]},
60
+ {'title': 'LECO options:', 'name': 'leco', 'type': 'group', 'visible': True, 'expanded': False,
61
+ 'children': [
62
+ {'title': 'Connect:', 'name': 'connect_leco_server', 'type': 'bool_push', 'label': 'Connect',
63
+ 'value': False},
64
+ {'title': 'Connected?:', 'name': 'leco_connected', 'type': 'led', 'value': False},
65
+ {'title': 'Name', 'name': 'leco_name', 'type': 'str', 'value': "", 'default': ""},
66
+ {'title': 'Host:', 'name': 'host', 'type': 'str', 'value': config('network', "leco-server", "host"), "default": "localhost"},
67
+ {'title': 'Port:', 'name': 'port', 'type': 'int', 'value': config('network', 'leco-server', 'port')},
68
+ ]},
60
69
  {'title': 'Overshoot options:', 'name': 'overshoot', 'type': 'group', 'visible': True, 'expanded': False,
61
70
  'children': [
62
71
  {'title': 'Overshoot:', 'name': 'stop_overshoot', 'type': 'bool', 'value': False},
@@ -129,7 +138,7 @@ class DAQ_Viewer_base(QObject):
129
138
  *params* list
130
139
  *settings* instance of pyqtgraph Parameter
131
140
  *parent* ???
132
- *status* dictionnary
141
+ *status* dictionary
133
142
  ===================== ===================================
134
143
 
135
144
  See Also
@@ -182,22 +191,25 @@ class DAQ_Viewer_base(QObject):
182
191
 
183
192
  self.ini_attributes()
184
193
 
185
- self.data_grabed_signal.connect(self._emit_dte)
186
- self.data_grabed_signal_temp.connect(self._emit_dte_temp)
194
+ try:
195
+ self.data_grabed_signal.connect(self._emit_dte)
196
+ self.data_grabed_signal_temp.connect(self._emit_dte_temp)
197
+ except Exception as exc:
198
+ print(f"Error with old message signal stuff: {exc}")
187
199
 
188
200
  def _emit_dte(self, dte: Union[DataToExport, list]):
189
201
  if isinstance(dte, list):
190
- deprecation_msg(f'Data emitted from the instrument plugins should be a DataToExport instance'
191
- f'See: http://pymodaq.cnrs.fr/en/latest/developer_folder/'
192
- f'instrument_plugins.html#emission-of-data')
202
+ deprecation_msg('Data emitted from the instrument plugins should be a DataToExport instance'
203
+ 'See: http://pymodaq.cnrs.fr/en/latest/developer_folder/'
204
+ 'instrument_plugins.html#emission-of-data')
193
205
  dte = DataToExport('temp', dte)
194
206
  self.dte_signal.emit(dte)
195
207
 
196
208
  def _emit_dte_temp(self, dte: Union[DataToExport, list]):
197
209
  if isinstance(dte, list):
198
- deprecation_msg(f'Data emitted from the instrument plugins should be a DataToExport instance'
199
- f'See: http://pymodaq.cnrs.fr/en/latest/developer_folder/'
200
- f'instrument_plugins.html#emission-of-data')
210
+ deprecation_msg('Data emitted from the instrument plugins should be a DataToExport instance'
211
+ 'See: http://pymodaq.cnrs.fr/en/latest/developer_folder/'
212
+ 'instrument_plugins.html#emission-of-data')
201
213
  dte = DataToExport('temp', dte)
202
214
  self.dte_signal_temp.emit(dte)
203
215
 
@@ -210,7 +222,7 @@ class DAQ_Viewer_base(QObject):
210
222
  def ini_detector_init(self, old_controller=None, new_controller=None):
211
223
  """Manage the Master/Slave controller issue
212
224
 
213
- First initialize the status dictionnary
225
+ First initialize the status dictionary
214
226
  Then check whether this stage is controlled by a multiaxe controller (to be defined for each plugin)
215
227
  if it is a multiaxes controller then:
216
228
  * if it is Master: init the controller here
@@ -241,28 +253,28 @@ class DAQ_Viewer_base(QObject):
241
253
  Mandatory
242
254
  To be reimplemented in subclass
243
255
  """
244
- raise NotImplemented
256
+ raise NotImplementedError
245
257
 
246
258
  def close(self):
247
259
  """
248
260
  Mandatory
249
261
  To be reimplemented in subclass
250
262
  """
251
- raise NotImplemented
263
+ raise NotImplementedError
252
264
 
253
265
  def grab_data(self, Naverage=1, **kwargs):
254
266
  """
255
267
  Mandatory
256
268
  To be reimplemented in subclass
257
269
  """
258
- raise NotImplemented
270
+ raise NotImplementedError
259
271
 
260
272
  def stop(self):
261
273
  """
262
274
  Mandatory
263
275
  To be reimplemented in subclass
264
276
  """
265
- raise NotImplemented
277
+ raise NotImplementedError
266
278
 
267
279
  def commit_settings(self, param):
268
280
  """
@@ -296,7 +308,7 @@ class DAQ_Viewer_base(QObject):
296
308
  print(status)
297
309
 
298
310
  def update_scanner(self, scan_parameters):
299
- #todo check this because ScanParameters has been removed
311
+ # todo check this because ScanParameters has been removed
300
312
  self.scan_parameters = scan_parameters
301
313
 
302
314
  @Slot(edict)
@@ -307,7 +319,7 @@ class DAQ_Viewer_base(QObject):
307
319
 
308
320
  ========================== ============= =====================================================
309
321
  **Parameters** **Type** **Description**
310
- *settings_parameter_dict* dictionnnary a dictionnary listing path and associated parameter
322
+ *settings_parameter_dict* dictionnnary a dictionary listing path and associated parameter
311
323
  ========================== ============= =====================================================
312
324
 
313
325
  See Also
@@ -378,7 +390,6 @@ class DAQ_Viewer_base(QObject):
378
390
  pass
379
391
 
380
392
 
381
-
382
393
  class DAQ_Viewer_TCP_server(DAQ_Viewer_base, TCPServer):
383
394
  """
384
395
  ================= ==============================
@@ -413,7 +424,7 @@ class DAQ_Viewer_TCP_server(DAQ_Viewer_base, TCPServer):
413
424
  grabber_type: (str) either '0D', '1D' or '2D'
414
425
  """
415
426
  self.client_type = "GRABBER"
416
- DAQ_Viewer_base.__init__(self, parent, params_state) # initialize base class with commom attribute and methods
427
+ DAQ_Viewer_base.__init__(self, parent, params_state) # initialize base class with common attribute and methods
417
428
  TCPServer.__init__(self, self.client_type)
418
429
 
419
430
  self.x_axis = None
@@ -469,7 +480,7 @@ class DAQ_Viewer_TCP_server(DAQ_Viewer_base, TCPServer):
469
480
 
470
481
  def data_ready(self, data: DataToExport):
471
482
  """
472
- Send the grabed data signal.
483
+ Send the grabbed data signal.
473
484
  """
474
485
  self.dte_signal.emit(data)
475
486
 
@@ -505,7 +516,7 @@ class DAQ_Viewer_TCP_server(DAQ_Viewer_base, TCPServer):
505
516
 
506
517
  def ini_detector(self, controller=None):
507
518
  """
508
- | Initialisation procedure of the detector updating the status dictionnary.
519
+ | Initialisation procedure of the detector updating the status dictionary.
509
520
  |
510
521
  | Init axes from image , here returns only None values (to tricky to di it with the server and not really
511
522
  necessary for images anyway)
pymodaq/dashboard.py CHANGED
@@ -16,6 +16,7 @@ import numpy as np
16
16
  from pymodaq.utils.logger import set_logger, get_module_name
17
17
  from pymodaq.utils.gui_utils import DockArea, Dock, select_file
18
18
  import pymodaq.utils.gui_utils.layout as layout_mod
19
+ from pymodaq.utils.gui_utils.utils import start_qapplication
19
20
  from pymodaq.utils.messenger import messagebox
20
21
  from pymodaq.utils.parameter import utils as putils
21
22
  from pymodaq.utils import daq_utils as utils
@@ -28,7 +29,7 @@ from pymodaq.utils.managers.roi_manager import ROISaver
28
29
  from pymodaq.utils.exceptions import DetectorError, ActuatorError, PIDError, MasterSlaveError
29
30
  from pymodaq.utils import config as configmod
30
31
  from pymodaq.utils.parameter import ParameterTree, Parameter
31
-
32
+ from pymodaq.utils.leco.utils import start_coordinator
32
33
  from pymodaq.control_modules.daq_move import DAQ_Move
33
34
  from pymodaq.control_modules.daq_viewer import DAQ_Viewer
34
35
 
@@ -214,6 +215,19 @@ class DashBoard(QObject):
214
215
 
215
216
  return qtconsole
216
217
 
218
+ def load_bayesian(self, win=None):
219
+ if win is None:
220
+ self.bayesian_window = QtWidgets.QMainWindow()
221
+ else:
222
+ self.bayesian_window = win
223
+ dockarea = DockArea()
224
+ self.bayesian_window.setCentralWidget(dockarea)
225
+ self.bayesian_window.setWindowTitle('Bayesian Optimiser')
226
+ self.bayesian_module = extmod.BayesianOptimisation(dockarea=dockarea, dashboard=self)
227
+ self.extensions['bayesian'] = self.bayesian_module
228
+ self.bayesian_window.show()
229
+ return self.bayesian_module
230
+
217
231
  def load_extension_from_name(self, name: str) -> dict:
218
232
  self.load_extensions_module(find_dict_in_list_from_key_val(extensions, 'name', name))
219
233
 
@@ -262,6 +276,8 @@ class DashBoard(QObject):
262
276
  restart_action.triggered.connect(self.restart_fun)
263
277
 
264
278
  self.settings_menu = menubar.addMenu('Settings')
279
+ action_leco = self.settings_menu.addAction('Run Leco Coordinator')
280
+ action_leco.triggered.connect(start_coordinator)
265
281
  docked_menu = self.settings_menu.addMenu('Docked windows')
266
282
  action_load = docked_menu.addAction('Load Layout')
267
283
  action_save = docked_menu.addAction('Save Layout')
@@ -348,6 +364,8 @@ class DashBoard(QObject):
348
364
  action_pid.triggered.connect(lambda: self.load_pid_module())
349
365
  action_console = self.actions_menu.addAction('IPython Console')
350
366
  action_console.triggered.connect(lambda: self.load_console())
367
+ action_bayesian = self.actions_menu.addAction('Bayesian Optimisation')
368
+ action_bayesian.triggered.connect(lambda: self.load_bayesian())
351
369
 
352
370
  extensions_actions = []
353
371
  for ext in extensions:
@@ -501,6 +519,9 @@ class DashBoard(QObject):
501
519
  try:
502
520
  self.remote_timer.stop()
503
521
 
522
+ for ext in self.extensions:
523
+ if hasattr(self.extensions[ext], 'quit_fun'):
524
+ self.extensions[ext].quit_fun()
504
525
  for mov in self.actuators_modules:
505
526
  mov.init_signal.disconnect(self.update_init_tree)
506
527
  for det in self.detector_modules:
@@ -1395,10 +1416,7 @@ class DashBoard(QObject):
1395
1416
 
1396
1417
  def main(init_qt=True):
1397
1418
  if init_qt: # used for the test suite
1398
- app = QtWidgets.QApplication(sys.argv)
1399
- if config('style', 'darkstyle'):
1400
- import qdarkstyle
1401
- app.setStyleSheet(qdarkstyle.load_stylesheet(qdarkstyle.DarkPalette))
1419
+ app = start_qapplication()
1402
1420
 
1403
1421
  win = QtWidgets.QMainWindow()
1404
1422
  area = DockArea()
@@ -0,0 +1,97 @@
1
+ """
2
+ Minimal example of a TCP client connecting to a TCP server instrument class plugin (type 0D) and
3
+ sending to it 0D data in a row representing a sinus.
4
+
5
+ To execute all this:
6
+
7
+ * start a Daq_Viewer from the console, select DAQ0D and TCP_Server, set the IP to localhost, then init
8
+ * execute this script
9
+
10
+ You should see the TCP server printing the sinus in its 0D data viewer
11
+
12
+ """
13
+
14
+
15
+ import numpy as np
16
+
17
+ from pymodaq.utils.tcp_ip.tcp_server_client import TCPClientTemplate
18
+ from pymodaq.utils.data import DataToExport, DataRaw
19
+
20
+
21
+ class TCPClient(TCPClientTemplate):
22
+ def __init__(self):
23
+ super().__init__(ipaddress="localhost", port=6341, client_type="GRABBER")
24
+
25
+ def post_init(self, extra_commands=[]):
26
+ self.socket.check_sended_with_serializer(self.client_type)
27
+
28
+ def send_data(self, data: DataToExport):
29
+ # first send 'Done' and then send the length of the list
30
+ if not isinstance(data, DataToExport):
31
+ raise TypeError(f'should send a DataToExport object')
32
+ if self.socket is not None:
33
+ self.socket.check_sended_with_serializer('Done')
34
+ self.socket.check_sended_with_serializer(data)
35
+
36
+ def ready_to_read(self):
37
+ message = self._deserializer.string_deserialization()
38
+ self.get_data(message)
39
+
40
+ def get_data(self, message: str):
41
+ """
42
+
43
+ Parameters
44
+ ----------
45
+ message
46
+
47
+ Returns
48
+ -------
49
+
50
+ """
51
+ if self.socket is not None:
52
+
53
+ if message == 'set_info':
54
+ path = self._deserializer.list_deserialization()
55
+ param_xml = self._deserializer.string_deserialization()
56
+ print(param_xml)
57
+
58
+ elif message == 'move_abs' or message == 'move_rel':
59
+ position = self._deserializer.dwa_deserialization()
60
+ print(f'Position is {position}')
61
+
62
+ else:
63
+ print(message)
64
+
65
+ def data_ready(self, data: DataToExport):
66
+ self.send_data(data)
67
+
68
+ def ready_to_write(self):
69
+ pass
70
+
71
+ def ready_with_error(self):
72
+ self.connected = False
73
+
74
+ def process_error_in_polling(self, e: Exception):
75
+ print(e)
76
+
77
+
78
+
79
+ if __name__ == '__main__':
80
+ from threading import Thread
81
+ from time import sleep
82
+
83
+ tcpclient = TCPClient()
84
+ t = Thread(target=tcpclient.init_connection)
85
+
86
+ t.start()
87
+ sleep(1)
88
+ sinus = np.sin(np.linspace(0, 2 * np.pi, 10))
89
+
90
+ for ind in range(10):
91
+ dwa = DataRaw('mydata', data=[np.array([sinus[ind]])], plot=True)
92
+ tcpclient.data_ready(dwa.as_dte())
93
+
94
+ tcpclient.close()
95
+
96
+
97
+
@@ -13,4 +13,8 @@ from .daq_logger import DAQ_Logger
13
13
  from .pid.pid_controller import DAQ_PID
14
14
  from .h5browser import H5Browser
15
15
 
16
+ from .bayesian.bayesian_optimisation import BayesianOptimisation
17
+ from .bayesian.utils import BayesianModelDefault, BayesianModelGeneric
18
+
19
+
16
20
 
@@ -0,0 +1,2 @@
1
+ from . import bayesian_optimisation
2
+ from . import utils