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,705 +0,0 @@
1
- import numpy
2
- import numpy as np
3
- from qtpy import QtWidgets, QtGui
4
- from qtpy.QtCore import QObject, Signal
5
- from pyqtgraph import LinearRegionItem
6
-
7
- from pymodaq.daq_utils.daq_utils import set_logger, get_module_name
8
- from pymodaq.daq_utils.plotting.data_viewers.viewer1Dbasic import Viewer1DBasic
9
-
10
- logger = set_logger(get_module_name(__file__))
11
-
12
-
13
- def my_moment(x, y):
14
- """Returns the moments of a distribution y over an axe x
15
-
16
- Parameters
17
- ----------
18
- x: list or ndarray
19
- vector of floats
20
- y: list or ndarray
21
- vector of floats corresponding to the x axis
22
-
23
- Returns
24
- -------
25
- m: list
26
- Contains moment of order 0 (mean) and of order 1 (std) of the distribution y
27
- """
28
- dx = np.mean(np.diff(x))
29
- norm = np.sum(y) * dx
30
- m = [np.sum(x * y) * dx / norm]
31
- m.extend([np.sqrt(np.sum((x - m[0]) ** 2 * y) * dx / norm)])
32
- return m
33
-
34
-
35
- def normalize(x):
36
- x = x - np.min(x)
37
- x = x / np.max(x)
38
- return x
39
-
40
-
41
- def odd_even(x):
42
- """
43
- odd_even tells if a number is odd (return True) or even (return False)
44
-
45
- Parameters
46
- ----------
47
- x: the integer number to test
48
-
49
- Returns
50
- -------
51
- bool : boolean
52
- """
53
- if not isinstance(x, int):
54
- raise TypeError(f'{x} should be an integer')
55
- if int(x) % 2 == 0:
56
- bool = False
57
- else:
58
- bool = True
59
- return bool
60
-
61
-
62
- def greater2n(x):
63
- """
64
- return the first power of 2 greater than x
65
- Parameters
66
- ----------
67
- x: (int or float) a number
68
-
69
- Returns
70
- -------
71
- int: the power of 2 greater than x
72
- """
73
- if isinstance(x, bool):
74
- raise TypeError(f'{x} should be an integer or a float')
75
- if hasattr(x, '__iter__'):
76
- res = []
77
- for el in x:
78
- if isinstance(el, bool):
79
- raise TypeError(f'{el} should be an integer or a float')
80
- if not (isinstance(el, int) or isinstance(el, float)):
81
- raise TypeError(f'{x} elements should be integer or float')
82
- res.append(1 << (int(el) - 1).bit_length())
83
- if isinstance(x, np.ndarray):
84
- return np.array(res)
85
- else:
86
- return res
87
- else:
88
- if not (isinstance(x, int) or isinstance(x, float)):
89
- raise TypeError(f'{x} should be an integer or a float')
90
- return 1 << (int(x) - 1).bit_length()
91
-
92
-
93
- def linspace_step(start, stop, step):
94
- """
95
- Compute a regular linspace_step distribution from start to stop values.
96
-
97
- =============== =========== ======================================
98
- **Parameters** **Type** **Description**
99
- *start* scalar the starting value of distribution
100
- *stop* scalar the stopping value of distribution
101
- *step* scalar the length of a distribution step
102
- =============== =========== ======================================
103
-
104
- Returns
105
- -------
106
-
107
- scalar array
108
- The computed distribution axis as an array.
109
- """
110
- if np.abs(step) < 1e-12 or np.sign(stop - start) != np.sign(step) or start == stop:
111
- raise ValueError('Invalid value for one parameter')
112
- Nsteps = int(np.ceil((stop - start) / step))
113
- new_stop = start + (Nsteps - 1) * step
114
- if np.abs(new_stop + step - stop) < 1e-12:
115
- Nsteps += 1
116
- new_stop = start + (Nsteps - 1) * step
117
- return np.linspace(start, new_stop, Nsteps)
118
-
119
-
120
- def linspace_step_N(start, step, Npts):
121
- stop = (Npts - 1) * step + start
122
- return linspace_step(start, stop, step)
123
-
124
-
125
- def find_index(x, threshold):
126
- """
127
- find_index finds the index ix such that x(ix) is the closest from threshold
128
- Parameters
129
- ----------
130
- x : vector
131
- threshold : list of scalar
132
-
133
- Returns
134
- -------
135
- out : list of 2-tuple containing ix,x[ix]
136
- out=[(ix0,xval0),(ix1,xval1),...]
137
- """
138
-
139
- if not hasattr(threshold, '__iter__'):
140
- threshold = [threshold]
141
- out = []
142
- for value in threshold:
143
- ix = int(np.argmin(np.abs(x - value)))
144
- out.append((ix, x[ix]))
145
- return out
146
-
147
-
148
- def find_common_index(x, y, x0, y0):
149
- vals = x + 1j * y
150
- val = x0 + 1j * y0
151
- ind = int(np.argmin(np.abs(vals - val)))
152
- return ind, x[ind], y[ind]
153
-
154
-
155
- def gauss1D(x, x0, dx, n=1):
156
- """
157
- compute the gaussian function along a vector x, centered in x0 and with a
158
- FWHM i intensity of dx. n=1 is for the standart gaussian while n>1 defines
159
- a hypergaussian
160
-
161
- Parameters
162
- ----------
163
- x: (ndarray) first axis of the 2D gaussian
164
- x0: (float) the central position of the gaussian
165
- dx: (float) :the FWHM of the gaussian
166
- n=1 : an integer to define hypergaussian, n=1 by default for regular gaussian
167
- Returns
168
- -------
169
- out : vector
170
- the value taken by the gaussian along x axis
171
-
172
- """
173
- if dx <= 0:
174
- raise ValueError('dx should be strictly positive')
175
- if not isinstance(n, int):
176
- raise TypeError('n should be a positive integer')
177
- elif n < 0:
178
- raise ValueError('n should be a positive integer')
179
- out = np.exp(-2 * np.log(2) ** (1 / n) * (((x - x0) / dx)) ** (2 * n))
180
- return out
181
-
182
-
183
- def gauss2D(x, x0, dx, y, y0, dy, n=1, angle=0):
184
- """
185
- compute the 2D gaussian function along a vector x, centered in x0 and with a
186
- FWHM in intensity of dx and smae along y axis. n=1 is for the standard gaussian while n>1 defines
187
- a hypergaussian. optionally rotate it by an angle in degree
188
-
189
- Parameters
190
- ----------
191
- x: (ndarray) first axis of the 2D gaussian
192
- x0: (float) the central position of the gaussian
193
- dx: (float) :the FWHM of the gaussian
194
- y: (ndarray) second axis of the 2D gaussian
195
- y0: (float) the central position of the gaussian
196
- dy: (float) :the FWHM of the gaussian
197
- n=1 : an integer to define hypergaussian, n=1 by default for regular gaussian
198
- angle: (float) a float to rotate main axes, in degree
199
-
200
- Returns
201
- -------
202
- out : ndarray 2 dimensions
203
-
204
- """
205
- if angle == 0:
206
- data = np.transpose(np.outer(gauss1D(x, x0, dx, n), gauss1D(y, y0, dy, n)))
207
-
208
- else:
209
-
210
- theta = np.radians(angle)
211
- c, s = np.cos(theta), np.sin(theta)
212
- R = np.array(((c, -s), (s, c)))
213
- (x0r, y0r) = tuple(R.dot(np.array([x0, y0])))
214
-
215
- data = np.zeros((len(y), len(x)))
216
-
217
- for indx, xtmp in enumerate(x):
218
- for indy, ytmp in enumerate(y):
219
- rotatedvect = R.dot(np.array([xtmp, ytmp]))
220
- data[indy, indx] = gauss1D(rotatedvect[0], x0r, dx, n) * gauss1D(rotatedvect[1], y0r, dy, n)
221
-
222
- return data
223
-
224
-
225
- def ftAxis(Npts, omega_max):
226
- """
227
- Given two numbers Npts,omega_max, return two vectors spanning the temporal
228
- and spectral range. They are related by Fourier Transform
229
-
230
- Parameters
231
- ----------
232
- Npts: (int)
233
- A number of points defining the length of both grids
234
- omega_max: (float)
235
- The maximum circular frequency in the spectral domain. its unit defines
236
- the temporal units. ex: omega_max in rad/fs implies time_grid in fs
237
-
238
- Returns
239
- -------
240
- omega_grid: (ndarray)
241
- The spectral axis of the FFT
242
- time_grid: (ndarray))
243
- The temporal axis of the FFT
244
- See Also
245
- --------
246
- ftAxis, ftAxis_time, ift, ft2, ift2
247
- """
248
- if not isinstance(Npts, int):
249
- raise TypeError('n should be a positive integer, if possible power of 2')
250
- elif Npts < 1:
251
- raise ValueError('n should be a strictly positive integer')
252
- dT = 2 * np.pi / (2 * omega_max)
253
- omega_grid = np.linspace(-omega_max, omega_max, Npts)
254
- time_grid = dT * np.linspace(-(Npts - 1) / 2, (Npts - 1) / 2, Npts)
255
- return omega_grid, time_grid
256
-
257
-
258
- def ftAxis_time(Npts, time_max):
259
- """
260
- Given two numbers Npts,omega_max, return two vectors spanning the temporal
261
- and spectral range. They are related by Fourier Transform
262
-
263
- Parameters
264
- ----------
265
- Npts : number
266
- A number of points defining the length of both grids
267
- time_max : number
268
- The maximum tmporal window
269
-
270
- Returns
271
- -------
272
- omega_grid : vector
273
- The spectral axis of the FFT
274
- time_grid : vector
275
- The temporal axis of the FFT
276
- See Also
277
- --------
278
- ftAxis, ftAxis_time, ift, ft2, ift2
279
- """
280
- if not isinstance(Npts, int):
281
- raise TypeError('n should be a positive integer, if possible power of 2')
282
- elif Npts < 1:
283
- raise ValueError('n should be a strictly positive integer')
284
- dT = time_max / Npts
285
- omega_max = (Npts - 1) / 2 * 2 * np.pi / time_max
286
- omega_grid = np.linspace(-omega_max, omega_max, Npts)
287
- time_grid = dT * np.linspace(-(Npts - 1) / 2, (Npts - 1) / 2, Npts)
288
- return omega_grid, time_grid
289
-
290
-
291
- def ft(x, dim=-1):
292
- """
293
- Process the 1D fast fourier transform and swaps the axis to get coorect results using ftAxis
294
- Parameters
295
- ----------
296
- x: (ndarray) the array on which the FFT should be done
297
- dim: the axis over which is done the FFT (default is the last of the array)
298
-
299
- Returns
300
- -------
301
- See Also
302
- --------
303
- ftAxis, ftAxis_time, ift, ft2, ift2
304
- """
305
- if not isinstance(dim, int):
306
- raise TypeError('dim should be an integer specifying the array dimension over which to do the calculation')
307
- assert isinstance(x, np.ndarray)
308
- assert dim >= -1
309
- assert dim <= len(x.shape) - 1
310
-
311
- out = np.fft.fftshift(np.fft.fft(np.fft.fftshift(x, axes=dim), axis=dim), axes=dim)
312
- return out
313
-
314
-
315
- def ift(x, dim=0):
316
- """
317
- Process the inverse 1D fast fourier transform and swaps the axis to get correct results using ftAxis
318
- Parameters
319
- ----------
320
- x: (ndarray) the array on which the FFT should be done
321
- dim: the axis over which is done the FFT (default is the last of the array)
322
-
323
- Returns
324
- -------
325
- See Also
326
- --------
327
- ftAxis, ftAxis_time, ift, ft2, ift2
328
- """
329
- if not isinstance(dim, int):
330
- raise TypeError('dim should be an integer specifying the array dimension over which to do the calculation')
331
- assert isinstance(x, np.ndarray)
332
- assert dim >= -1
333
- assert dim <= len(x.shape) - 1
334
- out = np.fft.fftshift(np.fft.ifft(np.fft.fftshift(x, axes=dim), axis=dim), axes=dim)
335
- return out
336
-
337
-
338
- def ft2(x, dim=(-2, -1)):
339
- """
340
- Process the 2D fast fourier transform and swaps the axis to get correct results using ftAxis
341
- Parameters
342
- ----------
343
- x: (ndarray) the array on which the FFT should be done
344
- dim: the axis over which is done the FFT (default is the last of the array)
345
-
346
- Returns
347
- -------
348
- See Also
349
- --------
350
- ftAxis, ftAxis_time, ift, ft2, ift2
351
- """
352
- assert isinstance(x, np.ndarray)
353
- if hasattr(dim, '__iter__'):
354
- for d in dim:
355
- if not isinstance(d, int):
356
- raise TypeError(
357
- 'elements in dim should be an integer specifying the array dimension over which to do the calculation')
358
- assert d <= len(x.shape)
359
- else:
360
- if not isinstance(dim, int):
361
- raise TypeError(
362
- 'elements in dim should be an integer specifying the array dimension over which to do the calculation')
363
- assert dim <= len(x.shape)
364
- out = np.fft.fftshift(np.fft.fft2(np.fft.fftshift(x, axes=dim)), axes=dim)
365
- return out
366
-
367
-
368
- def ift2(x, dim=(-2, -1)):
369
- """
370
- Process the inverse 2D fast fourier transform and swaps the axis to get correct results using ftAxis
371
- Parameters
372
- ----------
373
- x: (ndarray) the array on which the FFT should be done
374
- dim: the axis (or a tuple of axes) over which is done the FFT (default is the last of the array)
375
-
376
- Returns
377
- -------
378
- See Also
379
- --------
380
- ftAxis, ftAxis_time, ift, ft2, ift2
381
- """
382
- assert isinstance(x, np.ndarray)
383
- if hasattr(dim, '__iter__'):
384
- for d in dim:
385
- if not isinstance(d, int):
386
- raise TypeError(
387
- 'elements in dim should be an integer specifying the array dimension over which to do the calculation')
388
- assert d <= len(x.shape)
389
- else:
390
- if not isinstance(dim, int):
391
- raise TypeError(
392
- 'elements in dim should be an integer specifying the array dimension over which to do the calculation')
393
- assert dim <= len(x.shape)
394
- out = np.fft.fftshift(np.fft.ifft2(np.fft.fftshift(x, axes=dim)), axes=dim)
395
- return out
396
-
397
-
398
- class FourierFilterer(QObject):
399
- filter_changed = Signal(dict)
400
-
401
- def __init__(self, parent=None):
402
- super(FourierFilterer, self).__init__()
403
- if parent is None:
404
- parent = QtWidgets.QWidget()
405
-
406
- self.parent = parent
407
-
408
- self.raw_data = None
409
- self.data = None
410
- self.data_fft = None
411
- self.filter = None
412
- self.xaxis = None
413
- self.yaxis = None
414
- self.xaxisft = None
415
- self.yaxisft = None
416
-
417
- self.frequency = 0
418
- self.phase = 0
419
-
420
- self.c = None
421
- self.viewer2D = None
422
- self.setUI()
423
-
424
- def setUI(self):
425
- self.vlayout = QtWidgets.QVBoxLayout()
426
- self.parent.setLayout(self.vlayout)
427
-
428
- form = QtWidgets.QWidget()
429
- self.viewer1D = Viewer1DBasic(form)
430
- self.vlayout.addWidget(form)
431
- self.fftbutton1D = QtWidgets.QPushButton()
432
- self.fftbutton1D.setText("")
433
- icon = QtGui.QIcon()
434
- icon.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/FFT.png"), QtGui.QIcon.Normal,
435
- QtGui.QIcon.Off)
436
- self.fftbutton1D.setIcon(icon)
437
- self.fftbutton1D.setCheckable(True)
438
- self.fftbutton1D.clicked.connect(self.update_plot)
439
-
440
- vbox = self.viewer1D.parent.layout()
441
- widg = QtWidgets.QWidget()
442
- hbox = QtWidgets.QHBoxLayout()
443
- widg.setLayout(hbox)
444
- vbox.insertWidget(0, widg)
445
- hbox.addWidget(self.fftbutton1D)
446
- hbox.addStretch()
447
-
448
- self.viewer1D.ROI = LinearRegionItem(values=[0, 100])
449
- self.viewer1D.plotwidget.plotItem.addItem(self.viewer1D.ROI)
450
- self.data_filtered_plot = self.viewer1D.plotwidget.plotItem.plot()
451
- self.data_filtered_plot.setPen('w')
452
- self.viewer1D.ROI.sigRegionChangeFinished.connect(self.set_data)
453
-
454
- self.viewer1D.ROIfft = LinearRegionItem()
455
- self.viewer1D.plotwidget.plotItem.addItem(self.viewer1D.ROIfft)
456
- self.viewer1D.ROIfft.sigRegionChangeFinished.connect(self.update_filter)
457
-
458
- self.parent.show()
459
-
460
- def calculate_fft(self):
461
-
462
- ftaxis, axis = ftAxis_time(len(self.xaxis), np.max(self.xaxis) - np.min(self.xaxis))
463
- self.xaxisft = ftaxis / (2 * np.pi)
464
- self.data_fft = ft(self.data)
465
-
466
- def show_data(self, data):
467
- """
468
- show data and fft
469
- Parameters
470
- ----------
471
- data: (dict) with keys 'data', optionally 'xaxis' and 'yaxis'
472
- """
473
- try:
474
- self.raw_data = data
475
-
476
- if 'xaxis' in data:
477
- self.xaxis = data['xaxis']
478
- else:
479
- self.xaxis = np.arange(0, data['data'].shape[0], 1)
480
- self.raw_data['xaxis'] = self.xaxis
481
- # self.viewer1D.ROI.setRegion((np.min(self.xaxis), np.max(self.xaxis)))
482
- self.set_data()
483
- except Exception as e:
484
- logger.exception(str(e))
485
-
486
- def set_data(self):
487
- xlimits = self.viewer1D.ROI.getRegion()
488
- indexes = find_index(self.raw_data['xaxis'], xlimits)
489
- self.data = self.raw_data['data'][indexes[0][0]:indexes[1][0]]
490
- self.xaxis = self.raw_data['xaxis'][indexes[0][0]:indexes[1][0]]
491
- try:
492
- self.calculate_fft()
493
- except Exception as e:
494
- logger.exception(str(e))
495
- self.viewer1D.x_axis = self.xaxis
496
- self.update_plot()
497
-
498
- def update_filter(self):
499
- try:
500
- xmin, xmax = self.viewer1D.ROIfft.getRegion()
501
- self.filter = gauss1D(self.xaxisft, np.mean([xmin, xmax]), xmax - xmin)
502
- self.data = np.real(ift(self.filter * self.data_fft))
503
- index = np.argmax(self.filter * self.data_fft)
504
- self.frequency = self.xaxisft[index]
505
- self.phase = np.angle(self.data_fft[index])
506
-
507
- self.filter_changed.emit(dict(frequency=self.frequency, phase=self.phase))
508
- self.update_plot()
509
- except Exception as e:
510
- logger.exception(str(e))
511
-
512
- def update_plot(self):
513
-
514
- if self.fftbutton1D.isChecked():
515
- if self.data_fft is not None:
516
- if self.filter is not None:
517
- self.viewer1D.show_data([np.abs(self.data_fft), np.max(np.abs(self.data_fft)) * self.filter])
518
- else:
519
- self.viewer1D.show_data([np.abs(self.data_fft)])
520
- self.viewer1D.x_axis = dict(data=self.xaxisft, label='freq.')
521
- self.viewer1D.ROIfft.setVisible(True)
522
- self.viewer1D.ROI.setVisible(False)
523
- self.data_filtered_plot.setVisible(False)
524
- else:
525
- if self.raw_data is not None:
526
- self.viewer1D.show_data([self.raw_data['data']])
527
- self.viewer1D.x_axis = dict(data=self.raw_data['xaxis'], label='Pxls')
528
- self.data_filtered_plot.setData(self.xaxis, self.data)
529
- self.data_filtered_plot.setVisible(True)
530
- self.viewer1D.ROIfft.setVisible(False)
531
- self.viewer1D.ROI.setVisible(True)
532
-
533
-
534
- class LSqEllipse:
535
-
536
- def fit(self, data):
537
- """Lest Squares fitting algorithm
538
-
539
- Theory taken from (*)
540
- Solving equation Sa=lCa. with a = |a b c d f g> and a1 = |a b c>
541
- a2 = |d f g>
542
-
543
- Args
544
- ----
545
- data (list:list:float): list of two lists containing the x and y data of the
546
- ellipse. of the form [[x1, x2, ..., xi],[y1, y2, ..., yi]]
547
-
548
- Returns
549
- ------
550
- coef (list): list of the coefficients describing an ellipse
551
- [a,b,c,d,f,g] corresponding to ax**2+2bxy+cy**2+2dx+2fy+g
552
- """
553
- x, y = numpy.asarray(data, dtype=float)
554
-
555
- # Quadratic part of design matrix [eqn. 15] from (*)
556
- D1 = numpy.mat(numpy.vstack([x ** 2, x * y, y ** 2])).T
557
- # Linear part of design matrix [eqn. 16] from (*)
558
- D2 = numpy.mat(numpy.vstack([x, y, numpy.ones(len(x))])).T
559
-
560
- # forming scatter matrix [eqn. 17] from (*)
561
- S1 = D1.T * D1
562
- S2 = D1.T * D2
563
- S3 = D2.T * D2
564
-
565
- # Constraint matrix [eqn. 18]
566
- C1 = numpy.mat('0. 0. 2.; 0. -1. 0.; 2. 0. 0.')
567
-
568
- # Reduced scatter matrix [eqn. 29]
569
- M = C1.I * (S1 - S2 * S3.I * S2.T)
570
-
571
- # M*|a b c >=l|a b c >. Find eigenvalues and eigenvectors from this equation [eqn. 28]
572
- eval, evec = numpy.linalg.eig(M)
573
-
574
- # eigenvector must meet constraint 4ac - b^2 to be valid.
575
- cond = 4 * numpy.multiply(evec[0, :], evec[2, :]) - numpy.power(evec[1, :], 2)
576
- a1 = evec[:, numpy.nonzero(cond.A > 0)[1]]
577
-
578
- # |d f g> = -S3^(-1)*S2^(T)*|a b c> [eqn. 24]
579
- a2 = -S3.I * S2.T * a1
580
-
581
- # eigenvectors |a b c d f g>
582
- self.coef = numpy.vstack([a1, a2])
583
- self._save_parameters()
584
-
585
- def _save_parameters(self):
586
- """finds the important parameters of the fitted ellipse
587
-
588
- Theory taken form http://mathworld.wolfram
589
-
590
- Args
591
- -----
592
- coef (list): list of the coefficients describing an ellipse
593
- [a,b,c,d,f,g] corresponding to ax**2+2bxy+cy**2+2dx+2fy+g
594
-
595
- Returns
596
- _______
597
- center (List): of the form [x0, y0]
598
- width (float): major axis
599
- height (float): minor axis
600
- phi (float): rotation of major axis form the x-axis in radians
601
- """
602
-
603
- # eigenvectors are the coefficients of an ellipse in general form
604
- # a*x^2 + 2*b*x*y + c*y^2 + 2*d*x + 2*f*y + g = 0 [eqn. 15) from (**) or (***)
605
- a = self.coef[0, 0]
606
- b = self.coef[1, 0] / 2.
607
- c = self.coef[2, 0]
608
- d = self.coef[3, 0] / 2.
609
- f = self.coef[4, 0] / 2.
610
- g = self.coef[5, 0]
611
-
612
- # finding center of ellipse [eqn.19 and 20] from (**)
613
- x0 = (c * d - b * f) / (b ** 2. - a * c)
614
- y0 = (a * f - b * d) / (b ** 2. - a * c)
615
-
616
- # Find the semi-axes lengths [eqn. 21 and 22] from (**)
617
- numerator = 2 * (a * f * f + c * d * d + g * b * b - 2 * b * d * f - a * c * g)
618
- denominator1 = (b * b - a * c) * ((c - a) * numpy.sqrt(1 + 4 * b * b / ((a - c) * (a - c))) - (c + a))
619
- denominator2 = (b * b - a * c) * ((a - c) * numpy.sqrt(1 + 4 * b * b / ((a - c) * (a - c))) - (c + a))
620
- width = numpy.sqrt(numerator / denominator1)
621
- height = numpy.sqrt(numerator / denominator2)
622
-
623
- # angle of counterclockwise rotation of major-axis of ellipse to x-axis [eqn. 23] from (**)
624
- # or [eqn. 26] from (***).
625
- phi = .5 * numpy.arctan((2. * b) / (a - c))
626
-
627
- self._center = [x0, y0]
628
- self._width = width
629
- self._height = height
630
- self._phi = phi
631
-
632
- @property
633
- def center(self):
634
- return self._center
635
-
636
- @property
637
- def width(self):
638
- return self._width
639
-
640
- @property
641
- def height(self):
642
- return self._height
643
-
644
- @property
645
- def phi(self):
646
- """angle of counterclockwise rotation of major-axis of ellipse to x-axis
647
- [eqn. 23] from (**)
648
- """
649
- return self._phi
650
-
651
- def parameters(self):
652
- return self.center, self.width, self.height, self.phi
653
-
654
-
655
- def make_test_ellipse(center=[1, 1], width=1, height=.6, phi=3.14 / 5):
656
- """Generate Elliptical data with noise
657
-
658
- Args
659
- ----
660
- center (list:float): (<x_location>, <y_location>)
661
- width (float): semimajor axis. Horizontal dimension of the ellipse (**)
662
- height (float): semiminor axis. Vertical dimension of the ellipse (**)
663
- phi (float:radians): tilt of the ellipse, the angle the semimajor axis
664
- makes with the x-axis
665
-
666
- Returns
667
- -------
668
- data (list:list:float): list of two lists containing the x and y data of the
669
- ellipse. of the form [[x1, x2, ..., xi],[y1, y2, ..., yi]]
670
- """
671
- t = numpy.linspace(0, 2 * numpy.pi, 1000)
672
- x_noise, y_noise = numpy.random.rand(2, len(t))
673
-
674
- ellipse_x = center[0] + width * numpy.cos(t) * numpy.cos(phi) - height * numpy.sin(t) * numpy.sin(
675
- phi) + x_noise / 2.
676
- ellipse_y = center[1] + width * numpy.cos(t) * numpy.sin(phi) + height * numpy.sin(t) * numpy.cos(
677
- phi) + y_noise / 2.
678
-
679
- return [ellipse_x, ellipse_y]
680
-
681
-
682
-
683
- if __name__ == '__main__':
684
- import sys
685
-
686
- app = QtWidgets.QApplication(sys.argv)
687
- prog = FourierFilterer()
688
-
689
- from pymodaq.daq_utils.daq_utils import gauss1D
690
-
691
- xdata = np.linspace(0, 400, 401)
692
- x0 = 50
693
- dx = 20
694
- tau = 27
695
- tau2 = 100
696
- ydata_gauss = 10 * gauss1D(xdata, x0, dx) + np.random.rand(len(xdata))
697
- ydata_expodec = np.zeros((len(xdata)))
698
- ydata_expodec[:50] = 10 * gauss1D(xdata[:50], x0, dx, 2)
699
- ydata_expodec[50:] = 10 * np.exp(-(xdata[50:] - x0) / tau) # +10*np.exp(-(xdata[50:]-x0)/tau2)
700
- ydata_expodec += 2 * np.random.rand(len(xdata))
701
- ydata_sin = 10 + 2 * np.sin(2 * np.pi * 0.1 * xdata - np.deg2rad(55)) + np.sin(
702
- 2 * np.pi * 0.008 * xdata - np.deg2rad(-10)) + 2 * np.random.rand(len(xdata))
703
-
704
- prog.show_data(dict(data=ydata_sin, xaxis=xdata))
705
- sys.exit(app.exec_())
@@ -1 +0,0 @@
1
- from pyqtgraph.parametertree import parameterTypes, Parameter, ParameterTree