pymodaq 5.0.17__py3-none-any.whl → 5.1.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 (92) hide show
  1. pymodaq/__init__.py +23 -11
  2. pymodaq/control_modules/__init__.py +1 -0
  3. pymodaq/control_modules/daq_move.py +458 -246
  4. pymodaq/control_modules/daq_move_ui/__init__.py +0 -0
  5. pymodaq/control_modules/daq_move_ui/factory.py +48 -0
  6. pymodaq/control_modules/{daq_move_ui.py → daq_move_ui/ui_base.py} +168 -210
  7. pymodaq/control_modules/daq_move_ui/uis/__init__.py +0 -0
  8. pymodaq/control_modules/daq_move_ui/uis/binary.py +139 -0
  9. pymodaq/control_modules/daq_move_ui/uis/original.py +120 -0
  10. pymodaq/control_modules/daq_move_ui/uis/relative.py +124 -0
  11. pymodaq/control_modules/daq_move_ui/uis/simple.py +126 -0
  12. pymodaq/control_modules/daq_viewer.py +113 -101
  13. pymodaq/control_modules/daq_viewer_ui.py +41 -31
  14. pymodaq/control_modules/mocks.py +2 -2
  15. pymodaq/control_modules/move_utility_classes.py +113 -41
  16. pymodaq/control_modules/thread_commands.py +137 -0
  17. pymodaq/control_modules/ui_utils.py +72 -0
  18. pymodaq/control_modules/utils.py +107 -63
  19. pymodaq/control_modules/viewer_utility_classes.py +13 -17
  20. pymodaq/dashboard.py +1294 -625
  21. pymodaq/examples/qt_less_standalone_module.py +48 -11
  22. pymodaq/extensions/__init__.py +8 -3
  23. pymodaq/extensions/adaptive/__init__.py +2 -0
  24. pymodaq/extensions/adaptive/adaptive_optimization.py +179 -0
  25. pymodaq/extensions/adaptive/loss_function/_1d_loss_functions.py +73 -0
  26. pymodaq/extensions/adaptive/loss_function/_2d_loss_functions.py +73 -0
  27. pymodaq/extensions/adaptive/loss_function/__init__.py +3 -0
  28. pymodaq/extensions/adaptive/loss_function/loss_factory.py +110 -0
  29. pymodaq/extensions/adaptive/utils.py +123 -0
  30. pymodaq/extensions/bayesian/__init__.py +1 -1
  31. pymodaq/extensions/bayesian/acquisition/__init__.py +2 -0
  32. pymodaq/extensions/bayesian/acquisition/acquisition_function_factory.py +80 -0
  33. pymodaq/extensions/bayesian/acquisition/base_acquisition_function.py +105 -0
  34. pymodaq/extensions/bayesian/bayesian_optimization.py +143 -0
  35. pymodaq/extensions/bayesian/utils.py +71 -297
  36. pymodaq/extensions/daq_logger/daq_logger.py +7 -12
  37. pymodaq/extensions/daq_logger/h5logging.py +1 -1
  38. pymodaq/extensions/daq_scan.py +30 -55
  39. pymodaq/extensions/data_mixer/__init__.py +0 -0
  40. pymodaq/extensions/data_mixer/daq_0Dviewer_DataMixer.py +97 -0
  41. pymodaq/extensions/data_mixer/data_mixer.py +262 -0
  42. pymodaq/extensions/data_mixer/model.py +108 -0
  43. pymodaq/extensions/data_mixer/models/__init__.py +0 -0
  44. pymodaq/extensions/data_mixer/models/equation_model.py +91 -0
  45. pymodaq/extensions/data_mixer/models/gaussian_fit_model.py +65 -0
  46. pymodaq/extensions/data_mixer/parser.py +53 -0
  47. pymodaq/extensions/data_mixer/utils.py +23 -0
  48. pymodaq/extensions/h5browser.py +3 -34
  49. pymodaq/extensions/optimizers_base/__init__.py +0 -0
  50. pymodaq/extensions/optimizers_base/optimizer.py +1016 -0
  51. pymodaq/extensions/optimizers_base/thread_commands.py +22 -0
  52. pymodaq/extensions/optimizers_base/utils.py +427 -0
  53. pymodaq/extensions/pid/actuator_controller.py +3 -2
  54. pymodaq/extensions/pid/daq_move_PID.py +107 -30
  55. pymodaq/extensions/pid/pid_controller.py +613 -287
  56. pymodaq/extensions/pid/utils.py +8 -5
  57. pymodaq/extensions/utils.py +17 -2
  58. pymodaq/resources/config_template.toml +57 -0
  59. pymodaq/resources/preset_default.xml +1 -1
  60. pymodaq/utils/config.py +13 -4
  61. pymodaq/utils/daq_utils.py +14 -0
  62. pymodaq/utils/data.py +1 -0
  63. pymodaq/utils/gui_utils/loader_utils.py +25 -15
  64. pymodaq/utils/h5modules/module_saving.py +134 -22
  65. pymodaq/utils/leco/daq_move_LECODirector.py +123 -84
  66. pymodaq/utils/leco/daq_xDviewer_LECODirector.py +84 -97
  67. pymodaq/utils/leco/director_utils.py +32 -16
  68. pymodaq/utils/leco/leco_director.py +104 -27
  69. pymodaq/utils/leco/pymodaq_listener.py +186 -97
  70. pymodaq/utils/leco/rpc_method_definitions.py +43 -0
  71. pymodaq/utils/leco/utils.py +25 -25
  72. pymodaq/utils/managers/batchscan_manager.py +12 -11
  73. pymodaq/utils/managers/modules_manager.py +74 -33
  74. pymodaq/utils/managers/overshoot_manager.py +11 -10
  75. pymodaq/utils/managers/preset_manager.py +100 -64
  76. pymodaq/utils/managers/preset_manager_utils.py +163 -107
  77. pymodaq/utils/managers/remote_manager.py +21 -16
  78. pymodaq/utils/scanner/scan_factory.py +18 -4
  79. pymodaq/utils/scanner/scan_selector.py +1 -3
  80. pymodaq/utils/scanner/scanner.py +35 -6
  81. pymodaq/utils/scanner/scanners/_1d_scanners.py +15 -46
  82. pymodaq/utils/scanner/scanners/_2d_scanners.py +21 -68
  83. pymodaq/utils/scanner/scanners/sequential.py +50 -31
  84. pymodaq/utils/scanner/scanners/tabular.py +45 -28
  85. {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/METADATA +7 -6
  86. pymodaq-5.1.0.dist-info/RECORD +154 -0
  87. {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/entry_points.txt +0 -2
  88. pymodaq/extensions/bayesian/bayesian_optimisation.py +0 -685
  89. pymodaq/utils/leco/desktop.ini +0 -2
  90. pymodaq-5.0.17.dist-info/RECORD +0 -121
  91. {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/WHEEL +0 -0
  92. {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/licenses/LICENSE +0 -0
@@ -7,12 +7,8 @@ Created on Wed Jan 10 16:54:14 2018
7
7
  from __future__ import annotations
8
8
  from importlib import import_module
9
9
 
10
- from collections import OrderedDict
11
- import copy
12
-
13
10
  import os
14
11
  from pathlib import Path
15
- from random import randint
16
12
  import sys
17
13
  from typing import List, Tuple, Union, Optional
18
14
  import time
@@ -49,16 +45,22 @@ from pymodaq_gui.utils.utils import mkQApp
49
45
 
50
46
  from pymodaq.utils.gui_utils import get_splash_sc
51
47
  from pymodaq.control_modules.daq_viewer_ui import DAQ_Viewer_UI
52
- from pymodaq.control_modules.utils import DET_TYPES, get_viewer_plugins, DAQTypesEnum, DetectorError
48
+ from pymodaq.control_modules.utils import (DET_TYPES, get_viewer_plugins, DAQTypesEnum,
49
+ DetectorError)
50
+ from pymodaq.control_modules.thread_commands import (ThreadStatus, ThreadStatusViewer, ControlToHardwareViewer,
51
+ UiToMainViewer)
53
52
  from pymodaq_gui.plotting.data_viewers.viewer import ViewerBase
54
53
  from pymodaq_gui.plotting.data_viewers import ViewersEnum
55
54
  from pymodaq_utils.enums import enum_checker
56
55
  from pymodaq.control_modules.viewer_utility_classes import DAQ_Viewer_base
57
56
 
58
- from pymodaq.utils.leco.pymodaq_listener import ViewerActorListener, LECOClientCommands
57
+ from pymodaq.utils.leco.pymodaq_listener import ViewerActorListener, LECOClientCommands, LECOViewerCommands
58
+ from pymodaq.utils.config import Config as ControlModulesConfig
59
+
59
60
 
60
61
  logger = set_logger(get_module_name(__file__))
61
- config = Config()
62
+ config_utils = Config()
63
+ config = ControlModulesConfig()
62
64
 
63
65
  local_path = get_set_local_dir()
64
66
 
@@ -104,11 +106,17 @@ class DAQ_Viewer(ParameterControlModule):
104
106
  params = daq_viewer_params
105
107
 
106
108
  listener_class = ViewerActorListener
107
-
108
- def __init__(self, parent: DockArea=None, title="Testing",
109
- daq_type=config('viewer', 'daq_type'),
110
- dock_settings=None, dock_viewer=None,
111
- **kwargs):
109
+ ui: Optional[DAQ_Viewer_UI]
110
+
111
+ def __init__(
112
+ self,
113
+ parent: Optional[DockArea] = None,
114
+ title: str = "Testing",
115
+ daq_type=config("viewer", "daq_type"),
116
+ dock_settings=None,
117
+ dock_viewer=None,
118
+ **kwargs,
119
+ ):
112
120
 
113
121
  self.logger = set_logger(f'{logger.name}.{title}')
114
122
  self.logger.info(f'Initializing DAQ_Viewer: {title}')
@@ -121,6 +129,9 @@ class DAQ_Viewer(ParameterControlModule):
121
129
  self._viewer_types: List[ViewersEnum] = []
122
130
  self._viewers: List[ViewerBase] = []
123
131
 
132
+ self.override_grab_from_extension = False # boolean allowing an extension to tell to init a grab or not
133
+ # (see DataMixer for reasons and use case in ModulesManager and dashboard method add_det_from_extension)
134
+
124
135
  if isinstance(parent, DockArea):
125
136
  self.dockarea = parent
126
137
  else:
@@ -128,11 +139,11 @@ class DAQ_Viewer(ParameterControlModule):
128
139
 
129
140
  self.parent = parent
130
141
  if parent is not None:
131
- self.ui: DAQ_Viewer_UI = DAQ_Viewer_UI(parent, title, daq_type=daq_type,
142
+ self.ui = DAQ_Viewer_UI(parent, title, daq_type=daq_type,
132
143
  dock_settings=dock_settings,
133
144
  dock_viewer=dock_viewer)
134
145
  else:
135
- self.ui: Optional[DAQ_Viewer_UI] = None
146
+ self.ui = None
136
147
 
137
148
  if self.ui is not None:
138
149
  QtWidgets.QApplication.processEvents()
@@ -145,9 +156,9 @@ class DAQ_Viewer(ParameterControlModule):
145
156
 
146
157
  self._title = title
147
158
 
148
- self.module_and_data_saver: Union[None,
159
+ self._module_and_data_saver: Union[None,
149
160
  module_saving.DetectorSaver,
150
- module_saving.DetectorEnlargeableSaver,
161
+ module_saving.DetectorTimeSaver,
151
162
  module_saving.DetectorExtendedSaver] = None
152
163
  self._h5saver_continuous: Optional[H5Saver] = None
153
164
  self._ind_continuous_grab = 0
@@ -200,6 +211,8 @@ class DAQ_Viewer(ParameterControlModule):
200
211
  def process_ui_cmds(self, cmd: utils.ThreadCommand):
201
212
  """Process commands sent by actions done in the ui
202
213
 
214
+ See pymodaq.control_modules.thread_commands.UiToMainViewer
215
+
203
216
  Parameters
204
217
  ----------
205
218
  cmd: ThreadCommand
@@ -220,38 +233,38 @@ class DAQ_Viewer(ParameterControlModule):
220
233
  * show_config
221
234
  """
222
235
 
223
- if cmd.command == 'init':
236
+ if cmd.command == UiToMainViewer.INIT:
224
237
  self.init_hardware(cmd.attribute[0])
225
- elif cmd.command == 'quit':
238
+ elif cmd.command == UiToMainViewer.QUIT:
226
239
  self.quit_fun()
227
- elif cmd.command == 'stop':
240
+ elif cmd.command == UiToMainViewer.STOP:
228
241
  self.stop()
229
- elif cmd.command == 'show_log':
242
+ elif cmd.command == UiToMainViewer.SHOW_LOG:
230
243
  self.show_log()
231
- elif cmd.command == 'grab':
244
+ elif cmd.command == UiToMainViewer.GRAB:
232
245
  self.grab_data(cmd.attribute, snap_state=False)
233
- elif cmd.command == 'snap':
246
+ elif cmd.command == UiToMainViewer.SNAP:
234
247
  self.grab_data(False, snap_state=True)
235
- elif cmd.command == 'save_new':
248
+ elif cmd.command == UiToMainViewer.SAVE_NEW:
236
249
  self.save_new()
237
- elif cmd.command == 'save_current':
250
+ elif cmd.command == UiToMainViewer.SAVE_CURRENT:
238
251
  self.save_current()
239
- elif cmd.command == 'open':
252
+ elif cmd.command == UiToMainViewer.OPEN:
240
253
  self.load_data()
241
- elif cmd.command == 'detector_changed':
254
+ elif cmd.command == UiToMainViewer.DETECTOR_CHANGED:
242
255
  if cmd.attribute != '':
243
256
  self.detector_changed_from_ui(cmd.attribute)
244
- elif cmd.command == 'daq_type_changed':
257
+ elif cmd.command == UiToMainViewer.DAQ_TYPE_CHANGED:
245
258
  if cmd.attribute != '':
246
259
  self.daq_type_changed_from_ui(cmd.attribute)
247
- elif cmd.command == 'take_bkg':
260
+ elif cmd.command == UiToMainViewer.TAKE_BKG:
248
261
  self.take_bkg()
249
- elif cmd.command == 'do_bkg':
262
+ elif cmd.command == UiToMainViewer.DO_BKG:
250
263
  self.do_bkg = cmd.attribute
251
- elif cmd.command == 'viewers_changed':
264
+ elif cmd.command == UiToMainViewer.VIEWERS_CHANGED:
252
265
  self._viewer_types: List[ViewersEnum] = cmd.attribute['viewer_types']
253
266
  self.viewers = cmd.attribute['viewers']
254
- elif cmd.command == 'show_config':
267
+ elif cmd.command == UiToMainViewer.SHOW_CONFIG:
255
268
  self.config = self.show_config(self.config)
256
269
  self.ui.config = self.config
257
270
 
@@ -401,18 +414,17 @@ class DAQ_Viewer(ParameterControlModule):
401
414
  pass
402
415
  for ind_viewer, viewer in enumerate(viewers):
403
416
  viewer.data_to_export_signal.connect(self._get_data_from_viewer)
404
- #deprecated:
405
- viewer.ROI_select_signal.connect(
406
- lambda roi_info: self.command_hardware.emit(ThreadCommand('ROISelect', roi_info)))
407
- #use that now
417
+
408
418
  viewer.roi_select_signal.connect(
409
419
  lambda roi_info: self.command_hardware.emit(
410
- ThreadCommand('roi_select',
411
- dict(roi_info=roi_info, ind_viewer=ind_viewer))))
420
+ ThreadCommand(ControlToHardwareViewer.ROI_SELECT,
421
+ dict(roi_info=roi_info,
422
+ ind_viewer=ind_viewer))))
412
423
  viewer.crosshair_dragged.connect(
413
424
  lambda crosshair_info: self.command_hardware.emit(
414
- ThreadCommand('crosshair',
415
- dict(crosshair_info=crosshair_info, ind_viewer=ind_viewer))))
425
+ ThreadCommand(ControlToHardwareViewer.CROSSHAIR,
426
+ dict(crosshair_info=crosshair_info,
427
+ ind_viewer=ind_viewer))))
416
428
 
417
429
 
418
430
  self._viewers = viewers
@@ -457,7 +469,7 @@ class DAQ_Viewer(ParameterControlModule):
457
469
  """
458
470
  if not do_init:
459
471
  try:
460
- self.command_hardware.emit(ThreadCommand(command="close"))
472
+ self.command_hardware.emit(ThreadCommand(ControlToHardwareViewer.CLOSE))
461
473
  QtWidgets.QApplication.processEvents()
462
474
  if self.ui is not None:
463
475
  self.ui.detector_init = False
@@ -481,8 +493,10 @@ class DAQ_Viewer(ParameterControlModule):
481
493
  self._hardware_thread.hardware = hardware
482
494
  if self.config('viewer', 'viewer_in_thread'):
483
495
  self._hardware_thread.start()
484
- self.command_hardware.emit(ThreadCommand("ini_detector", attribute=[
485
- self.settings.child('detector_settings').saveState(), self.controller]))
496
+ self.command_hardware.emit(ThreadCommand(ControlToHardwareViewer.INI_DETECTOR,
497
+ attribute=[
498
+ self.settings.child('detector_settings').saveState(),
499
+ self.controller]))
486
500
  if self.ui is not None:
487
501
  for dock in self.ui.viewer_docks:
488
502
  dock.setEnabled(True)
@@ -490,15 +504,15 @@ class DAQ_Viewer(ParameterControlModule):
490
504
  except Exception as e:
491
505
  self.logger.exception(str(e))
492
506
 
493
- def snap(self):
507
+ def snap(self, send_to_tcpip=False):
494
508
  """ Launch a single grab """
495
- self.grab_data(False, snap_state=True)
509
+ self.grab_data(False, snap_state=True, send_to_tcpip=send_to_tcpip)
496
510
 
497
- def grab(self):
511
+ def grab(self, send_to_tcpip=False):
498
512
  """ Launch a continuous grab """
499
513
  if self.ui is not None:
500
514
  self.manage_ui_actions('grab', 'setChecked', not self._grabing)
501
- self.grab_data(not self._grabing, snap_state=False)
515
+ self.grab_data(not self._grabing, snap_state=False, send_to_tcpip=send_to_tcpip)
502
516
 
503
517
  def snapshot(self, pathname=None, dosave=False, send_to_tcpip=False):
504
518
  """Do one single grab (snap) and eventually save the data.
@@ -545,16 +559,18 @@ class DAQ_Viewer(ParameterControlModule):
545
559
  if snap_state:
546
560
  self.update_status(f'{self._title}: Snap')
547
561
  self.command_hardware.emit(
548
- ThreadCommand("single", dict(Naverage=self.settings['main_settings', 'Naverage'])))
562
+ ThreadCommand(ControlToHardwareViewer.SINGLE,
563
+ dict(Naverage=self.settings['main_settings', 'Naverage'])))
549
564
  else:
550
565
  if not grab_state:
551
566
  self.update_status(f'{self._title}: Stop Grab')
552
- self.command_hardware.emit(ThreadCommand("stop_grab", ))
567
+ self.command_hardware.emit(ThreadCommand(ControlToHardwareViewer.STOP_GRAB, ))
553
568
  else:
554
- self.thread_status(ThreadCommand("update_channels", ))
569
+ self.thread_status(ThreadCommand(ThreadStatusViewer.UPDATE_CHANNELS, ))
555
570
  self.update_status(f'{self._title}: Continuous Grab')
556
571
  self.command_hardware.emit(
557
- ThreadCommand("grab", dict(Naverage=self.settings['main_settings', 'Naverage'])))
572
+ ThreadCommand(ControlToHardwareViewer.GRAB,
573
+ dict(Naverage=self.settings['main_settings', 'Naverage'])))
558
574
 
559
575
  def take_bkg(self):
560
576
  """ Do a snap and store data to be used as background into an attribute: `self._bkg`
@@ -578,14 +594,14 @@ class DAQ_Viewer(ParameterControlModule):
578
594
  def stop(self):
579
595
  """ Stop the current continuous grabbing """
580
596
  self.update_status(f'{self._title}: Stop Grab')
581
- self.command_hardware.emit(ThreadCommand("stop_all", ))
597
+ self.command_hardware.emit(ThreadCommand(ControlToHardwareViewer.STOP_GRAB, ))
582
598
  self._grabing = False
583
599
 
584
600
  @Slot()
585
601
  def _raise_timeout(self):
586
602
  """ Print the "timeout occurred" error message in the status bar via the update_status method.
587
603
  """
588
- self.update_status("Timeout occured", log_type="log")
604
+ self.update_status("Timeout occurred", log_type="log")
589
605
 
590
606
  @staticmethod
591
607
  def load_data():
@@ -612,7 +628,7 @@ class DAQ_Viewer(ParameterControlModule):
612
628
  def _init_continuous_save(self):
613
629
  """ Initialize the continuous saving H5Saver object
614
630
 
615
- Update the module_and_data_saver attribute as :class:`DetectorEnlargeableSaver` object
631
+ Update the module_and_data_saver attribute as :class:`DetectorTimeSaver` object
616
632
  """
617
633
  if self._h5saver_continuous.settings.child('do_save').value():
618
634
 
@@ -622,7 +638,7 @@ class DAQ_Viewer(ParameterControlModule):
622
638
  self.module_and_data_saver.h5saver = self._h5saver_continuous
623
639
  self._h5saver_continuous.init_file(update_h5=True)
624
640
 
625
- self.module_and_data_saver = module_saving.DetectorEnlargeableSaver(self)
641
+ self.module_and_data_saver = module_saving.DetectorTimeSaver(self)
626
642
  self.module_and_data_saver.h5saver = self._h5saver_continuous
627
643
  self.module_and_data_saver.get_set_node()
628
644
 
@@ -637,8 +653,10 @@ class DAQ_Viewer(ParameterControlModule):
637
653
  except Exception as e:
638
654
  self.logger.exception(str(e))
639
655
 
640
- def append_data(self, dte: DataToExport = None, where: Union[Node, str] = None):
641
- """Appends current DataToExport to a DetectorEnlargeableSaver
656
+ def append_data(self, dte: DataToExport = None,
657
+ where: Union[Node, str] = None,
658
+ **kwargs):
659
+ """Appends current DataToExport to a DetectorTimeSaver
642
660
 
643
661
  Method to be used when performing continuous saving into a h5file (continuous mode or DAQ_Logger)
644
662
 
@@ -647,14 +665,21 @@ class DAQ_Viewer(ParameterControlModule):
647
665
  dte: DataToExport
648
666
  not really used
649
667
  where: Node or str
668
+ kwargs: dict
650
669
  See Also
651
670
  --------
652
- :class:`DetectorEnlargeableSaver`
671
+ :class:`DetectorTimeSaver`
653
672
  """
654
673
  if dte is None:
655
674
  dte = self._data_to_save_export
656
- self._add_data_to_saver(dte, init_step=self._h5saver_continuous.settings['N_saved'] == 0,
657
- where=where)
675
+ init_step = kwargs.pop('init_step', None)
676
+ if init_step is None:
677
+ init_step = self._h5saver_continuous.settings['N_saved'] == 0
678
+ self._add_data_to_saver(dte,
679
+ init_step=init_step,
680
+ where=where,
681
+ **kwargs)
682
+
658
683
  self._h5saver_continuous.settings.child('N_saved').setValue(self._h5saver_continuous.settings['N_saved'] + 1)
659
684
 
660
685
  def insert_data(self, indexes: Tuple[int], where: Union[Node, str] = None,
@@ -693,7 +718,7 @@ class DAQ_Viewer(ParameterControlModule):
693
718
 
694
719
  See Also
695
720
  --------
696
- DetectorSaver, DetectorEnlargeableSaver, DetectorExtendedSaver
721
+ DetectorSaver, DetectorTimeSaver, DetectorExtendedSaver
697
722
 
698
723
  """
699
724
  if dte is not None:
@@ -970,7 +995,8 @@ class DAQ_Viewer(ParameterControlModule):
970
995
  self._h5saver_continuous.show_settings(param.value())
971
996
 
972
997
  elif param.name() == 'wait_time':
973
- self.command_hardware.emit(ThreadCommand('update_wait_time', [param.value()]))
998
+ self.command_hardware.emit(ThreadCommand(ControlToHardwareViewer.UPDATE_WAIT_TIME,
999
+ [param.value()]))
974
1000
 
975
1001
  self._update_settings(param=param)
976
1002
 
@@ -1047,6 +1073,7 @@ class DAQ_Viewer(ParameterControlModule):
1047
1073
  scaling=self.settings['main_settings', 'axes', 'yaxis', 'yscaling'])
1048
1074
  return scaled_xaxis, scaled_yaxis
1049
1075
 
1076
+
1050
1077
  def thread_status(self, status: ThreadCommand):
1051
1078
  """Get back info (using the ThreadCommand object) from the hardware
1052
1079
 
@@ -1068,7 +1095,7 @@ class DAQ_Viewer(ParameterControlModule):
1068
1095
  """
1069
1096
  super().thread_status(status, 'detector')
1070
1097
 
1071
- if status.command == "ini_detector":
1098
+ if status.command == ThreadStatusViewer.INI_DETECTOR:
1072
1099
  self.update_status("detector initialized: " + str(status.attribute['initialized']))
1073
1100
  if self.ui is not None:
1074
1101
  self.ui.detector_init = status.attribute['initialized']
@@ -1080,13 +1107,13 @@ class DAQ_Viewer(ParameterControlModule):
1080
1107
 
1081
1108
  self.init_signal.emit(self._initialized_state)
1082
1109
 
1083
- elif status.command == "grab":
1110
+ elif status.command == ThreadStatusViewer.GRAB:
1084
1111
  self.grab_status.emit(True)
1085
1112
 
1086
- elif status.command == 'grab_stopped':
1113
+ elif status.command == ThreadStatusViewer.GRAB_STOPPED:
1087
1114
  self.grab_status.emit(False)
1088
1115
 
1089
- elif status.command == 'init_lcd':
1116
+ elif status.command == ThreadStatusViewer.INI_LCD:
1090
1117
  if self._lcd is not None:
1091
1118
  try:
1092
1119
  self._lcd.parent.close()
@@ -1098,11 +1125,11 @@ class DAQ_Viewer(ParameterControlModule):
1098
1125
  lcd.setVisible(True)
1099
1126
  QtWidgets.QApplication.processEvents()
1100
1127
 
1101
- elif status.command == 'lcd':
1128
+ elif status.command == ThreadStatusViewer.LCD:
1102
1129
  """status.attribute should be a list of numpy arrays of shape (1,)"""
1103
1130
  self._lcd.setvalues(status.attribute)
1104
1131
 
1105
- elif status.command == 'stop':
1132
+ elif status.command == ThreadStatusViewer.STOP:
1106
1133
  self.stop_grab()
1107
1134
 
1108
1135
  def connect_tcp_ip(self):
@@ -1132,6 +1159,13 @@ class DAQ_Viewer(ParameterControlModule):
1132
1159
  return
1133
1160
  if 'Send Data' in status.command:
1134
1161
  self.snapshot('', send_to_tcpip=True)
1162
+ elif status.command == LECOViewerCommands.GRAB:
1163
+ self.grab(send_to_tcpip=True)
1164
+ elif status.command ==LECOViewerCommands.SNAP:
1165
+ self.snap( send_to_tcpip=True)
1166
+
1167
+ elif status.command == LECOViewerCommands.STOP:
1168
+ self.stop()
1135
1169
 
1136
1170
  elif status.command == LECOClientCommands.LECO_CONNECTED:
1137
1171
  self.settings.child('main_settings', 'leco', 'leco_connected').setValue(True)
@@ -1139,18 +1173,6 @@ class DAQ_Viewer(ParameterControlModule):
1139
1173
  elif status.command == LECOClientCommands.LECO_DISCONNECTED:
1140
1174
  self.settings.child('main_settings', 'leco', 'leco_connected').setValue(False)
1141
1175
 
1142
- elif status.command == 'set_info':
1143
- path_in_settings = status.attribute[0]
1144
- param_as_xml = status.attribute[1]
1145
- param_dict = ioxml.XML_string_to_parameter(param_as_xml)[0]
1146
- param_tmp = Parameter.create(**param_dict)
1147
- param = self.settings.child('detector_settings', *path_in_settings[1:])
1148
- param.restoreState(param_tmp.saveState())
1149
-
1150
- elif status.command == 'get_axis':
1151
- raise DeprecationWarning('Do not use this, the axis are in the data objects')
1152
- self.command_hardware.emit(
1153
- ThreadCommand('get_axis', )) # tells the plugin to emit its axes so that the server will receive them
1154
1176
 
1155
1177
 
1156
1178
  class DAQ_Detector(QObject):
@@ -1235,46 +1257,37 @@ class DAQ_Detector(QObject):
1235
1257
  * get_axis
1236
1258
  * any string that the hardware is able to understand
1237
1259
  """
1238
- if command.command == "ini_detector":
1260
+ if command.command == ControlToHardwareViewer.INI_DETECTOR:
1239
1261
  status = self.ini_detector(*command.attribute)
1240
- self.status_sig.emit(ThreadCommand(command.command, status))
1262
+ self.status_sig.emit(ThreadCommand(ThreadStatusViewer.INI_DETECTOR, status))
1241
1263
 
1242
- elif command.command == "close":
1264
+ elif command.command == ControlToHardwareViewer.CLOSE:
1243
1265
  status = self.close()
1244
- self.status_sig.emit(ThreadCommand(command.command, [status, 'log']))
1266
+ self.status_sig.emit(ThreadCommand(ThreadStatus.CLOSE, [status, 'log']))
1245
1267
 
1246
- elif command.command == "grab":
1268
+ elif command.command == ControlToHardwareViewer.GRAB:
1247
1269
  self.single_grab = False
1248
1270
  self.grab_state = True
1249
1271
  self.grab_data(**command.attribute)
1250
1272
 
1251
- elif command.command == "single":
1273
+ elif command.command == ControlToHardwareViewer.SINGLE:
1252
1274
  self.single_grab = True
1253
1275
  self.grab_state = True
1254
1276
  self.single(**command.attribute)
1255
1277
 
1256
- elif command.command == "stop_grab":
1257
- self.grab_state = False
1258
- self.status_sig.emit(ThreadCommand("Update_Status", ['Stoping grab']))
1259
-
1260
- elif command.command == "stop_all":
1278
+ elif command.command == ControlToHardwareViewer.STOP_GRAB:
1261
1279
  self.grab_state = False
1262
1280
  self.detector.stop()
1263
1281
  QtWidgets.QApplication.processEvents()
1264
- self.status_sig.emit(ThreadCommand("Update_Status", ['Stoping grab']))
1282
+ self.status_sig.emit(ThreadCommand(ThreadStatus.UPDATE_STATUS, 'Stopping grab'))
1265
1283
 
1266
- elif command.command == 'update_scanner':
1267
- self.detector.update_scanner(command.attribute[0])
1268
1284
 
1269
- elif command.command == 'move_at_navigator':
1270
- self.detector.move_at_navigator(*command.attribute)
1285
+ elif command.command == ControlToHardwareViewer.UPDATE_SCANNER: # may be deprecated
1286
+ self.detector.update_scanner(command.attribute[0])
1271
1287
 
1272
- elif command.command == 'update_wait_time':
1288
+ elif command.command == ControlToHardwareViewer.UPDATE_WAIT_TIME:
1273
1289
  self.wait_time = command.attribute[0]
1274
1290
 
1275
- elif command.command == 'get_axis':
1276
- self.detector.get_axis()
1277
-
1278
1291
  else: # custom commands for particular plugins
1279
1292
  if hasattr(self.detector, command.command):
1280
1293
  cmd = getattr(self.detector, command.command)
@@ -1365,8 +1378,7 @@ class DAQ_Detector(QObject):
1365
1378
  self.average_done = True # expected to make sure the single_grab stop by itself
1366
1379
  self.data_detector_sig.emit(data)
1367
1380
  self.waiting_for_data = False
1368
- if not self.grab_state:
1369
- self.detector.stop()
1381
+
1370
1382
 
1371
1383
  def single(self, Naverage=1, *args, **kwargs):
1372
1384
  """ Convenience function to grab a single set of data
@@ -13,19 +13,22 @@ from qtpy import QtWidgets
13
13
  from qtpy.QtCore import Signal
14
14
  from qtpy.QtWidgets import QVBoxLayout, QWidget, QComboBox
15
15
  from pymodaq.utils.daq_utils import ThreadCommand
16
- from pymodaq.control_modules.utils import ControlModuleUI
16
+ from pymodaq.control_modules.ui_utils import ControlModuleUI
17
17
 
18
18
  from pymodaq_gui.utils.widgets import PushButtonIcon, LabelWithFont, QLED
19
19
  from pymodaq_gui.utils import Dock
20
- from pymodaq_utils.config import Config
20
+ from pymodaq_utils.config import Config as ConfigUtils
21
21
  from pymodaq.control_modules.utils import DET_TYPES, DAQTypesEnum
22
22
  from pymodaq_gui.plotting.data_viewers.viewer import ViewerFactory, ViewerDispatcher
23
23
  from pymodaq_gui.plotting.data_viewers import ViewersEnum
24
24
  from pymodaq_utils.enums import enum_checker
25
+ from pymodaq.utils.config import Config
26
+ from pymodaq.control_modules.thread_commands import UiToMainViewer
25
27
 
26
28
 
27
29
  viewer_factory = ViewerFactory()
28
30
  config = Config()
31
+ config_utils = ConfigUtils()
29
32
 
30
33
 
31
34
  class DAQ_Viewer_UI(ControlModuleUI, ViewerDispatcher):
@@ -107,12 +110,8 @@ class DAQ_Viewer_UI(ControlModuleUI, ViewerDispatcher):
107
110
 
108
111
  @detectors.setter
109
112
  def detectors(self, detectors: List[str]):
110
- #self._detectors_combo.currentTextChanged.disconnect()
111
113
  self._detectors_combo.clear()
112
114
  self._detectors_combo.addItems(detectors)
113
- #self._detectors_combo.currentTextChanged.connect(
114
- # lambda mod: self.command_sig.emit(ThreadCommand('detector_changed', mod)))
115
- #self.detector = detectors[0]
116
115
 
117
116
  @property
118
117
  def daq_type(self):
@@ -153,13 +152,15 @@ class DAQ_Viewer_UI(ControlModuleUI, ViewerDispatcher):
153
152
  self._detector_widget = QWidget()
154
153
  self._settings_widget = QWidget()
155
154
  self._settings_widget.setLayout(QtWidgets.QVBoxLayout())
155
+
156
156
  bkg_widget = QWidget()
157
157
  bkg_widget.setLayout(QtWidgets.QHBoxLayout())
158
158
 
159
159
  widget.layout().addWidget(info_ui)
160
160
  widget.layout().addWidget(self.toolbar)
161
161
  widget.layout().addWidget(self._detector_widget)
162
- widget.layout().addWidget(self._settings_widget)
162
+ if not config('viewer', 'settings_as_popup'):
163
+ widget.layout().addWidget(self._settings_widget)
163
164
  widget.layout().addStretch(0)
164
165
 
165
166
  info_ui.setLayout(QtWidgets.QHBoxLayout())
@@ -219,37 +220,38 @@ class DAQ_Viewer_UI(ControlModuleUI, ViewerDispatcher):
219
220
 
220
221
  def connect_things(self):
221
222
  self.connect_action('show_controls', lambda show: self._detector_widget.setVisible(show))
222
- self.connect_action('show_settings', lambda show: self._settings_widget.setVisible(show))
223
- self.connect_action('quit', lambda: self.command_sig.emit(ThreadCommand('quit', )))
224
- self.connect_action('show_config', lambda: self.command_sig.emit(ThreadCommand('show_config', )))
225
-
226
- self.connect_action('log', lambda: self.command_sig.emit(ThreadCommand('show_log', )))
227
- self.connect_action('stop', lambda: self.command_sig.emit(ThreadCommand('stop', )))
228
- self.connect_action('stop', lambda: self.get_action('grab').setChecked(False))
229
- self.connect_action('stop', lambda: self._enable_ini_buttons(True))
230
- self.connect_action('stop', lambda: self._settings_widget.setEnabled(True))
223
+ self.connect_action('show_settings', self._show_settings)
224
+ self.connect_action('quit', lambda: self.command_sig.emit(ThreadCommand(UiToMainViewer.QUIT, )))
225
+ self.connect_action('show_config', lambda: self.command_sig.emit(ThreadCommand(UiToMainViewer.SHOW_CONFIG, )))
231
226
 
227
+ self.connect_action('log', lambda: self.command_sig.emit(ThreadCommand(UiToMainViewer.SHOW_LOG, )))
228
+ self.connect_action('stop', self._stop)
232
229
  self.connect_action('grab', self._grab)
233
- self.connect_action('snap', lambda: self.command_sig.emit(ThreadCommand('snap', )))
230
+ self.connect_action('snap', lambda: self.command_sig.emit(ThreadCommand(UiToMainViewer.SNAP, )))
234
231
 
235
- self.connect_action('save_current', lambda: self.command_sig.emit(ThreadCommand('save_current', )))
236
- self.connect_action('save_new', lambda: self.command_sig.emit(ThreadCommand('save_new', )))
237
- self.connect_action('open', lambda: self.command_sig.emit(ThreadCommand('open', )))
232
+ self.connect_action('save_current', lambda: self.command_sig.emit(ThreadCommand(UiToMainViewer.SAVE_CURRENT, )))
233
+ self.connect_action('save_new', lambda: self.command_sig.emit(ThreadCommand(UiToMainViewer.SAVE_NEW, )))
234
+ self.connect_action('open', lambda: self.command_sig.emit(ThreadCommand(UiToMainViewer.OPEN, )))
238
235
 
239
236
  self._ini_det_pb.clicked.connect(self.send_init)
240
237
 
241
238
  self._detectors_combo.currentTextChanged.connect(
242
- lambda mod: self.command_sig.emit(ThreadCommand('detector_changed', mod)))
239
+ lambda mod: self.command_sig.emit(ThreadCommand(UiToMainViewer.DETECTOR_CHANGED, mod)))
243
240
  self._daq_types_combo.currentTextChanged.connect(self._daq_type_changed)
244
241
 
245
242
 
246
- self._do_bkg_cb.clicked.connect(lambda checked: self.command_sig.emit(ThreadCommand('do_bkg', checked)))
247
- self._take_bkg_pb.clicked.connect(lambda: self.command_sig.emit(ThreadCommand('take_bkg')))
243
+ self._do_bkg_cb.clicked.connect(lambda checked: self.command_sig.emit(ThreadCommand(UiToMainViewer.DO_BKG, checked)))
244
+ self._take_bkg_pb.clicked.connect(lambda: self.command_sig.emit(ThreadCommand(UiToMainViewer.TAKE_BKG)))
245
+
246
+ def _show_settings(self, show: bool = True):
247
+ self._settings_widget.setVisible(show)
248
+ self._settings_widget.closeEvent = lambda event: self.set_action_checked('show_settings', False)
248
249
 
249
250
  def update_viewers(self, viewers_type: List[ViewersEnum]):
250
251
  super().update_viewers(viewers_type)
251
- self.command_sig.emit(ThreadCommand('viewers_changed', attribute=dict(viewer_types=self.viewer_types,
252
- viewers=self.viewers)))
252
+ self.command_sig.emit(ThreadCommand(UiToMainViewer.VIEWERS_CHANGED,
253
+ attribute=dict(viewer_types=self.viewer_types,
254
+ viewers=self.viewers)))
253
255
 
254
256
  @property
255
257
  def data_ready(self):
@@ -263,7 +265,7 @@ class DAQ_Viewer_UI(ControlModuleUI, ViewerDispatcher):
263
265
  try:
264
266
  daq_type = enum_checker(DAQTypesEnum, daq_type)
265
267
 
266
- self.command_sig.emit(ThreadCommand('daq_type_changed', daq_type))
268
+ self.command_sig.emit(ThreadCommand(UiToMainViewer.DAQ_TYPE_CHANGED, daq_type))
267
269
  if self.viewer_types != [daq_type.to_viewer_type()]:
268
270
  self.update_viewers([daq_type.to_viewer_type()])
269
271
  except ValueError as e:
@@ -281,11 +283,18 @@ class DAQ_Viewer_UI(ControlModuleUI, ViewerDispatcher):
281
283
 
282
284
  def _grab(self):
283
285
  """Slot from the *grab* action"""
284
- self.command_sig.emit(ThreadCommand('grab', attribute=self.is_action_checked('grab')))
286
+ self.command_sig.emit(ThreadCommand(UiToMainViewer.GRAB, attribute=self.is_action_checked('grab')))
285
287
  self._enable_ini_buttons(not self.is_action_checked('grab'))
286
288
  if not self.config('viewer', 'allow_settings_edition'):
287
289
  self._settings_widget.setEnabled(not self.is_action_checked('grab'))
288
290
 
291
+ def _stop(self):
292
+ """Slot from the *stop* action"""
293
+ self.command_sig.emit(ThreadCommand(UiToMainViewer.STOP, ))
294
+ self.get_action('grab').setChecked(False)
295
+ self._enable_ini_buttons(True)
296
+ self._settings_widget.setEnabled(True)
297
+
289
298
  def do_init(self, do_init=True):
290
299
  """Programmatically press the Init button
291
300
  API entry
@@ -324,9 +333,10 @@ class DAQ_Viewer_UI(ControlModuleUI, ViewerDispatcher):
324
333
 
325
334
  def send_init(self, checked: bool):
326
335
  self._enable_detchoices(not checked)
327
- self.command_sig.emit(ThreadCommand('init', [checked,
328
- self._daq_types_combo.currentText(),
329
- self._detectors_combo.currentText()]))
336
+ self.command_sig.emit(ThreadCommand(UiToMainViewer.INIT,
337
+ [checked,
338
+ self._daq_types_combo.currentText(),
339
+ self._detectors_combo.currentText()]))
330
340
 
331
341
  def _enable_detchoices(self, enable=True):
332
342
  self._detectors_combo.setEnabled(enable)
@@ -377,7 +387,7 @@ def main(init_qt=True):
377
387
  def print_command_sig(cmd_sig):
378
388
  print(cmd_sig)
379
389
  prog.display_status(str(cmd_sig))
380
- if cmd_sig.command == 'init':
390
+ if cmd_sig.command == UiToMainViewer.INIT:
381
391
  prog._enable_grab_buttons(cmd_sig.attribute[0])
382
392
  prog.detector_init = cmd_sig.attribute[0]
383
393
 
@@ -6,7 +6,7 @@ Created the 16/03/2023
6
6
  """
7
7
  from pymodaq.utils.parameter import Parameter
8
8
  from pymodaq_gui.h5modules import saving
9
- from pymodaq.utils.h5modules.module_saving import DetectorSaver, ActuatorSaver, ScanSaver
9
+ from pymodaq.utils.h5modules.module_saving import DetectorSaver, ActuatorTimeSaver, ScanSaver
10
10
 
11
11
 
12
12
  class MockDAQViewer:
@@ -27,7 +27,7 @@ class MockDAQMove:
27
27
  self.settings = Parameter.create(name='settings', type='group', children=self.params) # create a Parameter
28
28
  self.h5saver = h5saver
29
29
  self.title = title
30
- self.module_and_data_saver = ActuatorSaver(self)
30
+ self.module_and_data_saver = ActuatorTimeSaver(self)
31
31
  self.ui = None
32
32
 
33
33