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.
- pymodaq/__init__.py +23 -4
- pymodaq/control_modules/daq_move.py +32 -73
- pymodaq/control_modules/daq_viewer.py +73 -98
- pymodaq/control_modules/daq_viewer_ui.py +2 -1
- pymodaq/control_modules/move_utility_classes.py +17 -7
- pymodaq/control_modules/utils.py +153 -5
- pymodaq/control_modules/viewer_utility_classes.py +31 -20
- pymodaq/dashboard.py +23 -5
- pymodaq/examples/tcp_client.py +97 -0
- pymodaq/extensions/__init__.py +4 -0
- pymodaq/extensions/bayesian/__init__.py +2 -0
- pymodaq/extensions/bayesian/bayesian_optimisation.py +673 -0
- pymodaq/extensions/bayesian/utils.py +403 -0
- pymodaq/extensions/daq_scan.py +4 -4
- pymodaq/extensions/daq_scan_ui.py +2 -1
- pymodaq/extensions/pid/pid_controller.py +12 -7
- pymodaq/extensions/pid/utils.py +9 -26
- pymodaq/extensions/utils.py +3 -0
- pymodaq/post_treatment/load_and_plot.py +42 -19
- pymodaq/resources/VERSION +1 -1
- pymodaq/resources/config_template.toml +9 -24
- pymodaq/resources/setup_plugin.py +1 -1
- pymodaq/utils/config.py +103 -5
- pymodaq/utils/daq_utils.py +35 -134
- pymodaq/utils/data.py +614 -95
- pymodaq/utils/enums.py +17 -1
- pymodaq/utils/factory.py +2 -2
- pymodaq/utils/gui_utils/custom_app.py +5 -2
- pymodaq/utils/gui_utils/dock.py +33 -4
- pymodaq/utils/gui_utils/utils.py +14 -1
- pymodaq/utils/h5modules/backends.py +9 -1
- pymodaq/utils/h5modules/data_saving.py +254 -57
- pymodaq/utils/h5modules/saving.py +1 -0
- pymodaq/utils/leco/__init__.py +25 -0
- pymodaq/utils/leco/daq_move_LECODirector.py +172 -0
- pymodaq/utils/leco/daq_xDviewer_LECODirector.py +170 -0
- pymodaq/utils/leco/desktop.ini +2 -0
- pymodaq/utils/leco/director_utils.py +58 -0
- pymodaq/utils/leco/leco_director.py +88 -0
- pymodaq/utils/leco/pymodaq_listener.py +279 -0
- pymodaq/utils/leco/utils.py +41 -0
- pymodaq/utils/managers/action_manager.py +20 -6
- pymodaq/utils/managers/parameter_manager.py +6 -4
- pymodaq/utils/managers/roi_manager.py +63 -54
- pymodaq/utils/math_utils.py +1 -1
- pymodaq/utils/plotting/data_viewers/__init__.py +3 -1
- pymodaq/utils/plotting/data_viewers/base.py +286 -0
- pymodaq/utils/plotting/data_viewers/viewer.py +29 -202
- pymodaq/utils/plotting/data_viewers/viewer0D.py +94 -47
- pymodaq/utils/plotting/data_viewers/viewer1D.py +341 -174
- pymodaq/utils/plotting/data_viewers/viewer1Dbasic.py +1 -1
- pymodaq/utils/plotting/data_viewers/viewer2D.py +271 -181
- pymodaq/utils/plotting/data_viewers/viewerND.py +26 -22
- pymodaq/utils/plotting/items/crosshair.py +3 -3
- pymodaq/utils/plotting/items/image.py +2 -1
- pymodaq/utils/plotting/plotter/plotter.py +94 -0
- pymodaq/utils/plotting/plotter/plotters/__init__.py +0 -0
- pymodaq/utils/plotting/plotter/plotters/matplotlib_plotters.py +134 -0
- pymodaq/utils/plotting/plotter/plotters/qt_plotters.py +78 -0
- pymodaq/utils/plotting/utils/axes_viewer.py +1 -1
- pymodaq/utils/plotting/utils/filter.py +194 -147
- pymodaq/utils/plotting/utils/lineout.py +13 -11
- pymodaq/utils/plotting/utils/plot_utils.py +89 -12
- pymodaq/utils/scanner/__init__.py +0 -3
- pymodaq/utils/scanner/scan_config.py +1 -9
- pymodaq/utils/scanner/scan_factory.py +10 -36
- pymodaq/utils/scanner/scanner.py +3 -2
- pymodaq/utils/scanner/scanners/_1d_scanners.py +7 -5
- pymodaq/utils/scanner/scanners/_2d_scanners.py +36 -49
- pymodaq/utils/scanner/scanners/sequential.py +10 -4
- pymodaq/utils/scanner/scanners/tabular.py +10 -5
- pymodaq/utils/slicing.py +1 -1
- pymodaq/utils/tcp_ip/serializer.py +38 -5
- pymodaq/utils/tcp_ip/tcp_server_client.py +25 -17
- {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/METADATA +4 -2
- {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/RECORD +79 -63
- pymodaq/resources/config_scan_template.toml +0 -42
- {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/WHEEL +0 -0
- {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/entry_points.txt +0 -0
- {pymodaq-4.1.5.dist-info → pymodaq-4.2.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -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,
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
pymodaq/control_modules/utils.py
CHANGED
|
@@ -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.
|
|
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
|
|
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
|
|
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*
|
|
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
|
-
|
|
186
|
-
|
|
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(
|
|
191
|
-
|
|
192
|
-
|
|
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(
|
|
199
|
-
|
|
200
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
+
|
pymodaq/extensions/__init__.py
CHANGED
|
@@ -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
|
|