pymodaq 3.6.12__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.12.dist-info → pymodaq-4.0.1.dist-info}/RECORD +167 -170
  139. {pymodaq-3.6.12.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 -671
  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.12.dist-info/METADATA +0 -39
  205. pymodaq-3.6.12.dist-info/entry_points.txt +0 -8
  206. pymodaq-3.6.12.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.12.dist-info → pymodaq-4.0.1.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,538 @@
1
+ import numpy as np
2
+ from pyqtgraph.parametertree import Parameter
3
+ from qtpy import QtCore, QtWidgets, QtGui
4
+ from qtpy.QtCore import QPointF, Slot, Signal, QObject
5
+ from typing import List, Tuple
6
+
7
+ from pyqtgraph import LinearRegionItem
8
+
9
+ from pymodaq.utils import data as data_mod
10
+ from pymodaq.utils import daq_utils as utils
11
+ from pymodaq.utils import math_utils as mutils
12
+ from pymodaq.utils.managers.roi_manager import ROIManager, LinearROI, RectROI
13
+ from pymodaq.utils.plotting.items.crosshair import Crosshair
14
+ from pymodaq.utils.plotting.items.image import UniformImageItem
15
+ from pymodaq.utils.plotting.data_viewers.viewer1Dbasic import Viewer1DBasic
16
+ from pymodaq.utils.logger import set_logger, get_module_name
17
+
18
+
19
+ from pymodaq.post_treatment.process_to_scalar import DataProcessorFactory
20
+
21
+
22
+ logger = set_logger(get_module_name(__file__))
23
+
24
+
25
+ data_processors = DataProcessorFactory()
26
+
27
+
28
+ class Filter:
29
+
30
+ def __init__(self):
31
+ self._is_active = False
32
+ self._slot_to_send_data = None
33
+
34
+ def register_activation_signal(self, activation_signal):
35
+ activation_signal.connect(lambda x: self.set_active(x))
36
+
37
+ def register_target_slot(self, slot):
38
+ self._slot_to_send_data = slot
39
+
40
+ @Slot(bool)
41
+ def set_active(self, activate=True):
42
+ self._is_active = activate
43
+
44
+ def filter_data(self, data: data_mod.DataFromPlugins):
45
+ if self._is_active:
46
+ filtered_data = self._filter_data(data)
47
+ if filtered_data is not None and self._slot_to_send_data is not None:
48
+ self._slot_to_send_data(filtered_data)
49
+
50
+ def _filter_data(self, data: data_mod.DataFromPlugins):
51
+ raise NotImplementedError
52
+
53
+
54
+ class Filter1DFromCrosshair(Filter):
55
+ def __init__(self, crosshair: Crosshair):
56
+ """
57
+ Extract data along a crosshair using coordinates and data displayed in graph_items such as imageItems
58
+ Parameters
59
+ ----------
60
+ crosshair : Crosshair
61
+ """
62
+ super().__init__()
63
+ self.crosshair = crosshair
64
+ self._x, self._y = 0., 0.
65
+ self._axis: data_mod.Axis = None
66
+
67
+ def update_axis(self, axis: data_mod.Axis):
68
+ self._axis = axis
69
+
70
+ def _filter_data(self, data: data_mod.DataFromPlugins):
71
+ data_dict = dict([])
72
+ if data is not None and self._axis is not None:
73
+ axis = data.get_axis_from_index(0, create=False)
74
+ if axis is not None:
75
+ self.update_axis(axis)
76
+
77
+ self._x, self._y = self.crosshair.get_positions()
78
+ ind_x, axis_val = mutils.find_index(self._axis.data, (self._x,))[0]
79
+ for label, dat in zip(data.labels, data.data):
80
+ data_dict[label] = dict(pos=axis_val, value=dat[ind_x])
81
+ return data_dict
82
+
83
+
84
+ class Filter2DFromCrosshair(Filter):
85
+ def __init__(self, crosshair: Crosshair, graph_items, image_keys):
86
+ """
87
+ Extract data along a crosshair using coordinates and data displayed in graph_items such as imageItems
88
+ Parameters
89
+ ----------
90
+ crosshair : (Crosshair)
91
+ graph_items : (dict)
92
+ image_keys : (list) list of string identifier to link datas to their graph_items. This means that in
93
+ _filter_data, datas['data'][key] is plotted on graph_items[key] for key in image_keys
94
+ """
95
+ super().__init__()
96
+ self._graph_items = graph_items
97
+ self._image_keys = image_keys
98
+ self.crosshair = crosshair
99
+ self._x, self._y = 0., 0.
100
+
101
+ def set_graph_items(self, graph_items):
102
+ self._graph_items = graph_items
103
+
104
+ @Slot(bool)
105
+ def set_active(self, activate=True):
106
+ self._is_active = activate
107
+ if activate:
108
+ self.crosshair.crosshair_dragged.emit(*self.crosshair.get_positions())
109
+
110
+ def _filter_data(self, datas: data_mod.DataFromPlugins):
111
+ data_dict = dict([])
112
+ if datas is not None:
113
+ self._x, self._y = self.crosshair.get_positions()
114
+ data_type = datas.distribution
115
+ for data_index in range(len(self._image_keys)):
116
+ if data_index < len(datas.data):
117
+ data = datas.data[data_index]
118
+ image_type = self._image_keys[data_index]
119
+ if data_type == 'uniform':
120
+ data_dict[image_type] = self.get_data_from_uniform(image_type, data)
121
+ elif data_type == 'spread':
122
+ data_dict[image_type] = self.get_data_from_spread(image_type, data)
123
+ return data_dict
124
+
125
+ def get_data_from_uniform(self, data_key, data):
126
+ hor_axis, ver_axis = \
127
+ np.linspace(0, self._graph_items[data_key].width() - 1, self._graph_items[data_key].width()),\
128
+ np.linspace(0, self._graph_items[data_key].height() - 1, self._graph_items[data_key].height())
129
+
130
+ indx, indy = self.mapfromview(self._x, self._y, data_key)
131
+
132
+ data_H_index = slice(None, None, 1)
133
+ data_V_index = slice(None, None, 1)
134
+ H_indexes = (utils.rint(indy), data_H_index)
135
+ V_indexes = (data_V_index, utils.rint(indx))
136
+
137
+ out_of_bounds = False
138
+ if 0 <= H_indexes[0] < len(ver_axis):
139
+ hor_data = data[H_indexes]
140
+ else:
141
+ out_of_bounds = True
142
+ hor_data = np.zeros(hor_axis.shape)
143
+ if 0 <= V_indexes[1] < len(hor_axis):
144
+ ver_data = data[V_indexes]
145
+ else:
146
+ out_of_bounds = True
147
+ ver_data = np.zeros(ver_axis.shape)
148
+ if out_of_bounds:
149
+ ind_data = 0.
150
+ else:
151
+ ind_data = data[utils.rint(indy), utils.rint(indx)]
152
+ return LineoutData(hor_axis=hor_axis, ver_axis=ver_axis, hor_data=hor_data, ver_data=ver_data,
153
+ int_data=ind_data)
154
+
155
+ def get_data_from_spread(self, data_key, data):
156
+ data_H_index = slice(None, None, 1)
157
+ data_V_index = slice(None, None, 1)
158
+ posx, posy = self.mapfromview(self._x, self._y, data_key)
159
+
160
+ points, data = self._graph_items[data_key].get_points_at(axis='y', val=posy)
161
+ x_sorted_indexes = np.argsort(points[:, 0])
162
+ hor_axis = points[x_sorted_indexes, 0][data_H_index]
163
+
164
+ hor_data = data[x_sorted_indexes][data_H_index]
165
+
166
+ points, data = self._graph_items[data_key].get_points_at(axis='x', val=posx)
167
+ y_sorted_indexes = np.argsort(points[:, 1])
168
+ ver_axis = points[y_sorted_indexes, 1][data_V_index]
169
+
170
+ ver_data = data[y_sorted_indexes][data_V_index]
171
+
172
+ return LineoutData(hor_axis=hor_axis, ver_axis=ver_axis, hor_data=hor_data, ver_data=ver_data,
173
+ int_data=self._graph_items[data_key].get_val_at((posx, posy)))
174
+
175
+ def mapfromview(self, x, y, item_key='red'):
176
+ """
177
+ get item coordinates from view coordinates
178
+ Parameters
179
+ ----------
180
+ x: (float) x coordinate in the view reference frame
181
+ y: (float) y coordinate in the view refernece frame
182
+
183
+ Returns
184
+ -------
185
+ x: (float) coordinate in the item reference frame
186
+ y: (float) coordinate in the item reference frame
187
+ """
188
+ point = self._graph_items[item_key].mapFromView(QPointF(x, y))
189
+ return point.x(), point.y()
190
+
191
+
192
+ class Filter1DFromRois(Filter):
193
+ """
194
+
195
+ Parameters
196
+ ----------
197
+ roi_manager:ROIManager
198
+ graph_item: PlotItems
199
+ """
200
+ def __init__(self, roi_manager: ROIManager):
201
+
202
+ super().__init__()
203
+ self._roi_settings = roi_manager.settings
204
+ self._ROIs = roi_manager.ROIs
205
+ self._axis: data_mod.Axis = None
206
+
207
+ def update_axis(self, axis: data_mod.Axis):
208
+ self._axis = axis
209
+
210
+ def _filter_data(self, data: data_mod.DataFromPlugins) -> dict:
211
+ data_dict = dict([])
212
+ try:
213
+ axis = data.get_axis_from_index(0, create=False)
214
+ if axis is not None:
215
+ self.update_axis(axis)
216
+ if data is not None:
217
+ for roi_key, roi in self._ROIs.items():
218
+ try:
219
+ data_index = data.labels.index(self._roi_settings['ROIs', roi_key, 'use_channel'])
220
+ except ValueError:
221
+ data_index = 0
222
+ data_dict[roi_key] = self.get_data_from_roi(roi, self._roi_settings.child('ROIs', roi_key),
223
+ data, data_index)
224
+ except Exception as e:
225
+ pass
226
+ return data_dict
227
+
228
+ def get_data_from_roi(self, roi: LinearROI, roi_param: Parameter, data: data_mod.DataWithAxes, data_index=0):
229
+ if data is not None:
230
+ _slice = self.get_slice_from_roi(roi, data)
231
+ sub_data = data.isig[_slice]
232
+ if sub_data.size != 0:
233
+ processed_data = data_processors.get(roi_param['math_function']).process(sub_data)
234
+ else:
235
+ processed_data = None
236
+ if processed_data is None:
237
+ return LineoutData()
238
+ else:
239
+ if len(sub_data.axes) == 0:
240
+ pass
241
+ return LineoutData(hor_axis=sub_data.axes[0], hor_data=sub_data.data[data_index],
242
+ int_data=processed_data.data[data_index])
243
+
244
+ def get_slice_from_roi(self, roi: RectROI, data: data_mod.DataWithAxes) -> slice:
245
+ ind_x_min, ind_x_max = data.get_axis_from_index(data.sig_indexes[0])[0].find_indexes(roi.getRegion())
246
+ size = data.get_axis_from_index(0)[0].size
247
+ ind_x_min = int(min(max(ind_x_min, 0), size))
248
+ ind_x_max = int(max(0, min(ind_x_max, size)))
249
+ return slice(ind_x_min, ind_x_max)
250
+
251
+
252
+ class Filter2DFromRois(Filter):
253
+ """Filters 2D data using 2D ROIs
254
+
255
+ Parameters
256
+ ----------
257
+ roi_manager: ROIManager
258
+ graph_item: UniformImageItem or SpreadImageItem
259
+ The graphical item where data and ROIs are plotted
260
+ image_keys : (list) list of string identifier to link datas to their graph_items. This means that in
261
+ _filter_data, datas.data[key] is plotted on graph_items[key] for key in image_keys
262
+ """
263
+ def __init__(self, roi_manager: ROIManager, graph_item: UniformImageItem, image_keys):
264
+
265
+ super().__init__()
266
+ self._roi_settings = roi_manager.settings
267
+ self._image_keys = image_keys
268
+ self._graph_item = graph_item
269
+ self.axes = (0, 1)
270
+ self._ROIs = roi_manager.ROIs
271
+
272
+ def _filter_data(self, data: data_mod.DataFromPlugins) -> dict:
273
+ data_dict = dict([])
274
+ try:
275
+ if data is not None:
276
+ for roi_key, roi in self._ROIs.items():
277
+ image_key = self._roi_settings['ROIs', roi_key, 'use_channel']
278
+ image_index = self._image_keys.index(image_key)
279
+
280
+ sub_data = data.deepcopy()
281
+ sub_data.data = [data[image_index]]
282
+ data_dict[roi_key] = self.get_xydata_from_roi(roi, sub_data,
283
+ self._roi_settings['ROIs', roi_key, 'math_function'])
284
+ except Exception as e:
285
+ pass
286
+ return data_dict
287
+
288
+ def get_slices_from_roi(self, roi: RectROI, data: data_mod.DataWithAxes) -> Tuple[slice]:
289
+ x, y = roi.pos().x(), roi.pos().y()
290
+ width, height = roi.size().x(), roi.size().y()
291
+ size_x = data.get_axis_from_index(1)[0].size
292
+ size_y = data.get_axis_from_index(0)[0].size
293
+ ind_x_min = int(min(max(x, 0), size_x))
294
+ ind_y_min = int(min(max(y, 0), size_y))
295
+ ind_x_max = int(max(0, min(x+width, size_x)))
296
+ ind_y_max = int(max(0, min(y+height, size_y)))
297
+
298
+ return slice(ind_y_min,ind_y_max), slice(ind_x_min, ind_x_max)
299
+
300
+ def get_xydata_from_roi(self, roi, data: data_mod.DataWithAxes, math_function: str):
301
+
302
+ if data is not None:
303
+ if data.distribution.name == 'spread':
304
+ xvals, yvals, data = self.get_xydata_spread(data, roi)
305
+ ind_xaxis = np.argsort(xvals)
306
+ ind_yaxis = np.argsort(yvals)
307
+ xvals = xvals[ind_xaxis]
308
+ yvals = yvals[ind_yaxis]
309
+ data_H = data[ind_xaxis]
310
+ data_V = data[ind_yaxis]
311
+ int_data = np.array([np.mean(data)])
312
+ math_data = int_data
313
+ else:
314
+ xvals, yvals, data_array = self.get_xydata(data.data[0], roi)
315
+ slices = self.get_slices_from_roi(roi, data)
316
+ sub_data = data.isig[slices[0], slices[1]]
317
+ data_H = np.mean(data_array, axis=0)
318
+ data_V = np.mean(data_array, axis=1)
319
+ int_data = np.array([np.mean(data_array)])
320
+ math_data = data_processors.get(math_function).process(sub_data).data
321
+
322
+ return LineoutData(hor_axis=xvals, ver_axis=yvals, hor_data=data_H, ver_data=data_V, int_data=int_data,
323
+ math_data=math_data)
324
+
325
+ def get_xydata(self, data: np.ndarray, roi: RectROI):
326
+ data, coords = self.data_from_roi(data, roi)
327
+
328
+ if data is not None:
329
+ xvals = np.linspace(np.min(np.min(coords[1, :, :])), np.max(np.max(coords[1, :, :])),
330
+ data.shape[1])
331
+ yvals = np.linspace(np.min(np.min(coords[0, :, :])), np.max(np.max(coords[0, :, :])),
332
+ data.shape[0])
333
+ else:
334
+ xvals = yvals = data = np.array([])
335
+ return xvals, yvals, data
336
+
337
+ def data_from_roi(self, data, roi):
338
+ data, coords = roi.getArrayRegion(data, self._graph_item, self.axes, returnMappedCoords=True)
339
+ return data, coords
340
+
341
+ def get_xydata_spread(self, data, roi):
342
+ xvals = []
343
+ yvals = []
344
+ data_out = []
345
+ for ind in range(data.shape[0]):
346
+ # invoke the QPainterpath of the ROI (from the shape method)
347
+ if roi.shape().contains(QPointF(data.get_axis_from_index(0)[0].get_data()[ind] - roi.pos().x(),
348
+ data.get_axis_from_index(0)[1].get_data()[ind] - roi.pos().y())):
349
+ xvals.append(data.get_axis_from_index(0)[0].get_data()[ind])
350
+ yvals.append(data.get_axis_from_index(0)[1].get_data()[ind])
351
+ data_out.append(data[0][ind])
352
+ data_out = np.array(data_out)
353
+ xvals = np.array(xvals)
354
+ yvals = np.array(yvals)
355
+ return xvals, yvals, data_out
356
+
357
+
358
+ class LineoutData:
359
+ def __init__(self, hor_axis=np.array([]), ver_axis=np.array([]), hor_data=np.array([]), ver_data=np.array([]),
360
+ int_data: np.ndarray = None, math_data: List[np.ndarray] = None):
361
+ super().__init__()
362
+ if len(hor_axis) != len(hor_data):
363
+ raise ValueError(f'Horizontal lineout data and axis must have the same size')
364
+ if len(ver_axis) != len(ver_data):
365
+ raise ValueError(f'Horizontal lineout data and axis must have the same size')
366
+
367
+ self.hor_axis = hor_axis
368
+ self.ver_axis = ver_axis
369
+ self.hor_data = hor_data
370
+ self.ver_data = ver_data
371
+ if int_data is None:
372
+ self.int_data = np.array([np.sum(self.ver_data)])
373
+ else:
374
+ self.int_data = int_data
375
+ if math_data is None:
376
+ math_data = self.int_data
377
+ self.math_data = math_data
378
+
379
+
380
+ class FourierFilterer(QObject):
381
+ filter_changed = Signal(dict)
382
+
383
+ def __init__(self, parent=None):
384
+ super().__init__()
385
+ if parent is None:
386
+ parent = QtWidgets.QWidget()
387
+
388
+ self.parent = parent
389
+
390
+ self.raw_data = None
391
+ self.data = None
392
+ self.data_fft = None
393
+ self.filter = None
394
+ self.xaxis = None
395
+ self.yaxis = None
396
+ self.xaxisft = None
397
+ self.yaxisft = None
398
+
399
+ self.frequency = 0
400
+ self.phase = 0
401
+
402
+ self.c = None
403
+ self.viewer2D = None
404
+ self.setUI()
405
+
406
+ def setUI(self):
407
+ self.vlayout = QtWidgets.QVBoxLayout()
408
+ self.parent.setLayout(self.vlayout)
409
+
410
+ form = QtWidgets.QWidget()
411
+ self.viewer1D = Viewer1DBasic(form)
412
+ self.vlayout.addWidget(form)
413
+ self.fftbutton1D = QtWidgets.QPushButton()
414
+ self.fftbutton1D.setText("")
415
+ icon = QtGui.QIcon()
416
+ icon.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/FFT.png"), QtGui.QIcon.Normal,
417
+ QtGui.QIcon.Off)
418
+ self.fftbutton1D.setIcon(icon)
419
+ self.fftbutton1D.setCheckable(True)
420
+ self.fftbutton1D.clicked.connect(self.update_plot)
421
+
422
+ vbox = self.viewer1D.parent.layout()
423
+ widg = QtWidgets.QWidget()
424
+ hbox = QtWidgets.QHBoxLayout()
425
+ widg.setLayout(hbox)
426
+ vbox.insertWidget(0, widg)
427
+ hbox.addWidget(self.fftbutton1D)
428
+ hbox.addStretch()
429
+
430
+ self.viewer1D.ROI = LinearRegionItem(values=[0, 100])
431
+ self.viewer1D.plotwidget.plotItem.addItem(self.viewer1D.ROI)
432
+ self.data_filtered_plot = self.viewer1D.plotwidget.plotItem.plot()
433
+ self.data_filtered_plot.setPen('w')
434
+ self.viewer1D.ROI.sigRegionChangeFinished.connect(self.set_data)
435
+
436
+ self.viewer1D.ROIfft = LinearRegionItem()
437
+ self.viewer1D.plotwidget.plotItem.addItem(self.viewer1D.ROIfft)
438
+ self.viewer1D.ROIfft.sigRegionChangeFinished.connect(self.update_filter)
439
+
440
+ self.parent.show()
441
+
442
+ def calculate_fft(self):
443
+
444
+ ftaxis, axis = mutils.ftAxis_time(len(self.xaxis), np.max(self.xaxis) - np.min(self.xaxis))
445
+ self.xaxisft = ftaxis / (2 * np.pi)
446
+ self.data_fft = mutils.ft(self.data)
447
+
448
+ def show_data(self, data):
449
+ """
450
+ show data and fft
451
+ Parameters
452
+ ----------
453
+ data: (dict) with keys 'data', optionally 'xaxis' and 'yaxis'
454
+ """
455
+ try:
456
+ self.raw_data = data
457
+
458
+ if 'xaxis' in data:
459
+ self.xaxis = data['xaxis']
460
+ else:
461
+ self.xaxis = np.arange(0, data['data'].shape[0], 1)
462
+ self.raw_data['xaxis'] = self.xaxis
463
+ # self.viewer1D.ROI.setRegion((np.min(self.xaxis), np.max(self.xaxis)))
464
+ self.set_data()
465
+ except Exception as e:
466
+ logger.exception(str(e))
467
+
468
+ def set_data(self):
469
+ xlimits = self.viewer1D.ROI.getRegion()
470
+ indexes = mutils.find_index(self.raw_data['xaxis'], xlimits)
471
+ self.data = self.raw_data['data'][indexes[0][0]:indexes[1][0]]
472
+ self.xaxis = self.raw_data['xaxis'][indexes[0][0]:indexes[1][0]]
473
+ try:
474
+ self.calculate_fft()
475
+ except Exception as e:
476
+ logger.exception(str(e))
477
+ self.viewer1D.x_axis = self.xaxis
478
+ self.update_plot()
479
+
480
+ def update_filter(self):
481
+ try:
482
+ xmin, xmax = self.viewer1D.ROIfft.getRegion()
483
+ self.filter = mutils.gauss1D(self.xaxisft, np.mean([xmin, xmax]), xmax - xmin)
484
+ self.data = np.real(mutils.ift(self.filter * self.data_fft))
485
+ index = np.argmax(self.filter * self.data_fft)
486
+ self.frequency = self.xaxisft[index]
487
+ self.phase = np.angle(self.data_fft[index])
488
+
489
+ self.filter_changed.emit(dict(frequency=self.frequency, phase=self.phase))
490
+ self.update_plot()
491
+ except Exception as e:
492
+ logger.exception(str(e))
493
+
494
+ def update_plot(self):
495
+
496
+ if self.fftbutton1D.isChecked():
497
+ if self.data_fft is not None:
498
+ if self.filter is not None:
499
+ self.viewer1D.show_data([np.abs(self.data_fft), np.max(np.abs(self.data_fft)) * self.filter])
500
+ else:
501
+ self.viewer1D.show_data([np.abs(self.data_fft)])
502
+ self.viewer1D.x_axis = dict(data=self.xaxisft, label='freq.')
503
+ self.viewer1D.ROIfft.setVisible(True)
504
+ self.viewer1D.ROI.setVisible(False)
505
+ self.data_filtered_plot.setVisible(False)
506
+ else:
507
+ if self.raw_data is not None:
508
+ self.viewer1D.show_data([self.raw_data['data']])
509
+ self.viewer1D.x_axis = dict(data=self.raw_data['xaxis'], label='Pxls')
510
+ self.data_filtered_plot.setData(self.xaxis, self.data)
511
+ self.data_filtered_plot.setVisible(True)
512
+ self.viewer1D.ROIfft.setVisible(False)
513
+ self.viewer1D.ROI.setVisible(True)
514
+
515
+
516
+ if __name__ == '__main__':
517
+ import sys
518
+
519
+ app = QtWidgets.QApplication(sys.argv)
520
+ prog = FourierFilterer()
521
+
522
+ from pymodaq.utils.daq_utils import gauss1D
523
+
524
+ xdata = np.linspace(0, 400, 401)
525
+ x0 = 50
526
+ dx = 20
527
+ tau = 27
528
+ tau2 = 100
529
+ ydata_gauss = 10 * gauss1D(xdata, x0, dx) + np.random.rand(len(xdata))
530
+ ydata_expodec = np.zeros((len(xdata)))
531
+ ydata_expodec[:50] = 10 * gauss1D(xdata[:50], x0, dx, 2)
532
+ ydata_expodec[50:] = 10 * np.exp(-(xdata[50:] - x0) / tau) # +10*np.exp(-(xdata[50:]-x0)/tau2)
533
+ ydata_expodec += 2 * np.random.rand(len(xdata))
534
+ ydata_sin = 10 + 2 * np.sin(2 * np.pi * 0.1 * xdata - np.deg2rad(55)) + np.sin(
535
+ 2 * np.pi * 0.008 * xdata - np.deg2rad(-10)) + 2 * np.random.rand(len(xdata))
536
+
537
+ prog.show_data(dict(data=ydata_sin, xaxis=xdata))
538
+ sys.exit(app.exec_())