pymodaq 3.6.13__py3-none-any.whl → 4.0.1__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (233) hide show
  1. pymodaq/__init__.py +13 -6
  2. pymodaq/control_modules/__init__.py +0 -7
  3. pymodaq/control_modules/daq_move.py +965 -2
  4. pymodaq/control_modules/daq_move_ui.py +319 -0
  5. pymodaq/control_modules/daq_viewer.py +1573 -3
  6. pymodaq/control_modules/daq_viewer_ui.py +393 -0
  7. pymodaq/control_modules/mocks.py +51 -0
  8. pymodaq/control_modules/move_utility_classes.py +709 -8
  9. pymodaq/control_modules/utils.py +256 -0
  10. pymodaq/control_modules/viewer_utility_classes.py +663 -6
  11. pymodaq/daq_utils.py +89 -0
  12. pymodaq/dashboard.py +91 -72
  13. pymodaq/examples/custom_app.py +12 -11
  14. pymodaq/examples/custom_viewer.py +10 -10
  15. pymodaq/examples/function_plotter.py +16 -13
  16. pymodaq/examples/nonlinearscanner.py +8 -6
  17. pymodaq/examples/parameter_ex.py +7 -7
  18. pymodaq/examples/preset_MockCamera.xml +1 -0
  19. pymodaq/extensions/__init__.py +16 -0
  20. pymodaq/extensions/console.py +76 -0
  21. pymodaq/{daq_logger.py → extensions/daq_logger.py} +115 -65
  22. pymodaq/extensions/daq_scan.py +1339 -0
  23. pymodaq/extensions/daq_scan_ui.py +240 -0
  24. pymodaq/extensions/h5browser.py +23 -0
  25. pymodaq/{pid → extensions/pid}/__init__.py +4 -2
  26. pymodaq/{pid → extensions/pid}/daq_move_PID.py +2 -2
  27. pymodaq/{pid → extensions/pid}/pid_controller.py +48 -36
  28. pymodaq/{pid → extensions/pid}/utils.py +52 -6
  29. pymodaq/extensions/utils.py +40 -0
  30. pymodaq/post_treatment/__init__.py +6 -0
  31. pymodaq/{daq_analysis → post_treatment/daq_analysis}/daq_analysis_main.py +17 -17
  32. pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_main.py +8 -14
  33. pymodaq/post_treatment/load_and_plot.py +219 -0
  34. pymodaq/post_treatment/process_to_scalar.py +263 -0
  35. pymodaq/resources/QtDesigner_Ressources/Icon_Library/run_all.png +0 -0
  36. pymodaq/resources/QtDesigner_Ressources/Icon_Library/stop_all.png +0 -0
  37. pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources.bat +1 -1
  38. pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources.qrc +1 -0
  39. pymodaq/resources/QtDesigner_Ressources/QtDesigner_ressources_rc.py +109784 -109173
  40. pymodaq/resources/QtDesigner_Ressources/icons.svg +142 -0
  41. pymodaq/resources/VERSION +1 -1
  42. pymodaq/resources/config_template.toml +32 -13
  43. pymodaq/resources/preset_default.xml +1 -1
  44. pymodaq/{daq_utils → utils}/Tuto innosetup/script_full_setup.iss +1 -1
  45. pymodaq/utils/__init__.py +0 -29
  46. pymodaq/utils/abstract/__init__.py +48 -0
  47. pymodaq/{daq_utils → utils}/abstract/logger.py +7 -3
  48. pymodaq/utils/array_manipulation.py +379 -8
  49. pymodaq/{daq_utils → utils}/calibration_camera.py +6 -6
  50. pymodaq/{daq_utils → utils}/chrono_timer.py +1 -1
  51. pymodaq/utils/config.py +448 -0
  52. pymodaq/utils/conftests.py +5 -0
  53. pymodaq/utils/daq_utils.py +828 -8
  54. pymodaq/utils/data.py +1873 -7
  55. pymodaq/{daq_utils → utils}/db/db_logger/db_logger.py +86 -47
  56. pymodaq/{daq_utils → utils}/db/db_logger/db_logger_models.py +31 -10
  57. pymodaq/{daq_utils → utils}/enums.py +12 -7
  58. pymodaq/utils/exceptions.py +37 -0
  59. pymodaq/utils/factory.py +82 -0
  60. pymodaq/{daq_utils → utils}/gui_utils/__init__.py +1 -1
  61. pymodaq/utils/gui_utils/custom_app.py +129 -0
  62. pymodaq/utils/gui_utils/file_io.py +66 -0
  63. pymodaq/{daq_utils → utils}/gui_utils/layout.py +2 -2
  64. pymodaq/{daq_utils → utils}/gui_utils/utils.py +13 -3
  65. pymodaq/{daq_utils → utils}/gui_utils/widgets/__init__.py +2 -2
  66. pymodaq/utils/gui_utils/widgets/label.py +24 -0
  67. pymodaq/{daq_utils → utils}/gui_utils/widgets/lcd.py +12 -7
  68. pymodaq/{daq_utils → utils}/gui_utils/widgets/push.py +66 -2
  69. pymodaq/{daq_utils → utils}/gui_utils/widgets/qled.py +6 -4
  70. pymodaq/utils/gui_utils/widgets/spinbox.py +24 -0
  71. pymodaq/{daq_utils → utils}/gui_utils/widgets/table.py +2 -2
  72. pymodaq/utils/h5modules/__init__.py +1 -0
  73. pymodaq/{daq_utils/h5backend.py → utils/h5modules/backends.py} +200 -112
  74. pymodaq/utils/h5modules/browsing.py +683 -0
  75. pymodaq/utils/h5modules/data_saving.py +839 -0
  76. pymodaq/utils/h5modules/h5logging.py +110 -0
  77. pymodaq/utils/h5modules/module_saving.py +350 -0
  78. pymodaq/utils/h5modules/saving.py +914 -0
  79. pymodaq/utils/h5modules/utils.py +85 -0
  80. pymodaq/utils/logger.py +64 -6
  81. pymodaq/utils/managers/action_manager.py +460 -0
  82. pymodaq/{daq_utils → utils}/managers/batchscan_manager.py +144 -112
  83. pymodaq/{daq_utils → utils}/managers/modules_manager.py +188 -114
  84. pymodaq/{daq_utils → utils}/managers/overshoot_manager.py +3 -3
  85. pymodaq/utils/managers/parameter_manager.py +110 -0
  86. pymodaq/{daq_utils → utils}/managers/preset_manager.py +17 -13
  87. pymodaq/{daq_utils → utils}/managers/preset_manager_utils.py +8 -7
  88. pymodaq/{daq_utils → utils}/managers/remote_manager.py +7 -6
  89. pymodaq/{daq_utils → utils}/managers/roi_manager.py +148 -57
  90. pymodaq/utils/math_utils.py +546 -10
  91. pymodaq/{daq_utils → utils}/messenger.py +5 -1
  92. pymodaq/utils/parameter/__init__.py +2 -15
  93. pymodaq/{daq_utils → utils}/parameter/ioxml.py +12 -6
  94. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/__init__.py +1 -3
  95. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/filedir.py +1 -1
  96. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/itemselect.py +3 -0
  97. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/led.py +1 -1
  98. pymodaq/utils/parameter/pymodaq_ptypes/pixmap.py +161 -0
  99. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/slide.py +1 -1
  100. pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/table.py +1 -1
  101. pymodaq/utils/parameter/utils.py +206 -11
  102. pymodaq/utils/plotting/data_viewers/__init__.py +6 -0
  103. pymodaq/utils/plotting/data_viewers/viewer.py +393 -0
  104. pymodaq/utils/plotting/data_viewers/viewer0D.py +251 -0
  105. pymodaq/utils/plotting/data_viewers/viewer1D.py +574 -0
  106. pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer1Dbasic.py +8 -3
  107. pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer2D.py +292 -357
  108. pymodaq/{daq_utils → utils}/plotting/data_viewers/viewer2D_basic.py +58 -75
  109. pymodaq/utils/plotting/data_viewers/viewerND.py +738 -0
  110. pymodaq/{daq_utils → utils}/plotting/gant_chart.py +2 -2
  111. pymodaq/{daq_utils → utils}/plotting/items/axis_scaled.py +4 -2
  112. pymodaq/{daq_utils → utils}/plotting/items/image.py +8 -6
  113. pymodaq/utils/plotting/navigator.py +355 -0
  114. pymodaq/utils/plotting/scan_selector.py +480 -0
  115. pymodaq/utils/plotting/utils/axes_viewer.py +88 -0
  116. pymodaq/utils/plotting/utils/filter.py +538 -0
  117. pymodaq/utils/plotting/utils/lineout.py +224 -0
  118. pymodaq/{daq_utils → utils}/plotting/utils/plot_utils.py +196 -84
  119. pymodaq/{daq_utils → utils}/plotting/utils/signalND.py +21 -13
  120. pymodaq/utils/plotting/widgets.py +76 -0
  121. pymodaq/utils/scanner/__init__.py +10 -0
  122. pymodaq/utils/scanner/scan_factory.py +204 -0
  123. pymodaq/utils/scanner/scanner.py +271 -0
  124. pymodaq/utils/scanner/scanners/_1d_scanners.py +117 -0
  125. pymodaq/utils/scanner/scanners/_2d_scanners.py +293 -0
  126. pymodaq/utils/scanner/scanners/sequential.py +192 -0
  127. pymodaq/utils/scanner/scanners/tabular.py +294 -0
  128. pymodaq/utils/scanner/utils.py +83 -0
  129. pymodaq/utils/slicing.py +47 -0
  130. pymodaq/utils/svg/__init__.py +6 -0
  131. pymodaq/utils/svg/svg_renderer.py +20 -0
  132. pymodaq/utils/svg/svg_view.py +35 -0
  133. pymodaq/utils/svg/svg_viewer2D.py +51 -0
  134. pymodaq/{daq_utils → utils}/tcp_server_client.py +36 -37
  135. pymodaq/{daq_utils → utils}/tree_layout/tree_layout_main.py +50 -35
  136. pymodaq/utils/units.py +216 -0
  137. pymodaq-4.0.1.dist-info/METADATA +159 -0
  138. {pymodaq-3.6.13.dist-info → pymodaq-4.0.1.dist-info}/RECORD +167 -170
  139. {pymodaq-3.6.13.dist-info → pymodaq-4.0.1.dist-info}/WHEEL +1 -2
  140. pymodaq-4.0.1.dist-info/entry_points.txt +8 -0
  141. pymodaq/daq_move/daq_move_gui.py +0 -279
  142. pymodaq/daq_move/daq_move_gui.ui +0 -534
  143. pymodaq/daq_move/daq_move_main.py +0 -1042
  144. pymodaq/daq_move/process_from_QtDesigner_DAQ_Move_GUI.bat +0 -2
  145. pymodaq/daq_move/utility_classes.py +0 -686
  146. pymodaq/daq_scan.py +0 -2160
  147. pymodaq/daq_utils/array_manipulation.py +0 -386
  148. pymodaq/daq_utils/config.py +0 -273
  149. pymodaq/daq_utils/conftests.py +0 -7
  150. pymodaq/daq_utils/custom_parameter_tree.py +0 -9
  151. pymodaq/daq_utils/daq_enums.py +0 -133
  152. pymodaq/daq_utils/daq_utils.py +0 -1402
  153. pymodaq/daq_utils/exceptions.py +0 -71
  154. pymodaq/daq_utils/gui_utils/custom_app.py +0 -103
  155. pymodaq/daq_utils/gui_utils/file_io.py +0 -75
  156. pymodaq/daq_utils/gui_utils/widgets/spinbox.py +0 -9
  157. pymodaq/daq_utils/h5exporter_hyperspy.py +0 -115
  158. pymodaq/daq_utils/h5exporters.py +0 -242
  159. pymodaq/daq_utils/h5modules.py +0 -1559
  160. pymodaq/daq_utils/h5utils.py +0 -241
  161. pymodaq/daq_utils/managers/action_manager.py +0 -236
  162. pymodaq/daq_utils/managers/parameter_manager.py +0 -57
  163. pymodaq/daq_utils/math_utils.py +0 -705
  164. pymodaq/daq_utils/parameter/__init__.py +0 -1
  165. pymodaq/daq_utils/parameter/oldpymodaq_ptypes.py +0 -1626
  166. pymodaq/daq_utils/parameter/pymodaq_ptypes/pixmap.py +0 -85
  167. pymodaq/daq_utils/parameter/utils.py +0 -136
  168. pymodaq/daq_utils/plotting/data_viewers/__init__.py +0 -0
  169. pymodaq/daq_utils/plotting/data_viewers/process_from_QtDesigner_0DViewer_GUI.bat +0 -2
  170. pymodaq/daq_utils/plotting/data_viewers/viewer0D.py +0 -204
  171. pymodaq/daq_utils/plotting/data_viewers/viewer0D_GUI.py +0 -89
  172. pymodaq/daq_utils/plotting/data_viewers/viewer0D_GUI.ui +0 -131
  173. pymodaq/daq_utils/plotting/data_viewers/viewer1D.py +0 -781
  174. pymodaq/daq_utils/plotting/data_viewers/viewerND.py +0 -894
  175. pymodaq/daq_utils/plotting/data_viewers/viewerbase.py +0 -64
  176. pymodaq/daq_utils/plotting/items/__init__.py +0 -0
  177. pymodaq/daq_utils/plotting/navigator.py +0 -500
  178. pymodaq/daq_utils/plotting/scan_selector.py +0 -289
  179. pymodaq/daq_utils/plotting/utils/__init__.py +0 -0
  180. pymodaq/daq_utils/plotting/utils/filter.py +0 -236
  181. pymodaq/daq_utils/plotting/viewer0D/__init__.py +0 -0
  182. pymodaq/daq_utils/plotting/viewer0D/viewer0D_main.py +0 -4
  183. pymodaq/daq_utils/plotting/viewer1D/__init__.py +0 -0
  184. pymodaq/daq_utils/plotting/viewer1D/viewer1D_main.py +0 -4
  185. pymodaq/daq_utils/plotting/viewer1D/viewer1Dbasic.py +0 -4
  186. pymodaq/daq_utils/plotting/viewer2D/viewer_2D_basic.py +0 -4
  187. pymodaq/daq_utils/plotting/viewer2D/viewer_2D_main.py +0 -4
  188. pymodaq/daq_utils/plotting/viewerND/__init__.py +0 -0
  189. pymodaq/daq_utils/plotting/viewerND/viewerND_main.py +0 -4
  190. pymodaq/daq_utils/scanner.py +0 -1289
  191. pymodaq/daq_utils/tree_layout/__init__.py +0 -0
  192. pymodaq/daq_viewer/__init__.py +0 -0
  193. pymodaq/daq_viewer/daq_gui_settings.py +0 -237
  194. pymodaq/daq_viewer/daq_gui_settings.ui +0 -441
  195. pymodaq/daq_viewer/daq_viewer_main.py +0 -2225
  196. pymodaq/daq_viewer/process_from_QtDesigner_DAQ_GUI_settings.bat +0 -2
  197. pymodaq/daq_viewer/utility_classes.py +0 -673
  198. pymodaq/examples/logger_image/__init__.py +0 -0
  199. pymodaq/examples/logger_image/logger_displayer.py +0 -121
  200. pymodaq/examples/logger_image/setup.svg +0 -3119
  201. pymodaq/examples/logger_image/setup_svg.py +0 -114
  202. pymodaq/h5browser.py +0 -39
  203. pymodaq/utils/scanner.py +0 -15
  204. pymodaq-3.6.13.dist-info/METADATA +0 -39
  205. pymodaq-3.6.13.dist-info/entry_points.txt +0 -8
  206. pymodaq-3.6.13.dist-info/top_level.txt +0 -1
  207. /pymodaq/{daq_analysis → post_treatment/daq_analysis}/__init__.py +0 -0
  208. /pymodaq/{daq_measurement → post_treatment/daq_measurement}/__init__.py +0 -0
  209. /pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_GUI.py +0 -0
  210. /pymodaq/{daq_measurement → post_treatment/daq_measurement}/daq_measurement_GUI.ui +0 -0
  211. /pymodaq/{daq_measurement → post_treatment/daq_measurement}/process_from_QtDesigner_DAQ_Measurement_GUI.bat +0 -0
  212. /pymodaq/{daq_utils → utils}/Tuto innosetup/Tuto innosetup.odt +0 -0
  213. /pymodaq/{daq_utils → utils}/Tuto innosetup/Tuto innosetup.pdf +0 -0
  214. /pymodaq/{daq_move → utils/db}/__init__.py +0 -0
  215. /pymodaq/{daq_utils → utils/db/db_logger}/__init__.py +0 -0
  216. /pymodaq/{daq_utils → utils}/gui_utils/dock.py +0 -0
  217. /pymodaq/{daq_utils → utils}/gui_utils/list_picker.py +0 -0
  218. /pymodaq/{daq_utils/abstract → utils/managers}/__init__.py +0 -0
  219. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/bool.py +0 -0
  220. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/date.py +0 -0
  221. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/list.py +0 -0
  222. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/numeric.py +0 -0
  223. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/tableview.py +0 -0
  224. /pymodaq/{daq_utils → utils}/parameter/pymodaq_ptypes/text.py +0 -0
  225. /pymodaq/{daq_utils/db → utils/plotting}/__init__.py +0 -0
  226. /pymodaq/{daq_utils → utils}/plotting/image_viewer.py +0 -0
  227. /pymodaq/{daq_utils/db/db_logger → utils/plotting/items}/__init__.py +0 -0
  228. /pymodaq/{daq_utils → utils}/plotting/items/crosshair.py +0 -0
  229. /pymodaq/{daq_utils/managers → utils/plotting/utils}/__init__.py +0 -0
  230. /pymodaq/{daq_utils → utils}/qvariant.py +0 -0
  231. /pymodaq/{daq_utils/plotting/viewer2D → utils/scanner/scanners}/__init__.py +0 -0
  232. /pymodaq/{daq_utils/plotting → utils/tree_layout}/__init__.py +0 -0
  233. {pymodaq-3.6.13.dist-info → pymodaq-4.0.1.dist-info/licenses}/LICENSE +0 -0
@@ -1,2225 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- Created on Wed Jan 10 16:54:14 2018
4
-
5
- @author: Weber Sébastien
6
- """
7
- import os
8
-
9
- from pymodaq.daq_utils.gui_utils.file_io import select_file
10
- import pymodaq.daq_utils.gui_utils.utils
11
- from qtpy import QtGui, QtWidgets, QtCore
12
- from qtpy.QtCore import Qt, QObject, Slot, QThread, Signal, QRectF
13
- import sys
14
- from typing import List
15
- import pymodaq.daq_utils.scanner
16
- from pymodaq.daq_viewer.daq_gui_settings import Ui_Form
17
- import copy
18
-
19
- from pymodaq.daq_utils.plotting.data_viewers.viewer0D import Viewer0D
20
- from pymodaq.daq_utils.plotting.data_viewers.viewer1D import Viewer1D
21
- from pymodaq.daq_utils.plotting.data_viewers.viewer2D import Viewer2D
22
- from pymodaq.daq_utils.plotting.data_viewers.viewerND import ViewerND
23
- from pymodaq.daq_utils.scanner import Scanner
24
- from pymodaq.daq_utils.plotting.navigator import Navigator
25
- from pymodaq.daq_utils.tcp_server_client import TCPClient
26
- from pymodaq.daq_utils.gui_utils.widgets.lcd import LCD
27
- from pymodaq.daq_utils.config import Config, get_set_local_dir
28
- from pymodaq.daq_utils import gui_utils as gutils
29
- from pymodaq.daq_utils.h5modules import browse_data
30
- from pymodaq.daq_utils.daq_utils import ThreadCommand, get_plugins
31
- from pymodaq.daq_utils.exceptions import DetectorError
32
-
33
- from collections import OrderedDict
34
- import numpy as np
35
-
36
- from pyqtgraph.parametertree import Parameter, ParameterTree
37
- from pymodaq.daq_utils.parameter import ioxml
38
- from pymodaq.daq_utils.parameter import utils as putils
39
-
40
- from easydict import EasyDict as edict
41
- from pymodaq.daq_viewer.utility_classes import params as daq_viewer_params
42
- import pickle
43
- import time
44
- import datetime
45
- import tables
46
- from pathlib import Path
47
- from pymodaq.daq_utils.h5modules import H5Saver
48
- from pymodaq.daq_utils import daq_utils as utils
49
- from pymodaq.daq_utils.gui_utils import DockArea, Dock
50
-
51
- logger = utils.set_logger(utils.get_module_name(__file__))
52
- config = Config()
53
-
54
- local_path = get_set_local_dir()
55
-
56
- DAQ_0DViewer_Det_types = get_plugins('daq_0Dviewer')
57
- DAQ_1DViewer_Det_types = get_plugins('daq_1Dviewer')
58
- DAQ_2DViewer_Det_types = get_plugins('daq_2Dviewer')
59
- DAQ_NDViewer_Det_types = get_plugins('daq_NDviewer')
60
-
61
-
62
- class DAQ_Viewer(QObject):
63
- """
64
- ========================= =======================================
65
- **Attributes** **Type**
66
-
67
- *command_detector* instance of pyqt Signal
68
- *grab_done_signal* instance of pyqt Signal
69
- *quit_signal* instance of pyqt Signal
70
- *update_settings_signal* instance of pyqt Signal
71
- *overshoot_signal* instance of pyqt Signal
72
- *status_signal* instance of pyqt Signal
73
- *params* dictionnary list
74
-
75
- *widgetsettings* instance of QWidget
76
- *title* string
77
- *DAQ_type* string
78
- *dockarea* instance of DockArea
79
- *bkg* ???
80
- *filters* instance of tables.Filters
81
- *settings* instance of pyqtgraph parameter tree
82
- *measurement_module* ???
83
- *detector* instance of DAQ_Detector
84
- *wait_time* int
85
- *save_file_pathname* string
86
- *ind_continuous_grab* int
87
- *initialized_state* boolean
88
- *snapshot_pathname* string
89
- *x_axis* 1D numpy array
90
- *y_axis* 1D numpy array
91
- *current_datas* dictionnary
92
- *data_to_save_export* ordered dictionnary
93
- *do_save_data* boolean
94
- *do_continuous_save* boolean
95
- *file_continuous_save* ???
96
- ========================= =======================================
97
- """
98
- command_detector = Signal(ThreadCommand)
99
- init_signal = Signal(bool)
100
- custom_sig = Signal(ThreadCommand) # particular case where DAQ_Viewer is used for a custom module
101
- command_tcpip = Signal(ThreadCommand)
102
- grab_done_signal = Signal(
103
- OrderedDict) # OrderedDict(name=self.title,x_axis=None,y_axis=None,z_axis=None,data0D=None,data1D=None,data2D=None)
104
- quit_signal = Signal()
105
- update_settings_signal = Signal(edict)
106
- overshoot_signal = Signal(bool)
107
- status_signal = Signal(str)
108
-
109
- params = daq_viewer_params
110
-
111
- def __init__(self, parent, dock_settings=None, dock_viewer=None, title="Testing", DAQ_type="DAQ0D",
112
- preset=None, init=False, controller_ID=-1, parent_scan=None):
113
-
114
- self.logger = utils.set_logger(f'{logger.name}.{title}')
115
- self.logger.info(f'Initializing DAQ_Viewer: {title}')
116
- super().__init__()
117
-
118
- here = Path(__file__).parent
119
- splash = QtGui.QPixmap(str(here.parent.joinpath('splash.png')))
120
- self.splash_sc = QtWidgets.QSplashScreen(splash, Qt.WindowStaysOnTopHint)
121
- self.title = title
122
- self.DAQ_type = DAQ_type
123
- self.h5saver_continuous = H5Saver(save_type='detector')
124
-
125
- self.time_array = None
126
- self.channel_arrays = []
127
- self.grab_done = False
128
- self.start_grab_time = 0. # used for the refreshing rate
129
- self.navigator = None
130
- self.scanner = None
131
- self.received_data = 0
132
- self.lcd = None
133
- self.parent_scan = parent_scan # to use if one need the DAQ_Scan object
134
-
135
- self.ini_time = 0 # used for the continuous saving
136
- self.wait_time = 1000
137
-
138
- self.dockarea = parent
139
- self.bkg = None # buffer to store background
140
- self.filters = tables.Filters(
141
- complevel=5) # options to save data to h5 file using compression zlib library and level 5 compression
142
-
143
- self.send_to_tcpip = False
144
- self.tcpclient_thread = None
145
-
146
- self.measurement_module = None
147
-
148
- self.save_file_pathname = None # to store last active path, will be an Path object
149
- self.ind_continuous_grab = 0
150
-
151
- self.initialized_state = False
152
- self.measurement_module = None
153
- self.snapshot_pathname = None
154
-
155
- self.current_datas = None
156
- # edict to be send to the daq_measurement module from 1D traces if any
157
-
158
- self.data_to_save_export = None
159
-
160
- self.do_save_data = False
161
- self.do_continuous_save = False
162
- self.is_continuous_initialized = False
163
- self.file_continuous_save = None
164
-
165
- # ###########IMPORTANT############################
166
- self.controller = None
167
- # the hardware controller/set after initialization and to be used by other modules if needed
168
- # ################################################
169
-
170
- self.setupUI(parent, dock_settings, dock_viewer)
171
-
172
- self.settings.child('main_settings', 'controller_ID').setValue(controller_ID)
173
-
174
- self.set_enabled_grab_buttons(enable=False)
175
- self.set_enabled_Ini_buttons(enable=True)
176
- self.ui.data_ready_led.set_as_false()
177
-
178
- self.set_setting_tree() # to activate parameters of default Mock detector
179
-
180
- # set managers options
181
- if preset is not None:
182
- for preset_dict in preset:
183
- # fo instance preset_dict=edict(object='Stage_type_combo',method='setCurrentIndex',value=1)
184
- if hasattr(self.ui, preset_dict['object']):
185
- obj = getattr(self.ui, preset_dict['object'])
186
- if hasattr(obj, preset_dict['method']):
187
- setattr(obj, preset_dict['method'], preset_dict['value'])
188
- # initialize the controller if init=True
189
- if init:
190
- self.ui.IniDet_pb.click()
191
-
192
- self.show_settings()
193
-
194
- @property
195
- def viewer_docks(self):
196
- return self.ui.viewer_docks
197
-
198
- @property
199
- def daq_type(self):
200
- return self.ui.DAQ_type_combo.CurrentText()
201
-
202
- @daq_type.setter
203
- def daq_type(self, daq_typ):
204
- self.ui.DAQ_type_combo.setCurrentText(daq_typ)
205
-
206
- @property
207
- def detector(self):
208
- return self.ui.Detector_type_combo.currentText()
209
-
210
- @detector.setter
211
- def detector(self, det):
212
- self.ui.Detector_type_combo.setCurrentText(det)
213
- if self.detector != det:
214
- raise DetectorError(f'{det} is not a valid installed detector: {self.detector_types}')
215
-
216
-
217
- @property
218
- def grab_state(self):
219
- return self.ui.grab_pb.isChecked()
220
-
221
- @property
222
- def is_bkg(self):
223
- return self.ui.do_bkg_cb.isChecked()
224
-
225
- @Slot(str)
226
- def set_DAQ_type(self, daq_type):
227
- self.DAQ_type = daq_type
228
- self.settings.child('main_settings', 'DAQ_type').setValue(daq_type)
229
-
230
- #######################
231
- # INIT QUIT
232
- def setupUI(self, parent, dock_settings, dock_viewer):
233
- self.ui = Ui_Form()
234
- widgetsettings = QtWidgets.QWidget()
235
- self.ui.setupUi(widgetsettings)
236
-
237
- self.ui.title_label.setText(self.title)
238
-
239
- self.ui.Ini_state_LED.clickable = False
240
- self.ui.Ini_state_LED.set_as_false()
241
-
242
- self.ui.navigator_pb.setVisible(False)
243
- self.ui.navigator_pb.clicked.connect(self.send_to_nav)
244
-
245
- self.ui.statusbar = QtWidgets.QStatusBar(parent)
246
- self.ui.statusbar.setMaximumHeight(25)
247
- self.ui.settings_layout.addWidget(self.ui.statusbar)
248
- self.ui.status_message = QtWidgets.QLabel()
249
- self.ui.status_message.setMaximumHeight(25)
250
- self.ui.statusbar.addWidget(self.ui.status_message)
251
-
252
- # create main parameter tree
253
- self.ui.settings_tree = ParameterTree()
254
- self.ui.settings_layout.addWidget(self.ui.settings_tree, 10)
255
- self.ui.settings_tree.setMinimumWidth(300)
256
- self.settings = Parameter.create(title=self.title + ' settings', name='Settings', type='group',
257
- children=self.params)
258
- self.settings.child('main_settings', 'DAQ_type').setValue(self.DAQ_type)
259
- self.ui.settings_tree.setParameters(self.settings, showTop=False)
260
- self.ui.settings_layout.addWidget(self.h5saver_continuous.settings_tree)
261
- self.h5saver_continuous.settings_tree.setVisible(False)
262
-
263
- # connecting from tree
264
- self.settings.sigTreeStateChanged.connect(
265
- self.parameter_tree_changed) # any changes on the settings will update accordingly the detector
266
- self.h5saver_continuous.settings.sigTreeStateChanged.connect(
267
- self.parameter_tree_changed) # trigger action from "do_save' boolean
268
-
269
- if dock_settings is not None:
270
- self.ui.settings_dock = dock_settings
271
- self.ui.settings_dock.setTitle(self.title + "_Settings")
272
- else:
273
- self.ui.settings_dock = Dock(self.title + "_Settings", size=(10, 10))
274
- self.dockarea.addDock(self.ui.settings_dock)
275
-
276
- self.ui.viewer_docks = []
277
- if dock_viewer is not None:
278
- self.ui.viewer_docks.append(dock_viewer)
279
- self.ui.viewer_docks[-1].setTitle(self.title + "_Viewer 1")
280
- else:
281
- self.ui.viewer_docks.append(Dock(self.title + "_Viewer", size=(500, 300), closable=False))
282
- self.dockarea.addDock(self.ui.viewer_docks[-1], 'right', self.ui.settings_dock)
283
-
284
- for dock in self.ui.viewer_docks:
285
- dock.setEnabled(False)
286
-
287
- # install specific viewers
288
- self.viewer_widgets = []
289
- self.change_viewer()
290
-
291
- self.ui.settings_dock.addWidget(widgetsettings)
292
-
293
- # #Setting detector types
294
- self.ui.Detector_type_combo.clear()
295
- self.ui.Detector_type_combo.addItems(self.detector_types)
296
-
297
- # #Connecting buttons:
298
- self.ui.update_com_pb.clicked.connect(self.update_com) # update communications with hardware
299
- self.ui.Quit_pb.clicked.connect(self.quit_fun, type=Qt.QueuedConnection)
300
- self.ui.settings_pb.clicked.connect(self.show_settings)
301
- self.ui.IniDet_pb.clicked.connect(self.ini_det_fun)
302
- self.update_status("Ready", wait_time=self.wait_time)
303
- self.ui.grab_pb.clicked.connect(lambda: self.grab_data(grab_state=True))
304
- self.ui.single_pb.clicked.connect(lambda: self.grab_data(grab_state=False))
305
- self.ui.stop_pb.clicked.connect(self.stop_all)
306
- self.ui.save_new_pb.clicked.connect(self.save_new)
307
- self.ui.save_current_pb.clicked.connect(self.save_current)
308
- self.ui.load_data_pb.clicked.connect(self.load_data)
309
- self.grab_done_signal[OrderedDict].connect(self.save_export_data)
310
- self.ui.Detector_type_combo.currentIndexChanged.connect(self.set_setting_tree)
311
- self.ui.save_settings_pb.clicked.connect(self.save_settings)
312
- self.ui.load_settings_pb.clicked.connect(self.load_settings)
313
- self.ui.DAQ_type_combo.currentTextChanged[str].connect(self.set_DAQ_type)
314
- self.ui.take_bkg_cb.clicked.connect(self.take_bkg)
315
- self.ui.DAQ_type_combo.setCurrentText(self.DAQ_type)
316
- self.ui.log_pb.clicked.connect(self.show_log)
317
-
318
- def quit_fun(self):
319
- """
320
- | close the current instance of daq_viewer_main emmiting the quit signal.
321
- | Treat an exception if an error during the detector unitializing has occured.
322
-
323
- """
324
- # insert anything that needs to be closed before leaving
325
- try:
326
- if self.initialized_state: # means initialzed
327
- self.ui.IniDet_pb.click()
328
- QtWidgets.QApplication.processEvents()
329
- self.quit_signal.emit()
330
- try:
331
- self.ui.settings_dock.close() # close the settings widget
332
- except Exception as e:
333
- self.logger.exception(str(e))
334
- if self.lcd is not None:
335
- try:
336
- self.lcd.parent.close()
337
- except Exception as e:
338
- self.logger.exception(str(e))
339
- try:
340
- for dock in self.ui.viewer_docks:
341
- dock.close() # the dock viewers
342
- except Exception as e:
343
- self.logger.exception(str(e))
344
- if hasattr(self, 'nav_dock'):
345
- self.nav_dock.close()
346
-
347
- if __name__ == '__main__':
348
- try:
349
- self.dockarea.parent().close()
350
- except Exception as e:
351
- self.logger.exception(str(e))
352
- except Exception as e:
353
- icon = QtGui.QIcon()
354
- icon.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/close2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
355
- msgBox = QtWidgets.QMessageBox(parent=None)
356
- msgBox.addButton(QtWidgets.QMessageBox.Yes)
357
- msgBox.addButton(QtWidgets.QMessageBox.No)
358
- msgBox.setWindowTitle("Error")
359
- msgBox.setText(str(e) + " error happened when uninitializing the Detector.\nDo you still want to quit?")
360
- msgBox.setDefaultButton(QtWidgets.QMessageBox.Yes)
361
- ret = msgBox.exec()
362
- if ret == QtWidgets.QMessageBox.Yes:
363
- self.dockarea.parent().close()
364
-
365
- def set_enabled_grab_buttons(self, enable=False):
366
- """
367
- Set enable with parameter value :
368
- * **grab** button
369
- * **single** button
370
- * **save current** button
371
- * **save new** button
372
-
373
- =============== =========== ===========================
374
- **Parameters** **Type** **Description**
375
- enable boolean the default value to map
376
- =============== =========== ===========================
377
- """
378
- self.ui.grab_pb.setEnabled(enable)
379
- self.ui.single_pb.setEnabled(enable)
380
- self.ui.save_current_pb.setEnabled(enable)
381
- self.ui.save_new_pb.setEnabled(enable)
382
- # self.ui.settings_pb.setEnabled(enable)
383
-
384
- def set_enabled_Ini_buttons(self, enable=False):
385
- """
386
- Set enable :
387
- * **Detector** button
388
- * **Init Detector** button
389
- * **Quit** button
390
-
391
- with the given enable boolean value.
392
-
393
- =============== =========== ===================
394
- **Parameters** **Type** **Description**
395
- *enable* boolean the value to map
396
- =============== =========== ===================
397
- """
398
- self.ui.Detector_type_combo.setEnabled(enable)
399
- self.ui.IniDet_pb.setEnabled(enable)
400
- self.ui.Quit_pb.setEnabled(enable)
401
-
402
- ######################################
403
- # Methods for running the acquisition
404
-
405
- def init_det(self):
406
- self.ui.IniDet_pb.click()
407
-
408
- def ini_det_fun(self):
409
- """
410
- | If Init detector button checked, init the detector and connect the data detector, the data detector temp, the status and the update_settings signals to their corresponding function.
411
- | Once done start the detector linked thread.
412
- |
413
- | Else send the "close" thread command.
414
-
415
- See Also
416
- --------
417
- set_enabled_grab_buttons, daq_utils.ThreadCommand, DAQ_Detector
418
- """
419
- try:
420
- QtWidgets.QApplication.processEvents()
421
- if not self.ui.IniDet_pb.isChecked():
422
- self.set_enabled_grab_buttons(enable=False)
423
- self.ui.Ini_state_LED.set_as_false()
424
- self.initialized_state = False
425
-
426
- if hasattr(self, 'detector_thread'):
427
- self.command_detector.emit(ThreadCommand("close"))
428
- QtWidgets.QApplication.processEvents()
429
- QThread.msleep(1000)
430
- if hasattr(self, 'detector_thread'):
431
- self.detector_thread.quit()
432
-
433
- self.initialized_state = False
434
- for dock in self.ui.viewer_docks:
435
- dock.setEnabled(False)
436
-
437
- else:
438
- self.detector_name = self.ui.Detector_type_combo.currentText()
439
-
440
- detector = DAQ_Detector(self.title, self.settings, self.detector_name)
441
- self.detector_thread = QThread()
442
- detector.moveToThread(self.detector_thread)
443
-
444
- self.command_detector[ThreadCommand].connect(detector.queue_command)
445
- detector.data_detector_sig[list].connect(self.show_data)
446
- detector.data_detector_temp_sig[list].connect(self.show_temp_data)
447
- detector.status_sig[ThreadCommand].connect(self.thread_status)
448
- self.update_settings_signal[edict].connect(detector.update_settings)
449
-
450
- self.detector_thread.detector = detector
451
- self.detector_thread.start()
452
-
453
- self.command_detector.emit(ThreadCommand("ini_detector", attributes=[
454
- self.settings.child(('detector_settings')).saveState(), self.controller]))
455
-
456
- for dock in self.ui.viewer_docks:
457
- dock.setEnabled(True)
458
-
459
- except Exception as e:
460
- self.logger.exception(str(e))
461
- self.set_enabled_grab_buttons(enable=False)
462
-
463
- def snap(self):
464
- self.ui.single_pb.click()
465
-
466
- def grab(self):
467
- self.ui.grab_pb.click()
468
-
469
- def snapshot(self, pathname=None, dosave=False, send_to_tcpip=False):
470
- """
471
- Do one single grab and save the data in pathname.
472
-
473
- =============== =========== =================================================
474
- **Parameters** **Type** **Description**
475
- *pathname* string the pathname to the location os the saved file
476
- =============== =========== =================================================
477
-
478
- See Also
479
- --------
480
- grab, update_status
481
- """
482
- try:
483
- self.do_save_data = dosave
484
- if pathname is None:
485
- raise (Exception("filepathanme has not been defined in snapshot"))
486
- self.save_file_pathname = pathname
487
-
488
- self.grab_data(False, send_to_tcpip=send_to_tcpip)
489
- except Exception as e:
490
- self.logger.exception(str(e))
491
-
492
- def grab_data(self, grab_state=False, send_to_tcpip=False):
493
- """
494
- Do a grab session using 2 profile :
495
- * if grab pb checked do a continous save and send an "update_channels" thread command and a "grab" too.
496
- * if not send a "stop_grab" thread command with settings "main settings-naverage" node value as an attribute.
497
-
498
- See Also
499
- --------
500
- daq_utils.ThreadCommand, set_enabled_Ini_buttons
501
- """
502
- self.send_to_tcpip = send_to_tcpip
503
- self.grab_done = False
504
- self.ui.data_ready_led.set_as_false()
505
- self.start_grab_time = time.perf_counter()
506
- if not (grab_state):
507
- self.update_status(f'{self.title}: Snap')
508
- self.command_detector.emit(
509
- ThreadCommand("single", [self.settings.child('main_settings', 'Naverage').value()]))
510
- else:
511
- if not (self.ui.grab_pb.isChecked()):
512
-
513
- self.update_status(f'{self.title}: Stop Grab')
514
- self.command_detector.emit(ThreadCommand("stop_grab"))
515
- self.set_enabled_Ini_buttons(enable=True)
516
- # self.ui.settings_tree.setEnabled(True)
517
- else:
518
-
519
- # self.ui.settings_tree.setEnabled(False)
520
- self.thread_status(ThreadCommand("update_channels"))
521
- self.set_enabled_Ini_buttons(enable=False)
522
- self.update_status(f'{self.title}: Continuous Grab')
523
- self.command_detector.emit(
524
- ThreadCommand("grab", [self.settings.child('main_settings', 'Naverage').value()]))
525
-
526
- def stop_all(self):
527
- self.update_status(f'{self.title}: Stop Grab')
528
- self.command_detector.emit(ThreadCommand("stop_all"))
529
- if self.ui.grab_pb.isChecked():
530
- self.ui.grab_pb.setChecked(False)
531
- self.set_enabled_Ini_buttons(enable=True)
532
-
533
- self.ui.settings_tree.setEnabled(True)
534
-
535
- def take_bkg(self):
536
- """
537
- Save a new file if bkg check button is on.
538
-
539
- See Also
540
- --------
541
- save_new
542
- """
543
- if self.ui.take_bkg_cb.isChecked():
544
- self.snap()
545
-
546
- def stop(self):
547
- self.ui.stop_pb.click()
548
-
549
- @Slot()
550
- def raise_timeout(self):
551
- """
552
- Print the "timeout occured" error message in the status bar via the update_status method.
553
-
554
- See Also
555
- --------
556
- update_status
557
- """
558
- self.update_status("Timeout occured", wait_time=self.wait_time, log_type="log")
559
-
560
-
561
- ############ LOADING SAVING
562
- ###########################
563
- ###### LOADING ##########
564
-
565
- def load_data(self):
566
-
567
- """
568
-
569
- """
570
- try:
571
- data = browse_data()
572
- datas = [OrderedDict(name='loaded data', data=[data], type='Data2D')]
573
- self.show_data(datas)
574
-
575
- except Exception as e:
576
- self.logger.exception(str(e))
577
-
578
- def load_settings(self, path=None):
579
- """
580
- to be checked to see if still working
581
- | Load settings contained in the pathname file (or select_file destination if path not defined).
582
- | Open a DAQ_type viewer instance (0D, 1D or 2D), send a data_to_save_export signal and restore state from the loaeded settings.
583
-
584
- =============== ========== =======================================
585
- **Parameters** **Type** **Description**
586
- *path* string the pathname of the file to be loaded
587
- =============== ========== =======================================
588
-
589
- See Also
590
- --------
591
- ini_det_fun, update_status
592
- """
593
- try:
594
- if self.ui.Ini_state_LED.state: # means initialzed
595
- self.ui.IniDet_pb.setChecked(False)
596
- QtWidgets.QApplication.processEvents()
597
- self.ini_det_fun()
598
-
599
- if path is None or path is False:
600
- path = select_file(start_path=Path.home(), save=False, ext='par')
601
- with open(str(path), 'rb') as f:
602
- settings = pickle.load(f)
603
- settings_main = settings['settings_main']
604
- DAQ_type = settings_main['children']['main_settings']['children']['DAQ_type']['value']
605
- if DAQ_type != self.settings.child('main_settings', 'DAQ_type'):
606
- self.settings.child('main_settings', 'DAQ_type').setValue(DAQ_type)
607
- QtWidgets.QApplication.processEvents()
608
-
609
- self.settings.restoreState(settings_main)
610
-
611
- settings_viewer = settings['settings_viewer']
612
- if self.DAQ_type != 'DAQ0D':
613
- self.ui.viewers[0].roi_manager.settings.restoreState(settings_viewer)
614
-
615
- except Exception as e:
616
- self.logger.exception(str(e))
617
-
618
- ####### SAVING########
619
-
620
- def set_continuous_save(self):
621
- """
622
- Set a continous save file using the base path located file with
623
- a header-name containing date as a string.
624
-
625
- See Also
626
- --------
627
- daq_utils.set_current_scan_path
628
- """
629
- if self.h5saver_continuous.settings.child(('do_save')).value():
630
- self.do_continuous_save = True
631
- self.is_continuous_initialized = False
632
- self.h5saver_continuous.settings.child(('base_name')).setValue('Data')
633
- self.h5saver_continuous.settings.child(('N_saved')).show()
634
- self.h5saver_continuous.settings.child(('N_saved')).setValue(0)
635
- self.h5saver_continuous.init_file(update_h5=True)
636
-
637
- settings_str = ioxml.parameter_to_xml_string(self.settings)
638
- settings_str = b'<All_settings>' + settings_str
639
- if hasattr(self.ui.viewers[0], 'roi_manager'):
640
- settings_str += ioxml.parameter_to_xml_string(self.ui.viewers[0].roi_manager.settings)
641
- settings_str += ioxml.parameter_to_xml_string(self.h5saver_continuous.settings) + b'</All_settings>'
642
- self.scan_continuous_group = self.h5saver_continuous.add_scan_group("Continuous Saving")
643
- self.continuous_group = self.h5saver_continuous.add_det_group(self.scan_continuous_group,
644
- "Continuous saving", settings_str)
645
- self.h5saver_continuous.h5_file.flush()
646
- else:
647
- self.do_continuous_save = False
648
- self.h5saver_continuous.settings.child(('N_saved')).hide()
649
-
650
- try:
651
- self.h5saver_continuous.close()
652
- except Exception as e:
653
- self.logger.exception(str(e))
654
-
655
- def do_save_continuous(self, datas):
656
- """
657
- method used to perform continuous saving of data, for instance for logging. Will save datas as a function of
658
- time in a h5 file set when *continuous_saving* parameter as been set.
659
-
660
- Parameters
661
- ----------
662
- datas: list of OrderedDict as exported by detector plugins
663
-
664
- """
665
- try:
666
- # init the enlargeable arrays
667
- if not self.is_continuous_initialized:
668
- self.channel_arrays = OrderedDict([])
669
- self.ini_time = time.perf_counter()
670
- self.time_array = self.h5saver_continuous.add_navigation_axis(np.array([0.0, ]),
671
- self.scan_continuous_group, 'x_axis',
672
- enlargeable=True,
673
- title='Time axis',
674
- metadata=dict(nav_index=0,
675
- label='Time axis',
676
- units='second'))
677
-
678
- data_dims = ['data0D', 'data1D']
679
- if self.h5saver_continuous.settings.child('save_2D').value():
680
- data_dims.extend(['data2D', 'dataND'])
681
-
682
- if self.bkg is not None and self.is_bkg:
683
- bkg_container = OrderedDict([])
684
- self.process_data(self.bkg, bkg_container)
685
-
686
- for data_dim in data_dims:
687
- if data_dim in datas.keys() and len(datas[data_dim]) != 0:
688
- if not self.h5saver_continuous.is_node_in_group(self.continuous_group, data_dim):
689
- self.channel_arrays[data_dim] = OrderedDict([])
690
-
691
- data_group = self.h5saver_continuous.add_data_group(self.continuous_group, data_dim)
692
- for ind_channel, channel in enumerate(datas[data_dim]): # list of OrderedDict
693
-
694
- channel_group = self.h5saver_continuous.add_CH_group(data_group, title=channel)
695
- self.channel_arrays[data_dim]['parent'] = channel_group
696
- if self.bkg is not None and self.is_bkg:
697
- if channel in bkg_container[data_dim]:
698
- datas[data_dim][channel]['bkg'] = bkg_container[data_dim][channel]['data']
699
- datas[data_dim][channel]['data'] =\
700
- utils.ensure_ndarray(datas[data_dim][channel]['data'])
701
- self.channel_arrays[data_dim][channel] = \
702
- self.h5saver_continuous.add_data(channel_group, datas[data_dim][channel],
703
- scan_type='scan1D', enlargeable=True)
704
- self.is_continuous_initialized = True
705
-
706
- dt = np.array([time.perf_counter() - self.ini_time])
707
- self.time_array.append(dt)
708
-
709
- data_dims = ['data0D', 'data1D']
710
- if self.h5saver_continuous.settings.child('save_2D').value():
711
- data_dims.extend(['data2D', 'dataND'])
712
-
713
- for data_dim in data_dims:
714
- if data_dim in datas.keys() and len(datas[data_dim]) != 0:
715
- for ind_channel, channel in enumerate(datas[data_dim]):
716
- if isinstance(datas[data_dim][channel]['data'], float) or isinstance(
717
- datas[data_dim][channel]['data'], int):
718
- datas[data_dim][channel]['data'] = np.array([datas[data_dim][channel]['data']])
719
- self.channel_arrays[data_dim][channel].append(datas[data_dim][channel]['data'])
720
-
721
- self.h5saver_continuous.h5_file.flush()
722
- self.h5saver_continuous.settings.child('N_saved').setValue(
723
- self.h5saver_continuous.settings.child('N_saved').value() + 1)
724
-
725
- except Exception as e:
726
- self.logger.exception(str(e))
727
-
728
- def save_current(self):
729
- """
730
-
731
-
732
- See Also
733
- --------
734
- gutils.select_file, save_export_data
735
- """
736
- self.do_save_data = True
737
- self.save_file_pathname = select_file(start_path=self.save_file_pathname, save=True,
738
- ext='h5') # see daq_utils
739
- self.save_export_data(self.data_to_save_export)
740
-
741
- def save_new(self):
742
- """
743
- Do a new save from the select_file obtained pathname into a h5 file structure.
744
-
745
- See Also
746
- --------
747
- gutils.select_file, snapshot
748
- """
749
- self.do_save_data = True
750
- self.save_file_pathname = select_file(start_path=self.save_file_pathname, save=True,
751
- ext='h5') # see daq_utils
752
- self.snapshot(pathname=self.save_file_pathname, dosave=True)
753
-
754
- def save_datas(self, path=None, datas=None):
755
- """
756
- Save procedure of .h5 file data.
757
- Course the data array and with :
758
- * **0D data** : store corresponding datas in a h5 file group (a node of the h5 tree)
759
- * **1D data** : store corresponding datas in a h5 file group (a node of the h5 tree) with a special array for x_axis values
760
- * **2D data** : store corresponding datas in a h5 file group (a node of the h5 tree) with a special array for x_axis and y_axis values.
761
-
762
- =============== ============= ========================================
763
- **Parameters** **Type** **Description**
764
- *path* string the path name of the file to be saved.
765
- *datas* dictionnary the raw datas to save.
766
- =============== ============= ========================================
767
- """
768
- if path is not None:
769
- path = Path(path)
770
- h5saver = H5Saver(save_type='detector')
771
- h5saver.init_file(update_h5=True, custom_naming=False, addhoc_file_path=path)
772
-
773
- settings_str = b'<All_settings>' + ioxml.parameter_to_xml_string(self.settings)
774
- if hasattr(self.ui.viewers[0], 'roi_manager'):
775
- settings_str += ioxml.parameter_to_xml_string(self.ui.viewers[0].roi_manager.settings)
776
- settings_str += ioxml.parameter_to_xml_string(h5saver.settings)
777
- settings_str += b'</All_settings>'
778
-
779
- det_group = h5saver.add_det_group(h5saver.raw_group, "Data", settings_str)
780
- if 'external_h5' in datas:
781
- try:
782
- external_group = h5saver.add_group('external_data', 'external_h5', det_group)
783
- if not datas['external_h5'].isopen:
784
- h5saver = H5Saver()
785
- h5saver.init_file(addhoc_file_path=datas['external_h5'].filename)
786
- h5_file = h5saver.h5_file
787
- else:
788
- h5_file = datas['external_h5']
789
- h5_file.copy_children(h5_file.get_node('/'), external_group, recursive=True)
790
- h5_file.flush()
791
- h5_file.close()
792
-
793
- except Exception as e:
794
- self.logger.exception(str(e))
795
- try:
796
- self.channel_arrays = OrderedDict([])
797
- data_dims = ['data1D'] # we don't recrod 0D data in this mode (only in continuous)
798
- if h5saver.settings.child(('save_2D')).value():
799
- data_dims.extend(['data2D', 'dataND'])
800
-
801
- if self.bkg is not None and self.is_bkg:
802
- bkg_container = OrderedDict([])
803
- self.process_data(self.bkg, bkg_container)
804
-
805
- for data_dim in data_dims:
806
- if datas[data_dim] is not None:
807
- if data_dim in datas.keys() and len(datas[data_dim]) != 0:
808
- if not h5saver.is_node_in_group(det_group, data_dim):
809
- self.channel_arrays[data_dim] = OrderedDict([])
810
-
811
- data_group = h5saver.add_data_group(det_group, data_dim)
812
- for ind_channel, channel in enumerate(datas[data_dim]): # list of OrderedDict
813
-
814
- channel_group = h5saver.add_CH_group(data_group, title=channel)
815
-
816
- self.channel_arrays[data_dim]['parent'] = channel_group
817
- if self.bkg is not None and self.is_bkg:
818
- if channel in bkg_container[data_dim]:
819
- datas[data_dim][channel]['bkg'] = bkg_container[data_dim][channel]['data']
820
- self.channel_arrays[data_dim][channel] = h5saver.add_data(channel_group,
821
- datas[data_dim][channel],
822
- scan_type='',
823
- enlargeable=False)
824
-
825
- if data_dim == 'data2D' and 'Data2D' in self.viewer_types:
826
- ind_viewer = self.viewer_types.index('Data2D')
827
- string = pymodaq.daq_utils.gui_utils.utils.widget_to_png_to_bytes(self.ui.viewers[ind_viewer].parent)
828
- self.channel_arrays[data_dim][channel].attrs['pixmap2D'] = string
829
- except Exception as e:
830
- self.logger.exception(str(e))
831
-
832
- try:
833
- (root, filename) = os.path.split(str(path))
834
- filename, ext = os.path.splitext(filename)
835
- image_path = os.path.join(root, filename + '.png')
836
- self.dockarea.parent().grab().save(image_path)
837
- except Exception as e:
838
- self.logger.exception(str(e))
839
-
840
- h5saver.close_file()
841
-
842
- @Slot(OrderedDict)
843
- def save_export_data(self, datas):
844
- """
845
- Store in data_to_save_export buffer the data to be saved and do save at self.snapshot_pathname.
846
-
847
- ============== ============= ======================
848
- **Parameters** **Type** **Description**
849
- *datas* dictionnary the data to be saved
850
- ============== ============= ======================
851
-
852
- See Also
853
- --------
854
- save_datas
855
- """
856
-
857
- if self.do_save_data:
858
- self.save_datas(self.save_file_pathname, datas)
859
- self.do_save_data = False
860
-
861
- def save_settings(self, path=None):
862
- """
863
- | Save the current viewer settings.
864
- | In case of Region Of Interest setting, save the current viewer state.
865
- | Then dump setting if the QDialog has been cancelled.
866
-
867
- ============== ========= ======================================
868
- **Parameters** **Type** **Description**
869
- path string the pathname of the file to be saved.
870
- ============== ========= ======================================
871
-
872
- See Also
873
- --------
874
- gutils.select_file, update_status
875
- """
876
- try:
877
- if path is None or path is False:
878
- path = select_file(start_path=Path.home(), save=True, ext='par')
879
-
880
- settings_main = self.settings.saveState()
881
- if self.DAQ_type != 'DAQ0D':
882
- settings_viewer = self.ui.viewers[0].roi_manager.settings.saveState()
883
- else:
884
- settings_viewer = None
885
-
886
- settings = OrderedDict(settings_main=settings_main, settings_viewer=settings_viewer)
887
-
888
- if path is not None: # could be if the Qdialog has been canceled
889
- with open(str(path), 'wb') as f:
890
- pickle.dump(settings, f, pickle.HIGHEST_PROTOCOL)
891
-
892
- except Exception as e:
893
- self.logger.exception(str(e))
894
-
895
- ######################
896
- # ### DATAMANAGEMENT
897
-
898
- @Slot(OrderedDict)
899
- def get_data_from_viewer(self, datas):
900
- """
901
- Emit the grab done signal with datas as an attribute.
902
-
903
- =============== ===================== ===================
904
- **Parameters** **Type** **Description**
905
- *datas* ordered dictionnary the datas to show
906
- =============== ===================== ===================
907
- """
908
- # datas=OrderedDict(name=self.title,data0D=None,data1D=None,data2D=None)
909
- if self.data_to_save_export is not None: # means that somehow datas are not initialized so no further procsessing
910
- self.received_data += 1
911
- for key in datas:
912
- if not (key == 'name' or key == 'acq_time_s'):
913
- if datas[key] is not None:
914
- if self.data_to_save_export[key] is None:
915
- self.data_to_save_export[key] = OrderedDict([])
916
- for k in datas[key]:
917
- if datas[key][k]['source'] != 'raw':
918
- name = f'{self.title}_{datas["name"]}_{k}'
919
- self.data_to_save_export[key][name] = utils.DataToExport(**datas[key][k])
920
- # if name not in self.data_to_save_export[key]:
921
- #
922
- # self.data_to_save_export[key][name].update(datas[key][k])
923
-
924
- if self.received_data == len(self.ui.viewers):
925
- if self.do_continuous_save:
926
- self.do_save_continuous(self.data_to_save_export)
927
-
928
- self.grab_done = True
929
- self.grab_done_signal.emit(self.data_to_save_export)
930
-
931
- def set_datas_to_viewers(self, datas, temp=False):
932
- for ind, data in enumerate(datas):
933
- self.ui.viewers[ind].title = data['name']
934
- if data['name'] != '':
935
- self.ui.viewer_docks[ind].setTitle(self.title + ' ' + data['name'])
936
- if data['dim'].lower() != 'datand':
937
- self.set_xy_axis(data, ind)
938
-
939
- if data['dim'] == 'Data0D':
940
- if 'labels' in data.keys():
941
- self.ui.viewers[ind].labels = data['labels']
942
- if temp:
943
- self.ui.viewers[ind].show_data_temp(data['data'])
944
- else:
945
- self.ui.viewers[ind].show_data(data['data'])
946
-
947
- elif data['dim'] == 'Data1D':
948
- if 'labels' in data.keys():
949
- self.ui.viewers[ind].labels = data['labels']
950
- if temp:
951
- self.ui.viewers[ind].show_data_temp(data['data'])
952
- else:
953
- self.ui.viewers[ind].show_data(data['data'])
954
-
955
- elif data['dim'] == 'Data2D':
956
- if temp:
957
- self.ui.viewers[ind].show_data_temp(data)
958
- else:
959
- self.ui.viewers[ind].show_data(data)
960
-
961
- else:
962
- if 'nav_axes' in data.keys():
963
- nav_axes = data['nav_axes']
964
- else:
965
- nav_axes = None
966
-
967
- kwargs = dict()
968
- if 'nav_x_axis' in data.keys():
969
- kwargs['nav_x_axis'] = data['nav_x_axis']
970
- if 'nav_y_axis' in data.keys():
971
- kwargs['nav_y_axis'] = data['nav_y_axis']
972
- if 'x_axis' in data.keys():
973
- kwargs['x_axis'] = data['x_axis']
974
- if 'y_axis' in data.keys():
975
- kwargs['y_axis'] = data['y_axis']
976
-
977
- if isinstance(data['data'], list):
978
- dat = data['data'][0]
979
- else:
980
- dat = data['data']
981
-
982
- if temp:
983
- self.ui.viewers[ind].show_data_temp(dat, nav_axes=nav_axes, **kwargs)
984
- else:
985
- self.ui.viewers[ind].show_data(dat, nav_axes=nav_axes, **kwargs)
986
-
987
- def init_show_data(self, datas):
988
- self.process_overshoot(datas)
989
- data_dims = [data['dim'] for data in datas]
990
- if data_dims != self.viewer_types:
991
- self.update_viewer_pannels(data_dims)
992
-
993
- def process_data(self, datas, container):
994
-
995
- data0D = OrderedDict([])
996
- data1D = OrderedDict([])
997
- data2D = OrderedDict([])
998
- dataND = OrderedDict([])
999
-
1000
- for ind_data, data in enumerate(datas):
1001
- if 'external_h5' in data.keys():
1002
- container['external_h5'] = data.pop('external_h5')
1003
- data_tmp = copy.deepcopy(data)
1004
- data_dim = data_tmp['dim']
1005
- if data_dim.lower() != 'datand':
1006
- self.set_xy_axis(data_tmp, ind_data)
1007
- data_arrays = data_tmp.pop('data')
1008
-
1009
- name = data_tmp.pop('name')
1010
- for ind_sub_data, dat in enumerate(data_arrays):
1011
- if 'labels' in data_tmp:
1012
- data_tmp.pop('labels')
1013
- subdata_tmp = utils.DataToExport(name=self.title, data=dat, **data_tmp)
1014
- sub_name = f'{self.title}_{name}_CH{ind_sub_data:03}'
1015
- if data_dim.lower() == 'data0d':
1016
- subdata_tmp['data'] = subdata_tmp['data'][0]
1017
- data0D[sub_name] = subdata_tmp
1018
- elif data_dim.lower() == 'data1d':
1019
- if 'x_axis' not in subdata_tmp:
1020
- Nx = len(dat)
1021
- x_axis = utils.Axis(data=np.linspace(0, Nx - 1, Nx))
1022
- subdata_tmp['x_axis'] = x_axis
1023
- data1D[sub_name] = subdata_tmp
1024
- elif data_dim.lower() == 'data2d':
1025
- if 'x_axis' not in subdata_tmp:
1026
- Nx = dat.shape[1]
1027
- x_axis = utils.Axis(data=np.linspace(0, Nx - 1, Nx))
1028
- subdata_tmp['x_axis'] = x_axis
1029
- if 'y_axis' not in subdata_tmp:
1030
- Ny = dat.shape[0]
1031
- y_axis = utils.Axis(data=np.linspace(0, Ny - 1, Ny))
1032
- subdata_tmp['y_axis'] = y_axis
1033
- data2D[sub_name] = subdata_tmp
1034
- elif data_dim.lower() == 'datand':
1035
- dataND[sub_name] = subdata_tmp
1036
-
1037
- container['data0D'] = data0D
1038
- container['data1D'] = data1D
1039
- container['data2D'] = data2D
1040
- container['dataND'] = dataND
1041
-
1042
- @Slot(list)
1043
- def show_data(self, datas: List[utils.DataFromPlugins]):
1044
- """
1045
-
1046
- """
1047
- try:
1048
- if self.settings.child('main_settings', 'tcpip', 'tcp_connected').value() and self.send_to_tcpip:
1049
- self.command_tcpip.emit(ThreadCommand('data_ready', datas))
1050
-
1051
- self.ui.data_ready_led.set_as_true()
1052
- self.init_show_data(datas)
1053
-
1054
- if self.settings.child('main_settings', 'live_averaging').value():
1055
- self.settings.child('main_settings', 'N_live_averaging').setValue(self.ind_continuous_grab)
1056
- # #self.ui.current_Naverage.setValue(self.ind_continuous_grab)
1057
- self.ind_continuous_grab += 1
1058
- if self.ind_continuous_grab > 1:
1059
- try:
1060
- for ind, dic in enumerate(datas):
1061
- dic['data'] = [((self.ind_continuous_grab - 1) * self.current_datas[ind]['data'][
1062
- ind_channel] + dic['data'][ind_channel]) / self.ind_continuous_grab for ind_channel in
1063
- range(len(dic['data']))]
1064
- except Exception as e:
1065
- self.logger.exception(str(e))
1066
-
1067
- # store raw data for further processing
1068
- Ndatas = len(datas)
1069
- acq_time = datetime.datetime.now().timestamp()
1070
- name = self.title
1071
- self.data_to_save_export = OrderedDict(Ndatas=Ndatas, acq_time_s=acq_time, name=name)
1072
-
1073
- self.process_data(datas, self.data_to_save_export)
1074
-
1075
- if self.ui.take_bkg_cb.isChecked():
1076
- self.ui.take_bkg_cb.setChecked(False)
1077
- self.bkg = copy.deepcopy(datas)
1078
- # process bkg if needed
1079
- if self.is_bkg and self.bkg is not None:
1080
- try:
1081
- for ind_channels, channels in enumerate(datas):
1082
- for ind_channel, channel in enumerate(channels['data']):
1083
- datas[ind_channels]['data'][ind_channel] -= self.bkg[ind_channels]['data'][ind_channel]
1084
- except Exception as e:
1085
- self.logger.exception(str(e))
1086
-
1087
- if self.ui.grab_pb.isChecked(): # if live
1088
- refresh = time.perf_counter() - self.start_grab_time > self.settings.child('main_settings',
1089
- 'refresh_time').value() /\
1090
- 1000
1091
- if refresh:
1092
- self.start_grab_time = time.perf_counter()
1093
- else:
1094
- refresh = True # if single
1095
- if self.settings.child('main_settings', 'show_data').value() and refresh:
1096
- self.received_data = 0 # so that data send back from viewers can be properly counted
1097
- self.set_datas_to_viewers(datas)
1098
- else:
1099
- if self.do_continuous_save:
1100
- self.do_save_continuous(self.data_to_save_export)
1101
-
1102
- self.grab_done = True
1103
- self.grab_done_signal.emit(self.data_to_save_export)
1104
-
1105
- self.current_datas = datas
1106
-
1107
- except Exception as e:
1108
- self.logger.exception(str(e))
1109
-
1110
- @Slot(list)
1111
- def show_temp_data(self, datas):
1112
- """
1113
- | Show the given datas in the different pannels but do not send processed datas signal.
1114
-
1115
- =============== ====================== ========================
1116
- **Parameters** **Type** **Description**
1117
- datas list of OrderedDict the datas to be showed.
1118
- =============== ====================== ========================
1119
-
1120
- """
1121
- self.init_show_data(datas)
1122
- self.set_datas_to_viewers(datas, temp=True)
1123
-
1124
- @property
1125
- def viewers(self):
1126
- return self.ui.viewers
1127
-
1128
- def update_viewer_pannels(self, data_dims=['Data0D']):
1129
- Nviewers = len(data_dims)
1130
-
1131
- self.settings.child('main_settings', 'Nviewers').setValue(Nviewers)
1132
-
1133
- # check if viewers are compatible with new data type
1134
- N = 0
1135
- for ind, data_dim in enumerate(data_dims):
1136
- if len(self.viewer_types) > ind:
1137
- if data_dim == self.viewer_types[ind]:
1138
- N += 1
1139
- else:
1140
- break
1141
- else:
1142
- break
1143
-
1144
- while len(self.ui.viewers) > N: # remove all viewers after index N
1145
- # #while len(self.ui.viewers)>Nviewers:
1146
- self.ui.viewers.pop()
1147
- widget = self.viewer_widgets.pop()
1148
- widget.close()
1149
- dock = self.ui.viewer_docks.pop()
1150
- dock.close()
1151
- QtWidgets.QApplication.processEvents()
1152
- # #for ind,data_dim in enumerate(data_dims):
1153
- ind_loop = 0
1154
- Nviewers_init = len(self.ui.viewers)
1155
- while len(self.ui.viewers) < len(data_dims):
1156
- data_dim = data_dims[Nviewers_init + ind_loop]
1157
- ind_loop += 1
1158
- if data_dim == "Data0D":
1159
- self.viewer_widgets.append(QtWidgets.QWidget())
1160
- self.ui.viewers.append(Viewer0D(self.viewer_widgets[-1]))
1161
- elif data_dim == "Data1D":
1162
- self.viewer_widgets.append(QtWidgets.QWidget())
1163
- self.ui.viewers.append(Viewer1D(self.viewer_widgets[-1]))
1164
- elif data_dim == "Data2D":
1165
- self.viewer_widgets.append(QtWidgets.QWidget())
1166
- self.ui.viewers.append(Viewer2D(self.viewer_widgets[-1]))
1167
- self.ui.viewers[-1].set_scaling_axes(self.get_scaling_options())
1168
- self.ui.viewers[-1].get_action('autolevels').trigger()
1169
-
1170
- else: # for multideimensional data 0 up to dimension 4
1171
- self.viewer_widgets.append(QtWidgets.QWidget())
1172
- self.ui.viewers.append(ViewerND(self.viewer_widgets[-1]))
1173
- self.ui.viewers[-1].status_signal.connect(self.log_messages)
1174
-
1175
- self.ui.viewer_docks.append(
1176
- Dock(self.title + "_Viewer {:d}".format(len(self.ui.viewer_docks) + 1), size=(500, 300),
1177
- closable=False))
1178
- self.ui.viewer_docks[-1].addWidget(self.viewer_widgets[-1])
1179
- if ind == 0:
1180
- self.dockarea.addDock(self.ui.viewer_docks[-1], 'right', self.ui.settings_dock)
1181
- else:
1182
- self.dockarea.addDock(self.ui.viewer_docks[-1], 'right', self.ui.viewer_docks[-2])
1183
- self.ui.viewers[-1].data_to_export_signal.connect(self.get_data_from_viewer)
1184
- QtWidgets.QApplication.processEvents()
1185
-
1186
- self.viewer_types = [viewer.viewer_type for viewer in self.ui.viewers]
1187
- QtWidgets.QApplication.processEvents()
1188
-
1189
- #####################
1190
- ##### PROCESS CHANGES
1191
- #####################
1192
-
1193
- def log_messages(self, txt):
1194
- self.status_signal.emit(txt)
1195
- self.logger.info(txt)
1196
-
1197
- def update_status(self, txt, wait_time=0, log=True):
1198
- """
1199
- | Show the given txt message in the status bar with a delay of wait_time ms.
1200
- | Emit a log signal if log_type parameter is defined.
1201
-
1202
- =============== =========== =====================================
1203
- **Parameters** **Type** **Description**
1204
- *txt* string the message to show
1205
- *wait_time* int the delay of showwing
1206
- *log_type* string the type of the log signal to emit
1207
- =============== =========== =====================================
1208
- """
1209
- self.ui.statusbar.showMessage(txt, wait_time)
1210
- self.status_signal.emit(txt)
1211
- if log:
1212
- self.logger.info(txt)
1213
-
1214
- def parameter_tree_changed(self, param, changes):
1215
- """
1216
- Foreach value changed, update :
1217
- * Viewer in case of **DAQ_type** parameter name
1218
- * visibility of button in case of **show_averaging** parameter name
1219
- * visibility of naverage in case of **live_averaging** parameter name
1220
- * scale of axis **else** (in 2D pymodaq type)
1221
-
1222
- Once done emit the update settings signal to link the commit.
1223
-
1224
- =============== =================================== ================================================================
1225
- **Parameters** **Type** **Description**
1226
- *param* instance of ppyqtgraph parameter the parameter to be checked
1227
- *changes* tuple list Contain the (param,changes,info) list listing the changes made
1228
- =============== =================================== ================================================================
1229
-
1230
- See Also
1231
- --------
1232
- change_viewer,
1233
- """
1234
-
1235
- for param, change, data in changes:
1236
- path = self.settings.childPath(param)
1237
- if change == 'childAdded':
1238
- if 'main_settings' not in path:
1239
- self.update_settings_signal.emit(edict(path=path, param=data[0].saveState(), change=change))
1240
-
1241
- elif change == 'value':
1242
- if param.name() == 'DAQ_type':
1243
- self.DAQ_type = param.value()
1244
- self.change_viewer()
1245
- self.h5saver_continuous.settings.child('do_save').setValue(False)
1246
- if param.value() == 'DAQ2D':
1247
- self.settings.child('main_settings', 'axes').show()
1248
- else:
1249
- self.settings.child('main_settings', 'axes').hide()
1250
- # elif param.name()=='Nviewers': #this parameter is readonly it is updated from the number of items in the data list sent to show_data
1251
- # self.update_viewer_pannels(param.value())
1252
- elif param.name() == 'show_averaging':
1253
- self.settings.child('main_settings', 'live_averaging').setValue(False)
1254
- self.update_settings_signal.emit(edict(path=path, param=param, change=change))
1255
-
1256
- elif param.name() == 'live_averaging':
1257
- self.settings.child('main_settings', 'show_averaging').setValue(False)
1258
- if param.value():
1259
- self.settings.child('main_settings', 'N_live_averaging').show()
1260
- self.ind_continuous_grab = 0
1261
- self.settings.child('main_settings', 'N_live_averaging').setValue(0)
1262
- else:
1263
- self.settings.child('main_settings', 'N_live_averaging').hide()
1264
- elif param.name() in putils.iter_children(self.settings.child('main_settings', 'axes'), []):
1265
- if self.DAQ_type == "DAQ2D":
1266
- if param.name() == 'use_calib':
1267
- if param.value() != 'None':
1268
- params = ioxml.XML_file_to_parameter(
1269
- os.path.join(local_path, 'camera_calibrations', param.value() + '.xml'))
1270
- param_obj = Parameter.create(name='calib', type='group', children=params)
1271
- self.settings.child('main_settings', 'axes').restoreState(
1272
- param_obj.child(('axes')).saveState(), addChildren=False, removeChildren=False)
1273
- self.settings.child('main_settings', 'axes').show()
1274
- else:
1275
- for viewer in self.ui.viewers:
1276
- viewer.set_scaling_axes(self.get_scaling_options())
1277
- elif param.name() in putils.iter_children(self.settings.child('detector_settings', 'ROIselect'),
1278
- []) and 'ROIselect' in param.parent().name(): # to be sure
1279
- # a param named 'y0' for instance will not collide with the y0 from the ROI
1280
- if self.DAQ_type == "DAQ2D":
1281
- try:
1282
- self.ui.viewers[0].ROI_select_signal.disconnect(self.update_ROI)
1283
- except Exception as e:
1284
- self.logger.exception(str(e))
1285
- if self.settings.child('detector_settings', 'ROIselect', 'use_ROI').value():
1286
- if not self.ui.viewers[0].is_action_checked('ROIselect'):
1287
- self.ui.viewers[0].get_action('ROIselect').trigger()
1288
- QtWidgets.QApplication.processEvents()
1289
- self.ui.viewers[0].ROIselect.setPos(
1290
- self.settings.child('detector_settings', 'ROIselect', 'x0').value(),
1291
- self.settings.child('detector_settings', 'ROIselect', 'y0').value())
1292
- self.ui.viewers[0].ROIselect.setSize(
1293
- [self.settings.child('detector_settings', 'ROIselect', 'width').value(),
1294
- self.settings.child('detector_settings', 'ROIselect', 'height').value()])
1295
- self.ui.viewers[0].ROI_select_signal.connect(self.update_ROI)
1296
-
1297
- elif param.name() == 'continuous_saving_opt':
1298
- self.h5saver_continuous.settings_tree.setVisible(param.value())
1299
-
1300
- elif param.name() == 'do_save':
1301
- self.set_continuous_save()
1302
-
1303
- elif param.name() == 'wait_time':
1304
- self.command_detector.emit(ThreadCommand('update_wait_time', [param.value()]))
1305
-
1306
- elif param.name() == 'connect_server':
1307
- if param.value():
1308
- self.connect_tcp_ip()
1309
- else:
1310
- self.command_tcpip.emit(ThreadCommand('quit'))
1311
-
1312
- elif param.name() == 'ip_address' or param.name == 'port':
1313
- self.command_tcpip.emit(ThreadCommand('update_connection',
1314
- dict(ipaddress=self.settings.child('main_settings', 'tcpip',
1315
- 'ip_address').value(),
1316
- port=self.settings.child('main_settings', 'tcpip',
1317
- 'port').value())))
1318
-
1319
- if path is not None:
1320
- if 'main_settings' not in path:
1321
- self.update_settings_signal.emit(edict(path=path, param=param, change=change))
1322
-
1323
- if self.settings.child('main_settings', 'tcpip', 'tcp_connected').value():
1324
- self.command_tcpip.emit(ThreadCommand('send_info', dict(path=path, param=param)))
1325
-
1326
- elif change == 'parent':
1327
- if param.name() not in putils.iter_children(self.settings.child('main_settings'), []):
1328
- self.update_settings_signal.emit(edict(path=['detector_settings'], param=param, change=change))
1329
-
1330
- def set_setting_tree(self):
1331
- """
1332
- Set the local setting tree instance cleaning the current one and populate it with
1333
- standard options corresponding to the pymodaq type viewer (0D, 1D or 2D).
1334
-
1335
- See Also
1336
- --------
1337
- update_status
1338
- """
1339
- det_name = self.detector
1340
- if det_name == '':
1341
- det_name = 'Mock'
1342
- self.detector_name = det_name
1343
- self.settings.child('main_settings', 'detector_type').setValue(self.detector_name)
1344
- try:
1345
- if len(self.settings.child(('detector_settings')).children()) > 0:
1346
- for child in self.settings.child(('detector_settings')).children()[1:]:
1347
- # leave just the ROIselect group
1348
- child.remove()
1349
- plug_name = self.detector_name
1350
- if self.DAQ_type == 'DAQ0D':
1351
- parent_module = utils.find_dict_in_list_from_key_val(DAQ_0DViewer_Det_types, 'name', plug_name)
1352
- obj = getattr(getattr(parent_module['module'], 'daq_0Dviewer_' + self.detector_name),
1353
- 'DAQ_0DViewer_' + self.detector_name)
1354
- elif self.DAQ_type == "DAQ1D":
1355
- parent_module = utils.find_dict_in_list_from_key_val(DAQ_1DViewer_Det_types, 'name', plug_name)
1356
- obj = getattr(getattr(parent_module['module'], 'daq_1Dviewer_' + self.detector_name),
1357
- 'DAQ_1DViewer_' + self.detector_name)
1358
- elif self.DAQ_type == 'DAQ2D':
1359
- parent_module = utils.find_dict_in_list_from_key_val(DAQ_2DViewer_Det_types, 'name', plug_name)
1360
- obj = getattr(getattr(parent_module['module'], 'daq_2Dviewer_' + self.detector_name),
1361
- 'DAQ_2DViewer_' + self.detector_name)
1362
- elif self.DAQ_type == 'DAQND':
1363
- parent_module = utils.find_dict_in_list_from_key_val(DAQ_NDViewer_Det_types, 'name', plug_name)
1364
- obj = getattr(getattr(parent_module['module'], 'daq_NDviewer_' + self.detector_name),
1365
- 'DAQ_NDViewer_' + self.detector_name)
1366
-
1367
- params = getattr(obj, 'params')
1368
- det_params = Parameter.create(name='Det Settings', type='group', children=params)
1369
- self.settings.child(('detector_settings')).addChildren(det_params.children())
1370
- except Exception as e:
1371
- self.logger.exception(str(e))
1372
-
1373
- def process_overshoot(self, datas):
1374
- if self.settings.child('main_settings', 'overshoot', 'stop_overshoot').value():
1375
- for channels in datas:
1376
- for channel in channels['data']:
1377
- if any(channel >= self.settings.child('main_settings', 'overshoot', 'overshoot_value').value()):
1378
- self.overshoot_signal.emit(True)
1379
-
1380
- def change_viewer(self):
1381
- """
1382
- Change the viewer type from DAQ_Type value between :
1383
- * **DAQ0D** : a 0D instance of viewer
1384
- * **DAQ1D** : a 1D instance of viewer
1385
- * **DAQ2D** : a 2D instance of viewer
1386
-
1387
- ============== ========== ===========================================
1388
- **Parameters** **Type** **Description**
1389
- *DAQ_type* string Define the target dimension of the viewer
1390
- ============== ========== ===========================================
1391
- """
1392
- DAQ_type = self.settings.child('main_settings', 'DAQ_type').value()
1393
- Nviewers = self.settings.child('main_settings', 'Nviewers').value()
1394
-
1395
- if self.ui.IniDet_pb.isChecked():
1396
- self.ui.IniDet_pb.click()
1397
- QtWidgets.QApplication.processEvents()
1398
-
1399
- self.DAQ_type = DAQ_type
1400
- if hasattr(self.ui, 'viewers'): # this basically means we are at the initialization satge of the class
1401
- if self.ui.viewers != []:
1402
- for ind in range(Nviewers):
1403
- self.ui.viewers.pop()
1404
- widget = self.viewer_widgets.pop()
1405
- widget.close()
1406
- if len(self.ui.viewer_docks) > 1:
1407
- dock = self.ui.viewer_docks.pop()
1408
- dock.close()
1409
-
1410
- self.ui.viewers = []
1411
- self.viewer_widgets = []
1412
- self.viewer_types = []
1413
- if DAQ_type == "DAQ0D":
1414
- for ind in range(Nviewers):
1415
- self.viewer_widgets.append(QtWidgets.QWidget())
1416
- self.ui.viewers.append(Viewer0D(self.viewer_widgets[-1]))
1417
- self.detector_types = [plugin['name'] for plugin in DAQ_0DViewer_Det_types]
1418
-
1419
- elif DAQ_type == "DAQ1D":
1420
- for ind in range(Nviewers):
1421
- self.viewer_widgets.append(QtWidgets.QWidget())
1422
- self.ui.viewers.append(Viewer1D(self.viewer_widgets[-1]))
1423
- self.detector_types = [plugin['name'] for plugin in DAQ_1DViewer_Det_types]
1424
-
1425
- elif DAQ_type == "DAQ2D":
1426
- for ind in range(Nviewers):
1427
- self.viewer_widgets.append(QtWidgets.QWidget())
1428
- self.ui.viewers.append(Viewer2D(self.viewer_widgets[-1]))
1429
- self.ui.viewers[-1].set_scaling_axes(self.get_scaling_options())
1430
- self.ui.viewers[-1].get_action('autolevels').trigger()
1431
-
1432
- self.detector_types = [plugin['name'] for plugin in DAQ_2DViewer_Det_types]
1433
- self.settings.child('main_settings', 'axes').show()
1434
- self.ui.viewers[0].ROI_select_signal.connect(self.update_ROI)
1435
- self.ui.viewers[0].get_action('ROIselect').triggered.connect(self.show_ROI)
1436
-
1437
- elif DAQ_type == "DAQND":
1438
- for ind in range(Nviewers):
1439
- self.viewer_widgets.append(QtWidgets.QWidget())
1440
- self.ui.viewers.append(ViewerND(self.viewer_widgets[-1]))
1441
- self.detector_types = [plugin['name'] for plugin in DAQ_NDViewer_Det_types]
1442
-
1443
- self.viewer_types = [viewer.viewer_type for viewer in self.ui.viewers]
1444
-
1445
- for ind, viewer in enumerate(self.viewer_widgets):
1446
- if ind == 0:
1447
- self.dockarea.addDock(self.ui.viewer_docks[-1], 'right', self.ui.settings_dock)
1448
- else:
1449
- self.ui.viewer_docks.append(
1450
- Dock(self.title + "_Viewer {:d}".format(ind), size=(500, 300), closable=False))
1451
- self.dockarea.addDock(self.ui.viewer_docks[-1], 'right', self.ui.viewer_docks[-2])
1452
- self.ui.viewer_docks[-1].addWidget(viewer)
1453
- self.ui.viewers[ind].data_to_export_signal.connect(self.get_data_from_viewer)
1454
-
1455
- # #Setting detector types
1456
- try:
1457
- self.ui.Detector_type_combo.currentIndexChanged.disconnect(self.set_setting_tree)
1458
- except (TypeError, RuntimeError) as e:
1459
- pass # just means it wasn't connected yet
1460
-
1461
- self.ui.Detector_type_combo.clear()
1462
- self.ui.Detector_type_combo.addItems(self.detector_types)
1463
- self.ui.Detector_type_combo.currentIndexChanged.connect(self.set_setting_tree)
1464
- self.set_setting_tree()
1465
-
1466
- def get_scaling_options(self):
1467
- """
1468
- Return the initialized dictionnary containing the scaling options.
1469
-
1470
-
1471
- Returns
1472
- -------
1473
- dictionnary
1474
- scaling options dictionnary.
1475
-
1476
- """
1477
- scaling_options = utils.ScalingOptions(
1478
- scaled_xaxis=utils.ScaledAxis(label=self.settings.child('main_settings', 'axes', 'xaxis', 'xlabel').value(),
1479
- units=self.settings.child('main_settings', 'axes', 'xaxis', 'xunits').value(),
1480
- offset=self.settings.child('main_settings', 'axes', 'xaxis',
1481
- 'xoffset').value(),
1482
- scaling=self.settings.child('main_settings', 'axes', 'xaxis',
1483
- 'xscaling').value()),
1484
- scaled_yaxis=utils.ScaledAxis(label=self.settings.child('main_settings', 'axes', 'yaxis', 'ylabel').value(),
1485
- units=self.settings.child('main_settings', 'axes', 'yaxis', 'yunits').value(),
1486
- offset=self.settings.child('main_settings', 'axes', 'yaxis',
1487
- 'yoffset').value(),
1488
- scaling=self.settings.child('main_settings', 'axes', 'yaxis',
1489
- 'yscaling').value()))
1490
- return scaling_options
1491
-
1492
- def set_xy_axis(self, data, ind_viewer):
1493
- if 'x_axis' in data.keys():
1494
- self.ui.viewers[ind_viewer].x_axis = data['x_axis']
1495
- if self.settings.child('main_settings', 'tcpip', 'tcp_connected').value():
1496
- self.command_tcpip.emit(ThreadCommand('x_axis', [data['x_axis']]))
1497
-
1498
- if 'y_axis' in data.keys():
1499
- self.ui.viewers[ind_viewer].y_axis = data['y_axis']
1500
- if self.settings.child('main_settings', 'tcpip', 'tcp_connected').value():
1501
- self.command_tcpip.emit(ThreadCommand('y_axis', [data['y_axis']]))
1502
-
1503
- def show_settings(self):
1504
- """
1505
- Set the settings tree visible if the corresponding button is checked.
1506
- """
1507
-
1508
- if self.ui.settings_pb.isChecked():
1509
- self.ui.settings_widget.setVisible(True)
1510
- else:
1511
- self.ui.settings_widget.setVisible(False)
1512
-
1513
- @Slot(ThreadCommand)
1514
- def thread_status(self, status): # general function to get datas/infos from all threads back to the main
1515
- """
1516
- General function to get datas/infos from all threads back to the main.
1517
-
1518
- In case of :
1519
- * **Update_Status** *command* : update the status from the given status attributes
1520
- * **ini_detector** *command* : update the status with "detector initialized" value and init state if attributes not null.
1521
- * **close** *command* : close the current thread and delete corresponding attributes on cascade.
1522
- * **grab** *command* : Do nothing
1523
- * **x_axis** *command* : update x_axis from status attributes and User Interface viewer consequently.
1524
- * **y_axis** *command* : update y_axis from status attributes and User Interface viewer consequently.
1525
- * **Update_channel** *command* : update the viewer channels in case of 0D DAQ_type
1526
- * **Update_settings** *command* : Update the "detector setting" node in the settings tree.
1527
-
1528
- =============== ================ =======================================================
1529
- **Parameters** **Type** **Description**
1530
-
1531
- *status* ThreadCommand() instance of ThreadCommand containing two attributes:
1532
- * command : string
1533
- * attributes: list
1534
- =============== ================ =======================================================
1535
-
1536
- See Also
1537
- --------
1538
- update_status, set_enabled_grab_buttons, raise_timeout
1539
- """
1540
- if status.command == "Update_Status":
1541
- if len(status.attributes) > 1:
1542
- self.update_status(status.attributes[0], wait_time=self.wait_time, log=status.attributes[1])
1543
- else:
1544
- self.update_status(status.attributes[0], wait_time=self.wait_time)
1545
-
1546
- elif status.command == "ini_detector":
1547
- self.update_status("detector initialized: " + str(status.attributes[0]['initialized']),
1548
- wait_time=self.wait_time)
1549
-
1550
- if status.attributes[0]['initialized']:
1551
- self.controller = status.attributes[0]['controller']
1552
- self.set_enabled_grab_buttons(enable=True)
1553
- self.ui.Ini_state_LED.set_as_true()
1554
- self.initialized_state = True
1555
- else:
1556
- self.initialized_state = False
1557
- self.init_signal.emit(self.initialized_state)
1558
-
1559
- elif status.command == "close":
1560
- try:
1561
- self.update_status(status.attributes[0], wait_time=self.wait_time)
1562
- self.detector_thread.exit()
1563
- self.detector_thread.wait()
1564
- finished = self.detector_thread.isFinished()
1565
- if finished:
1566
- delattr(self, 'detector_thread')
1567
- else:
1568
- self.update_status('thread is locked?!', self.wait_time, 'log')
1569
- except Exception as e:
1570
- self.logger.exception(str(e))
1571
-
1572
- self.initialized_state = False
1573
- self.init_signal.emit(self.initialized_state)
1574
-
1575
- elif status.command == "grab":
1576
- pass
1577
-
1578
- elif status.command == "x_axis":
1579
- try:
1580
- x_axis = status.attributes[0]
1581
- if isinstance(x_axis, list):
1582
- if len(x_axis) == len(self.ui.viewers):
1583
- for ind, viewer in enumerate(self.ui.viewers):
1584
- viewer.x_axis = x_axis[ind]
1585
- x_axis = x_axis[0]
1586
- else:
1587
- for viewer in self.ui.viewers:
1588
- viewer.x_axis = x_axis
1589
-
1590
- if self.settings.child('main_settings', 'tcpip', 'tcp_connected').value():
1591
- self.command_tcpip.emit(ThreadCommand('x_axis', [x_axis]))
1592
-
1593
- except Exception as e:
1594
- self.logger.exception(str(e))
1595
-
1596
- elif status.command == "y_axis":
1597
- try:
1598
- y_axis = status.attributes[0]
1599
- if isinstance(y_axis, list):
1600
- if len(y_axis) == len(self.ui.viewers):
1601
- for ind, viewer in enumerate(self.ui.viewers):
1602
- viewer.y_axis = y_axis[ind]
1603
- y_axis = y_axis[0]
1604
- else:
1605
- for viewer in self.ui.viewers:
1606
- viewer.y_axis = y_axis
1607
-
1608
- if self.settings.child('main_settings', 'tcpip', 'tcp_connected').value():
1609
- self.command_tcpip.emit(ThreadCommand('y_axis', [y_axis]))
1610
-
1611
- except Exception as e:
1612
- self.logger.exception(str(e))
1613
-
1614
- elif status.command == "update_channels":
1615
- pass
1616
- # if self.DAQ_type=='DAQ0D':
1617
- # for viewer in self.ui.viewers:
1618
- # viewer.update_channels()
1619
-
1620
- elif status.command == 'update_main_settings':
1621
- # this is a way for the plugins to update main settings of the ui (solely values, limits and options)
1622
- try:
1623
- if status.attributes[2] == 'value':
1624
- self.settings.child('main_settings', *status.attributes[0]).setValue(status.attributes[1])
1625
- elif status.attributes[2] == 'limits':
1626
- self.settings.child('main_settings', *status.attributes[0]).setLimits(status.attributes[1])
1627
- elif status.attributes[2] == 'options':
1628
- self.settings.child('main_settings', *status.attributes[0]).setOpts(**status.attributes[1])
1629
- except Exception as e:
1630
- self.logger.exception(str(e))
1631
-
1632
- elif status.command == 'update_settings':
1633
- # using this the settings shown in the UI for the plugin reflects the real plugin settings
1634
- try:
1635
- self.settings.sigTreeStateChanged.disconnect(
1636
- self.parameter_tree_changed) # any changes on the detcetor settings will update accordingly the gui
1637
- except Exception as e:
1638
- self.logger.exception(str(e))
1639
- try:
1640
- if status.attributes[2] == 'value':
1641
- self.settings.child('detector_settings', *status.attributes[0]).setValue(status.attributes[1])
1642
- elif status.attributes[2] == 'limits':
1643
- self.settings.child('detector_settings', *status.attributes[0]).setLimits(status.attributes[1])
1644
- elif status.attributes[2] == 'options':
1645
- self.settings.child('detector_settings', *status.attributes[0]).setOpts(**status.attributes[1])
1646
- elif status.attributes[2] == 'childAdded':
1647
- child = Parameter.create(name='tmp')
1648
- child.restoreState(status.attributes[1][0])
1649
- self.settings.child('detector_settings', *status.attributes[0]).addChild(status.attributes[1][0])
1650
-
1651
- except Exception as e:
1652
- self.logger.exception(str(e))
1653
- self.settings.sigTreeStateChanged.connect(self.parameter_tree_changed)
1654
-
1655
- elif status.command == 'raise_timeout':
1656
- self.raise_timeout()
1657
-
1658
- elif status.command == 'show_splash':
1659
- self.ui.settings_tree.setEnabled(False)
1660
- self.splash_sc.show()
1661
- self.splash_sc.raise_()
1662
- self.splash_sc.showMessage(status.attributes[0], color=Qt.white)
1663
-
1664
- elif status.command == 'close_splash':
1665
- self.splash_sc.close()
1666
- self.ui.settings_tree.setEnabled(True)
1667
-
1668
- elif status.command == 'init_lcd':
1669
- if self.lcd is not None:
1670
- try:
1671
- self.lcd.parent.close()
1672
- except Exception as e:
1673
- self.logger.exception(str(e))
1674
- # lcd module
1675
- lcd = QtWidgets.QWidget()
1676
- self.lcd = LCD(lcd, **status.attributes[0])
1677
- lcd.setVisible(True)
1678
- QtWidgets.QApplication.processEvents()
1679
-
1680
- elif status.command == 'lcd':
1681
- self.lcd.setvalues(status.attributes[0])
1682
-
1683
- elif status.command == 'show_navigator':
1684
- show = True
1685
- if len(status.attributes) != 0:
1686
- show = status.attributes[0]
1687
- self.show_navigator(show)
1688
- QtWidgets.QApplication.processEvents()
1689
-
1690
- elif status.command == 'show_scanner':
1691
- show = True
1692
- if len(status.attributes) != 0:
1693
- show = status.attributes[0]
1694
- self.show_scanner(show)
1695
- QtWidgets.QApplication.processEvents()
1696
-
1697
- elif status.command == 'stop':
1698
- self.stop()
1699
-
1700
- self.custom_sig.emit(status) # to be used if needed in custom application connected to this module
1701
-
1702
- def update_com(self):
1703
- self.command_detector.emit(ThreadCommand('update_com', []))
1704
-
1705
- @Slot(pymodaq.daq_utils.scanner.ScanParameters)
1706
- def update_from_scanner(self, scan_parameters):
1707
- self.command_detector.emit(ThreadCommand('update_scanner', [scan_parameters]))
1708
-
1709
- def show_ROI(self):
1710
- if self.DAQ_type == "DAQ2D":
1711
- self.settings.child('detector_settings', 'ROIselect').setOpts(
1712
- visible=self.ui.viewers[0].is_action_checked('ROIselect'))
1713
- pos = self.ui.viewers[0].ROIselect.pos()
1714
- size = self.ui.viewers[0].ROIselect.size()
1715
- self.update_ROI(QRectF(pos[0], pos[1], size[0], size[1]))
1716
-
1717
- @Slot(QRectF)
1718
- def update_ROI(self, rect=QRectF(0, 0, 1, 1)):
1719
- if self.DAQ_type == "DAQ2D":
1720
- self.settings.child('detector_settings', 'ROIselect', 'x0').setValue(int(rect.x()))
1721
- self.settings.child('detector_settings', 'ROIselect', 'y0').setValue(int(rect.y()))
1722
- self.settings.child('detector_settings', 'ROIselect', 'width').setValue(max([1, int(rect.width())]))
1723
- self.settings.child('detector_settings', 'ROIselect', 'height').setValue(max([1, int(rect.height())]))
1724
-
1725
- ######################
1726
- ### EXTERNAL actions
1727
-
1728
- def send_to_nav(self):
1729
- datas = dict()
1730
- keys = list(self.data_to_save_export['data2D'].keys())
1731
- datas['x_axis'] = self.data_to_save_export['data2D'][keys[0]]['x_axis']
1732
- datas['y_axis'] = self.data_to_save_export['data2D'][keys[0]]['y_axis']
1733
- datas['names'] = keys
1734
- datas['data'] = []
1735
- for k in self.data_to_save_export['data2D']:
1736
- datas['data'].append(self.data_to_save_export['data2D'][k]['data'].T)
1737
- png = self.ui.viewers[0].parent.grab().toImage()
1738
- png = png.scaled(100, 100, QtCore.Qt.KeepAspectRatio)
1739
- buffer = QtCore.QBuffer()
1740
- buffer.open(QtCore.QIODevice.WriteOnly)
1741
- png.save(buffer, "png")
1742
- datas['pixmap2D'] = buffer.data().data()
1743
-
1744
- self.navigator.show_image(datas)
1745
-
1746
- def show_scanner(self, show=True):
1747
- if self.scanner is None:
1748
- items = OrderedDict([])
1749
- if self.navigator is not None:
1750
- items['Navigator'] = dict(viewers=[self.navigator.viewer], names=["Navigator"])
1751
- viewers_title = [view.title for view in self.ui.viewers if view.viewer_type == 'Data2D']
1752
- if len(viewers_title) > 0:
1753
- items[self.title] = dict(viewers=[view for view in self.ui.viewers if view.viewer_type == 'Data2D'],
1754
- names=viewers_title)
1755
-
1756
- self.scanner = Scanner(items, scan_type='Scan2D')
1757
- self.scanner.settings_tree.setMinimumHeight(300)
1758
- self.scanner.settings_tree.setMinimumWidth(300)
1759
- # self.scanner.settings.child('scan_options', 'scan_type').setValue('Scan2D')
1760
- # self.scanner.settings.child('scan_options', 'scan2D_settings', 'scan2D_selection').setValue('FromROI')
1761
-
1762
- # self.navigator.sett_layout.insertWidget(0, self.scanner.settings_tree)
1763
- self.ui.settings_layout.addWidget(self.scanner.settings_tree)
1764
-
1765
- QtWidgets.QApplication.processEvents()
1766
- self.scanner.settings.child('scan_options', 'scan_type').setValue('Scan2D')
1767
- # self.scanner.settings.child('scan_options', 'scan_type').hide()
1768
- self.scanner.settings.child('scan_options', 'scan2D_settings', 'scan2D_type').setValue('Linear')
1769
- # self.scanner.settings.child('scan_options', 'scan2D_settings', 'scan2D_type').hide()
1770
- self.scanner.scan_params_signal[pymodaq.daq_utils.scanner.ScanParameters].connect(self.update_from_scanner)
1771
- QtWidgets.QApplication.processEvents()
1772
- self.scanner.set_scan()
1773
-
1774
- self.scanner.settings_tree.setVisible(show)
1775
-
1776
- def show_navigator(self, show=True):
1777
- if self.navigator is None:
1778
- self.nav_dock = Dock('Navigator')
1779
- self.widgnav = QtWidgets.QWidget()
1780
- self.navigator = Navigator(self.widgnav)
1781
- self.nav_dock.addWidget(self.widgnav)
1782
- self.dockarea.addDock(self.nav_dock)
1783
- self.nav_dock.float()
1784
- self.navigator.settings.child('settings', 'Load h5').hide()
1785
- self.navigator.loadaction.setVisible(False)
1786
- self.navigator.sig_double_clicked.connect(self.move_at_navigator)
1787
- self.ui.navigator_pb.setVisible(True)
1788
-
1789
- if self.scanner is not None:
1790
- items = self.scanner.viewers_items
1791
- if 'Navigator' not in items:
1792
- items['Navigator'] = dict(viewers=[self.navigator.viewer], names=["Navigator"])
1793
- self.scanner.viewers_items = items
1794
-
1795
- self.widgnav.setVisible(show)
1796
-
1797
- @Slot(float, float)
1798
- def move_at_navigator(self, posx, posy):
1799
- self.command_detector.emit(ThreadCommand("move_at_navigator", [posx, posy]))
1800
-
1801
- def show_log(self):
1802
- import webbrowser
1803
- webbrowser.open(self.logger.parent.handlers[0].baseFilename)
1804
-
1805
- ###########################
1806
- # TCPIP stuff
1807
-
1808
- def connect_tcp_ip(self):
1809
- if self.settings.child('main_settings', 'tcpip', 'connect_server').value():
1810
- self.tcpclient_thread = QThread()
1811
-
1812
- tcpclient = TCPClient(self.settings.child('main_settings', 'tcpip', 'ip_address').value(),
1813
- self.settings.child('main_settings', 'tcpip', 'port').value(),
1814
- self.settings.child(('detector_settings')))
1815
- tcpclient.moveToThread(self.tcpclient_thread)
1816
- self.tcpclient_thread.tcpclient = tcpclient
1817
- tcpclient.cmd_signal.connect(self.process_tcpip_cmds)
1818
-
1819
- self.command_tcpip[ThreadCommand].connect(tcpclient.queue_command)
1820
-
1821
- self.tcpclient_thread.start()
1822
- tcpclient.init_connection(extra_commands=[ThreadCommand('get_axis')])
1823
-
1824
- @Slot(ThreadCommand)
1825
- def process_tcpip_cmds(self, status):
1826
- if 'Send Data' in status.command:
1827
- self.snapshot('', send_to_tcpip=True)
1828
- elif status.command == 'connected':
1829
- self.settings.child('main_settings', 'tcpip', 'tcp_connected').setValue(True)
1830
-
1831
- elif status.command == 'disconnected':
1832
- self.settings.child('main_settings', 'tcpip', 'tcp_connected').setValue(False)
1833
-
1834
- elif status.command == 'Update_Status':
1835
- self.thread_status(status)
1836
-
1837
- elif status.command == 'set_info':
1838
- param_dict = ioxml.XML_string_to_parameter(status.attributes[1])[0]
1839
- param_tmp = Parameter.create(**param_dict)
1840
- param = self.settings.child('detector_settings', *status.attributes[0][1:])
1841
-
1842
- param.restoreState(param_tmp.saveState())
1843
-
1844
- elif status.command == 'get_axis':
1845
- self.command_detector.emit(
1846
- ThreadCommand('get_axis')) # tells the plugin to emit its axes so that the server will receive them
1847
-
1848
-
1849
- class DAQ_Detector(QObject):
1850
- """
1851
- ========================= ==========================
1852
- **Attributes** **Type**
1853
- *status_sig* instance of pyqt Signal
1854
- *data_detector_sig* instance of pyqt Signal
1855
- *data_detector_temp_sig* instance of pyqt Signal
1856
-
1857
- *waiting_for_data* boolean
1858
- *controller* ???
1859
- *detector_name* string
1860
- *detector* ???
1861
- *controller_adress* ???
1862
- *grab_state* boolean
1863
- *single_grab* boolean
1864
- *x_axis* 1D numpy array
1865
- *y_axis* 1D numpy array
1866
- *datas* dictionnary
1867
- *ind_average* int
1868
- *Naverage* int
1869
- *average_done* boolean
1870
- *hardware_averaging* boolean
1871
- *show_averaging* boolean
1872
- *wait_time* int
1873
- *DAQ_type* string
1874
- ========================= ==========================
1875
- """
1876
- status_sig = Signal(ThreadCommand)
1877
- data_detector_sig = Signal(list)
1878
- data_detector_temp_sig = Signal(list)
1879
-
1880
- def __init__(self, title, settings_parameter, detector_name):
1881
- super().__init__()
1882
- self.waiting_for_data = False
1883
- self.controller = None
1884
- self.logger = utils.set_logger(f'{logger.name}.{title}.detector')
1885
- self.detector_name = detector_name
1886
- self.detector = None
1887
- self.controller_adress = None
1888
- self.grab_state = False
1889
- self.single_grab = False
1890
- self.datas = None
1891
- self.ind_average = 0
1892
- self.Naverage = None
1893
- self.average_done = False
1894
- self.hardware_averaging = False
1895
- self.show_averaging = False
1896
- self.wait_time = settings_parameter.child('main_settings', 'wait_time').value()
1897
- self.DAQ_type = settings_parameter.child('main_settings', 'DAQ_type').value()
1898
-
1899
- @Slot(edict)
1900
- def update_settings(self, settings_parameter_dict):
1901
- """
1902
- | Set attributes values in case of "main_settings" path with corresponding parameter values.
1903
- | Recursively call the method on detector class attributes else.
1904
-
1905
- ======================== ============== ======================================
1906
- **Parameters** **Type** **Description**
1907
- settings_parameter_dict dictionnary the (pathname,parameter) dictionnary
1908
- ======================== ============== ======================================
1909
-
1910
- See Also
1911
- --------
1912
- update_settings
1913
- """
1914
-
1915
- path = settings_parameter_dict['path']
1916
- param = settings_parameter_dict['param']
1917
- if path[0] == 'main_settings':
1918
- if hasattr(self, path[-1]):
1919
- setattr(self, path[-1], param.value())
1920
-
1921
- elif path[0] == 'detector_settings':
1922
- self.detector.update_settings(settings_parameter_dict)
1923
-
1924
- @Slot(ThreadCommand)
1925
- def queue_command(self, command=ThreadCommand()):
1926
- """
1927
- Treat the given command parameter from his name :
1928
- * **ini_detector** : Send the corresponding Thread command via a status signal.
1929
- * **close** : Send the corresponding Thread command via a status signal.
1930
- * **grab** : Call the local grab method with command(s) attributes.
1931
- * **single** : Call the local single method with command(s) attributes.
1932
- * **stop_grab** : Send the correpsonding Thread command via a status signal.
1933
-
1934
- =============== ================= ============================
1935
- **Parameters** *Type* **Description**
1936
- *command* ThreadCommand() The command to be treated
1937
- =============== ================= ============================
1938
-
1939
- See Also
1940
- --------
1941
- grab, single, daq_utils.ThreadCommand
1942
- """
1943
- if command.command == "ini_detector":
1944
- status = self.ini_detector(*command.attributes)
1945
- self.status_sig.emit(ThreadCommand(command.command, [status, 'log']))
1946
-
1947
- elif command.command == "close":
1948
- status = self.close()
1949
- self.status_sig.emit(ThreadCommand(command.command, [status, 'log']))
1950
-
1951
- elif command.command == "grab":
1952
- self.single_grab = False
1953
- self.grab_state = True
1954
- self.grab_data(*command.attributes)
1955
-
1956
- elif command.command == "single":
1957
- self.single_grab = True
1958
- self.grab_state = True
1959
- self.single(*command.attributes)
1960
-
1961
- elif command.command == "stop_grab":
1962
- self.grab_state = False
1963
- # self.status_sig.emit(ThreadCommand("Update_Status", ['Stoping grab']))
1964
-
1965
- elif command.command == "stop_all":
1966
- self.grab_state = False
1967
- self.detector.stop()
1968
- QtWidgets.QApplication.processEvents()
1969
-
1970
- elif command.command == 'update_scanner':
1971
- self.detector.update_scanner(command.attributes[0])
1972
-
1973
- elif command.command == 'move_at_navigator':
1974
- self.detector.move_at_navigator(*command.attributes)
1975
-
1976
- elif command.command == 'update_com':
1977
- self.detector.update_com()
1978
-
1979
- elif command.command == 'update_wait_time':
1980
- self.wait_time = command.attributes[0]
1981
-
1982
- elif command.command == 'get_axis':
1983
- self.detector.get_axis()
1984
-
1985
- else: # custom commands for particular plugins (see spectrometer module 'get_spectro_wl' for instance)
1986
- if hasattr(self.detector, command.command):
1987
- cmd = getattr(self.detector, command.command)
1988
- cmd(*command.attributes)
1989
-
1990
- def ini_detector(self, params_state=None, controller=None):
1991
- """
1992
- Init the detector from params_state parameter and DAQ_type class attribute :
1993
- * in **0D** profile : update the local status and send the "x_axis" Thread command via a status signal
1994
- * in **1D** profile : update the local status and send the "x_axis" Thread command via a status signal
1995
- * in **2D** profile : update the local status and send the "x_axis" and the "y_axis" Thread command via a status signal
1996
-
1997
- =============== =========== ==========================================
1998
- **Parameters** **Type** **Description**
1999
- *params_state* ??? the parameter's state of initialization
2000
- =============== =========== ==========================================
2001
-
2002
- See Also
2003
- --------
2004
- ini_detector, daq_utils.ThreadCommand
2005
- """
2006
- try:
2007
- # status="Not initialized"
2008
- status = edict(initialized=False, info="", x_axis=None, y_axis=None)
2009
-
2010
- plug_name = self.detector_name
2011
-
2012
- if self.DAQ_type == 'DAQ0D':
2013
- parent_module = utils.find_dict_in_list_from_key_val(DAQ_0DViewer_Det_types, 'name', plug_name)
2014
- class_ = getattr(getattr(parent_module['module'], 'daq_0Dviewer_' + plug_name),
2015
- 'DAQ_0DViewer_' + plug_name)
2016
- elif self.DAQ_type == "DAQ1D":
2017
- parent_module = utils.find_dict_in_list_from_key_val(DAQ_1DViewer_Det_types, 'name', plug_name)
2018
- class_ = getattr(getattr(parent_module['module'], 'daq_1Dviewer_' + plug_name),
2019
- 'DAQ_1DViewer_' + plug_name)
2020
- elif self.DAQ_type == 'DAQ2D':
2021
- parent_module = utils.find_dict_in_list_from_key_val(DAQ_2DViewer_Det_types, 'name', plug_name)
2022
- class_ = getattr(getattr(parent_module['module'], 'daq_2Dviewer_' + plug_name),
2023
- 'DAQ_2DViewer_' + plug_name)
2024
- elif self.DAQ_type == 'DAQND':
2025
- parent_module = utils.find_dict_in_list_from_key_val(DAQ_NDViewer_Det_types, 'name', plug_name)
2026
- class_ = getattr(getattr(parent_module['module'], 'daq_NDviewer_' + plug_name),
2027
- 'DAQ_NDViewer_' + plug_name)
2028
- else:
2029
- raise Exception(plug_name + " unknown")
2030
-
2031
- self.detector = class_(self, params_state)
2032
-
2033
- try:
2034
- self.detector.data_grabed_signal.connect(self.data_ready)
2035
- self.detector.data_grabed_signal_temp.connect(self.emit_temp_data)
2036
- infos = self.detector.ini_detector(controller) # return edict(info="", controller=, stage=)
2037
- except Exception as e:
2038
- logger.exception('Hardware couldn\'t be initialized' + str(e))
2039
- infos = str(e), False
2040
-
2041
- if isinstance(infos, edict):
2042
- status.update(infos)
2043
- else:
2044
- status.info = infos[0]
2045
- status.initialized = infos[1]
2046
-
2047
- status.controller = self.detector.controller
2048
-
2049
- if status['x_axis'] is not None:
2050
- x_axis = status['x_axis']
2051
- self.status_sig.emit(ThreadCommand("x_axis", [x_axis]))
2052
- if status['y_axis'] is not None:
2053
- y_axis = status['y_axis']
2054
- self.status_sig.emit(ThreadCommand("y_axis", [y_axis]))
2055
-
2056
- self.hardware_averaging = class_.hardware_averaging # to check if averaging can be done directly by the hardware or done here software wise
2057
-
2058
- return status
2059
- except Exception as e:
2060
- self.logger.exception(str(e))
2061
- return status
2062
-
2063
- @Slot(list)
2064
- def emit_temp_data(self, datas):
2065
- self.data_detector_temp_sig.emit(datas)
2066
-
2067
- @Slot(list)
2068
- def data_ready(self, datas):
2069
- """
2070
- | Update the local datas attributes from the given datas parameter if the averaging has to be done software wise.
2071
- |
2072
- | Else emit the data detector signals with datas parameter as an attribute.
2073
-
2074
- =============== ===================== =========================
2075
- **Parameters** **Type** **Description**
2076
- *datas* list the datas to be emitted.
2077
- =============== ===================== =========================
2078
-
2079
- See Also
2080
- --------
2081
- daq_utils.ThreadCommand
2082
- """
2083
-
2084
- # datas validation check for backcompatibility with plugins not exporting new DataFromPlugins list of objects
2085
-
2086
- for dat in datas:
2087
- if not isinstance(dat, utils.DataFromPlugins):
2088
- if 'type' in dat:
2089
- dat['dim'] = dat['type']
2090
- dat['type'] = 'raw'
2091
-
2092
- if not self.hardware_averaging: # to execute if the averaging has to be done software wise
2093
- self.ind_average += 1
2094
- if self.ind_average == 1:
2095
- self.datas = datas
2096
- else:
2097
- try:
2098
- for indpannel, dic in enumerate(datas):
2099
- self.datas[indpannel]['data'] = \
2100
- [((self.ind_average - 1) * self.datas[indpannel]['data'][ind] + datas[indpannel]['data'][
2101
- ind]) / self.ind_average for ind in range(len(datas[indpannel]['data']))]
2102
-
2103
- if self.show_averaging:
2104
- self.emit_temp_data(self.datas)
2105
-
2106
- except Exception as e:
2107
- self.logger.exception(str(e))
2108
-
2109
- if self.ind_average == self.Naverage:
2110
- self.average_done = True
2111
- self.data_detector_sig.emit(self.datas)
2112
- self.ind_average = 0
2113
- else:
2114
- self.data_detector_sig.emit(datas)
2115
- self.waiting_for_data = False
2116
- if not self.grab_state:
2117
- # self.status_sig.emit(["Update_Status","Grabing braked"])
2118
- self.detector.stop()
2119
-
2120
- def single(self, Naverage=1, args_as_dict={}):
2121
- """
2122
- Call the grab method with Naverage parameter as an attribute.
2123
-
2124
- =============== =========== ==================
2125
- **Parameters** **Type** **Description**
2126
- *Naverage* int
2127
- *savepath* str eventual savepath
2128
- =============== =========== ==================
2129
-
2130
- See Also
2131
- --------
2132
- daq_utils.ThreadCommand, grab
2133
- """
2134
- try:
2135
- self.grab_data(Naverage, live=False, **args_as_dict)
2136
-
2137
- except Exception as e:
2138
- self.logger.exception(str(e))
2139
-
2140
- def grab_data(self, Naverage=1, live=True, **kwargs):
2141
- """
2142
- | Update status with 'Start Grabing' Update_status sub command of the Thread command.
2143
- | Process events and grab naverage is needed.
2144
-
2145
- =============== =========== ==================
2146
- **Parameters** **Type** **Description**
2147
- *Naverage* int
2148
- =============== =========== ==================
2149
-
2150
- See Also
2151
- --------
2152
- daq_utils.ThreadCommand, grab
2153
- """
2154
- try:
2155
- self.ind_average = 0
2156
- self.Naverage = Naverage
2157
- if Naverage > 1:
2158
- self.average_done = False
2159
- # self.status_sig.emit(ThreadCommand("Update_Status", [f'Start Grabing']))
2160
- self.waiting_for_data = False
2161
-
2162
- # for live mode:two possibilities: either snap one data and regrab softwarewise (while True) or if
2163
- # self.detector.live_mode_available is True all data is continuously emited from the plugin
2164
- if self.detector.live_mode_available:
2165
- kwargs['wait_time'] = self.wait_time
2166
- else:
2167
- kwargs['wait_time'] = 0
2168
- while True:
2169
- try:
2170
- if not self.waiting_for_data:
2171
- self.waiting_for_data = True
2172
- self.detector.grab_data(Naverage, live=live, **kwargs)
2173
- QtWidgets.QApplication.processEvents()
2174
- if self.single_grab:
2175
- if self.hardware_averaging:
2176
- break
2177
- else:
2178
- if self.average_done:
2179
- break
2180
- else:
2181
- QThread.msleep(self.wait_time) #if in live mode apply a waiting time after acquisition
2182
- if not self.grab_state:
2183
- break
2184
- if self.detector.live_mode_available:
2185
- break
2186
- except Exception as e:
2187
- self.logger.exception(str(e))
2188
-
2189
- except Exception as e:
2190
- self.logger.exception(str(e))
2191
-
2192
- def close(self):
2193
- """
2194
- close the current instance of DAQ_Detector.
2195
- """
2196
- try:
2197
- status = self.detector.close()
2198
- except Exception as e:
2199
- self.logger.exception(str(e))
2200
- status = str(e)
2201
- return status
2202
-
2203
-
2204
- def main(init_qt=True):
2205
- if init_qt: # used for the test suite
2206
- app = QtWidgets.QApplication(sys.argv)
2207
- if config('style', 'darkstyle'):
2208
- import qdarkstyle
2209
- app.setStyleSheet(qdarkstyle.load_stylesheet(qdarkstyle.DarkPalette))
2210
-
2211
- win = QtWidgets.QMainWindow()
2212
- area = DockArea()
2213
- win.setCentralWidget(area)
2214
- win.resize(1000, 500)
2215
- win.setWindowTitle('PyMoDAQ Viewer')
2216
- viewer = DAQ_Viewer(area, title="Testing", DAQ_type='DAQ2D')
2217
- win.show()
2218
- if init_qt:
2219
- sys.exit(app.exec_())
2220
- return viewer, win
2221
-
2222
-
2223
- if __name__ == '__main__':
2224
-
2225
- main()