sigima 0.0.1.dev0__py3-none-any.whl → 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. sigima/__init__.py +142 -2
  2. sigima/client/__init__.py +105 -0
  3. sigima/client/base.py +780 -0
  4. sigima/client/remote.py +469 -0
  5. sigima/client/stub.py +814 -0
  6. sigima/client/utils.py +90 -0
  7. sigima/config.py +444 -0
  8. sigima/data/logo/Sigima.svg +135 -0
  9. sigima/data/tests/annotations.json +798 -0
  10. sigima/data/tests/curve_fitting/exponential_fit.txt +511 -0
  11. sigima/data/tests/curve_fitting/gaussian_fit.txt +100 -0
  12. sigima/data/tests/curve_fitting/piecewiseexponential_fit.txt +1022 -0
  13. sigima/data/tests/curve_fitting/polynomial_fit.txt +100 -0
  14. sigima/data/tests/curve_fitting/twohalfgaussian_fit.txt +1000 -0
  15. sigima/data/tests/curve_formats/bandwidth.txt +201 -0
  16. sigima/data/tests/curve_formats/boxcar.npy +0 -0
  17. sigima/data/tests/curve_formats/datetime.txt +1001 -0
  18. sigima/data/tests/curve_formats/dynamic_parameters.txt +4000 -0
  19. sigima/data/tests/curve_formats/fw1e2.txt +301 -0
  20. sigima/data/tests/curve_formats/fwhm.txt +319 -0
  21. sigima/data/tests/curve_formats/multiple_curves.csv +29 -0
  22. sigima/data/tests/curve_formats/noised_saw.mat +0 -0
  23. sigima/data/tests/curve_formats/oscilloscope.csv +111 -0
  24. sigima/data/tests/curve_formats/other/other2/recursive2.txt +5 -0
  25. sigima/data/tests/curve_formats/other/recursive1.txt +5 -0
  26. sigima/data/tests/curve_formats/paracetamol.npy +0 -0
  27. sigima/data/tests/curve_formats/paracetamol.txt +1010 -0
  28. sigima/data/tests/curve_formats/paracetamol_dx_dy.csv +1000 -0
  29. sigima/data/tests/curve_formats/paracetamol_dy.csv +1001 -0
  30. sigima/data/tests/curve_formats/pulse1.npy +0 -0
  31. sigima/data/tests/curve_formats/pulse2.npy +0 -0
  32. sigima/data/tests/curve_formats/simple.txt +5 -0
  33. sigima/data/tests/curve_formats/spectrum.mca +2139 -0
  34. sigima/data/tests/curve_formats/square2.npy +0 -0
  35. sigima/data/tests/curve_formats/step.npy +0 -0
  36. sigima/data/tests/fabry-perot1.jpg +0 -0
  37. sigima/data/tests/fabry-perot2.jpg +0 -0
  38. sigima/data/tests/flower.npy +0 -0
  39. sigima/data/tests/image_formats/NF 180338201.scor-data +11003 -0
  40. sigima/data/tests/image_formats/binary_image.npy +0 -0
  41. sigima/data/tests/image_formats/binary_image.png +0 -0
  42. sigima/data/tests/image_formats/centroid_test.npy +0 -0
  43. sigima/data/tests/image_formats/coordinated_text/complex_image.txt +10011 -0
  44. sigima/data/tests/image_formats/coordinated_text/complex_ref_image.txt +10010 -0
  45. sigima/data/tests/image_formats/coordinated_text/image.txt +15 -0
  46. sigima/data/tests/image_formats/coordinated_text/image2.txt +14 -0
  47. sigima/data/tests/image_formats/coordinated_text/image_no_unit_no_label.txt +14 -0
  48. sigima/data/tests/image_formats/coordinated_text/image_with_nan.txt +15 -0
  49. sigima/data/tests/image_formats/coordinated_text/image_with_unit.txt +14 -0
  50. sigima/data/tests/image_formats/fiber.csv +480 -0
  51. sigima/data/tests/image_formats/fiber.jpg +0 -0
  52. sigima/data/tests/image_formats/fiber.png +0 -0
  53. sigima/data/tests/image_formats/fiber.txt +480 -0
  54. sigima/data/tests/image_formats/gaussian_spot_with_noise.npy +0 -0
  55. sigima/data/tests/image_formats/mr-brain.dcm +0 -0
  56. sigima/data/tests/image_formats/noised_gaussian.mat +0 -0
  57. sigima/data/tests/image_formats/sif_reader/nd_lum_image_no_glue.sif +0 -0
  58. sigima/data/tests/image_formats/sif_reader/raman1.sif +0 -0
  59. sigima/data/tests/image_formats/tiling.txt +10 -0
  60. sigima/data/tests/image_formats/uint16.tiff +0 -0
  61. sigima/data/tests/image_formats/uint8.tiff +0 -0
  62. sigima/data/tests/laser_beam/TEM00_z_13.jpg +0 -0
  63. sigima/data/tests/laser_beam/TEM00_z_18.jpg +0 -0
  64. sigima/data/tests/laser_beam/TEM00_z_23.jpg +0 -0
  65. sigima/data/tests/laser_beam/TEM00_z_30.jpg +0 -0
  66. sigima/data/tests/laser_beam/TEM00_z_35.jpg +0 -0
  67. sigima/data/tests/laser_beam/TEM00_z_40.jpg +0 -0
  68. sigima/data/tests/laser_beam/TEM00_z_45.jpg +0 -0
  69. sigima/data/tests/laser_beam/TEM00_z_50.jpg +0 -0
  70. sigima/data/tests/laser_beam/TEM00_z_55.jpg +0 -0
  71. sigima/data/tests/laser_beam/TEM00_z_60.jpg +0 -0
  72. sigima/data/tests/laser_beam/TEM00_z_65.jpg +0 -0
  73. sigima/data/tests/laser_beam/TEM00_z_70.jpg +0 -0
  74. sigima/data/tests/laser_beam/TEM00_z_75.jpg +0 -0
  75. sigima/data/tests/laser_beam/TEM00_z_80.jpg +0 -0
  76. sigima/enums.py +195 -0
  77. sigima/io/__init__.py +123 -0
  78. sigima/io/base.py +311 -0
  79. sigima/io/common/__init__.py +5 -0
  80. sigima/io/common/basename.py +164 -0
  81. sigima/io/common/converters.py +189 -0
  82. sigima/io/common/objmeta.py +181 -0
  83. sigima/io/common/textreader.py +58 -0
  84. sigima/io/convenience.py +157 -0
  85. sigima/io/enums.py +17 -0
  86. sigima/io/ftlab.py +395 -0
  87. sigima/io/image/__init__.py +9 -0
  88. sigima/io/image/base.py +177 -0
  89. sigima/io/image/formats.py +1016 -0
  90. sigima/io/image/funcs.py +414 -0
  91. sigima/io/signal/__init__.py +9 -0
  92. sigima/io/signal/base.py +129 -0
  93. sigima/io/signal/formats.py +290 -0
  94. sigima/io/signal/funcs.py +723 -0
  95. sigima/objects/__init__.py +260 -0
  96. sigima/objects/base.py +937 -0
  97. sigima/objects/image/__init__.py +88 -0
  98. sigima/objects/image/creation.py +556 -0
  99. sigima/objects/image/object.py +524 -0
  100. sigima/objects/image/roi.py +904 -0
  101. sigima/objects/scalar/__init__.py +57 -0
  102. sigima/objects/scalar/common.py +215 -0
  103. sigima/objects/scalar/geometry.py +502 -0
  104. sigima/objects/scalar/table.py +784 -0
  105. sigima/objects/shape.py +290 -0
  106. sigima/objects/signal/__init__.py +133 -0
  107. sigima/objects/signal/constants.py +27 -0
  108. sigima/objects/signal/creation.py +1428 -0
  109. sigima/objects/signal/object.py +444 -0
  110. sigima/objects/signal/roi.py +274 -0
  111. sigima/params.py +405 -0
  112. sigima/proc/__init__.py +96 -0
  113. sigima/proc/base.py +381 -0
  114. sigima/proc/decorator.py +330 -0
  115. sigima/proc/image/__init__.py +513 -0
  116. sigima/proc/image/arithmetic.py +335 -0
  117. sigima/proc/image/base.py +260 -0
  118. sigima/proc/image/detection.py +519 -0
  119. sigima/proc/image/edges.py +329 -0
  120. sigima/proc/image/exposure.py +406 -0
  121. sigima/proc/image/extraction.py +458 -0
  122. sigima/proc/image/filtering.py +219 -0
  123. sigima/proc/image/fourier.py +147 -0
  124. sigima/proc/image/geometry.py +661 -0
  125. sigima/proc/image/mathops.py +340 -0
  126. sigima/proc/image/measurement.py +195 -0
  127. sigima/proc/image/morphology.py +155 -0
  128. sigima/proc/image/noise.py +107 -0
  129. sigima/proc/image/preprocessing.py +182 -0
  130. sigima/proc/image/restoration.py +235 -0
  131. sigima/proc/image/threshold.py +217 -0
  132. sigima/proc/image/transformations.py +393 -0
  133. sigima/proc/signal/__init__.py +376 -0
  134. sigima/proc/signal/analysis.py +206 -0
  135. sigima/proc/signal/arithmetic.py +551 -0
  136. sigima/proc/signal/base.py +262 -0
  137. sigima/proc/signal/extraction.py +60 -0
  138. sigima/proc/signal/features.py +310 -0
  139. sigima/proc/signal/filtering.py +484 -0
  140. sigima/proc/signal/fitting.py +276 -0
  141. sigima/proc/signal/fourier.py +259 -0
  142. sigima/proc/signal/mathops.py +420 -0
  143. sigima/proc/signal/processing.py +580 -0
  144. sigima/proc/signal/stability.py +175 -0
  145. sigima/proc/title_formatting.py +227 -0
  146. sigima/proc/validation.py +272 -0
  147. sigima/tests/__init__.py +7 -0
  148. sigima/tests/common/__init__.py +0 -0
  149. sigima/tests/common/arithmeticparam_unit_test.py +26 -0
  150. sigima/tests/common/basename_unit_test.py +126 -0
  151. sigima/tests/common/client_unit_test.py +412 -0
  152. sigima/tests/common/converters_unit_test.py +77 -0
  153. sigima/tests/common/decorator_unit_test.py +176 -0
  154. sigima/tests/common/examples_unit_test.py +104 -0
  155. sigima/tests/common/kernel_normalization_unit_test.py +242 -0
  156. sigima/tests/common/roi_basic_unit_test.py +73 -0
  157. sigima/tests/common/roi_geometry_unit_test.py +171 -0
  158. sigima/tests/common/scalar_builder_unit_test.py +142 -0
  159. sigima/tests/common/scalar_unit_test.py +991 -0
  160. sigima/tests/common/shape_unit_test.py +183 -0
  161. sigima/tests/common/stat_unit_test.py +138 -0
  162. sigima/tests/common/title_formatting_unit_test.py +338 -0
  163. sigima/tests/common/tools_coordinates_unit_test.py +60 -0
  164. sigima/tests/common/transformations_unit_test.py +178 -0
  165. sigima/tests/common/validation_unit_test.py +205 -0
  166. sigima/tests/conftest.py +129 -0
  167. sigima/tests/data.py +998 -0
  168. sigima/tests/env.py +280 -0
  169. sigima/tests/guiutils.py +163 -0
  170. sigima/tests/helpers.py +532 -0
  171. sigima/tests/image/__init__.py +28 -0
  172. sigima/tests/image/binning_unit_test.py +128 -0
  173. sigima/tests/image/blob_detection_unit_test.py +312 -0
  174. sigima/tests/image/centroid_unit_test.py +170 -0
  175. sigima/tests/image/check_2d_array_unit_test.py +63 -0
  176. sigima/tests/image/contour_unit_test.py +172 -0
  177. sigima/tests/image/convolution_unit_test.py +178 -0
  178. sigima/tests/image/datatype_unit_test.py +67 -0
  179. sigima/tests/image/edges_unit_test.py +155 -0
  180. sigima/tests/image/enclosingcircle_unit_test.py +88 -0
  181. sigima/tests/image/exposure_unit_test.py +223 -0
  182. sigima/tests/image/fft2d_unit_test.py +189 -0
  183. sigima/tests/image/filtering_unit_test.py +166 -0
  184. sigima/tests/image/geometry_unit_test.py +654 -0
  185. sigima/tests/image/hough_circle_unit_test.py +147 -0
  186. sigima/tests/image/imageobj_unit_test.py +737 -0
  187. sigima/tests/image/morphology_unit_test.py +71 -0
  188. sigima/tests/image/noise_unit_test.py +57 -0
  189. sigima/tests/image/offset_correction_unit_test.py +72 -0
  190. sigima/tests/image/operation_unit_test.py +518 -0
  191. sigima/tests/image/peak2d_limits_unit_test.py +41 -0
  192. sigima/tests/image/peak2d_unit_test.py +133 -0
  193. sigima/tests/image/profile_unit_test.py +159 -0
  194. sigima/tests/image/projections_unit_test.py +121 -0
  195. sigima/tests/image/restoration_unit_test.py +141 -0
  196. sigima/tests/image/roi2dparam_unit_test.py +53 -0
  197. sigima/tests/image/roi_advanced_unit_test.py +588 -0
  198. sigima/tests/image/roi_grid_unit_test.py +279 -0
  199. sigima/tests/image/spectrum2d_unit_test.py +40 -0
  200. sigima/tests/image/threshold_unit_test.py +91 -0
  201. sigima/tests/io/__init__.py +0 -0
  202. sigima/tests/io/addnewformat_unit_test.py +125 -0
  203. sigima/tests/io/convenience_funcs_unit_test.py +470 -0
  204. sigima/tests/io/coordinated_text_format_unit_test.py +495 -0
  205. sigima/tests/io/datetime_csv_unit_test.py +198 -0
  206. sigima/tests/io/imageio_formats_test.py +41 -0
  207. sigima/tests/io/ioregistry_unit_test.py +69 -0
  208. sigima/tests/io/objmeta_unit_test.py +87 -0
  209. sigima/tests/io/readobj_unit_test.py +130 -0
  210. sigima/tests/io/readwriteobj_unit_test.py +67 -0
  211. sigima/tests/signal/__init__.py +0 -0
  212. sigima/tests/signal/analysis_unit_test.py +135 -0
  213. sigima/tests/signal/check_1d_arrays_unit_test.py +169 -0
  214. sigima/tests/signal/convolution_unit_test.py +404 -0
  215. sigima/tests/signal/datetime_unit_test.py +176 -0
  216. sigima/tests/signal/fft1d_unit_test.py +303 -0
  217. sigima/tests/signal/filters_unit_test.py +403 -0
  218. sigima/tests/signal/fitting_unit_test.py +929 -0
  219. sigima/tests/signal/fwhm_unit_test.py +111 -0
  220. sigima/tests/signal/noise_unit_test.py +128 -0
  221. sigima/tests/signal/offset_correction_unit_test.py +34 -0
  222. sigima/tests/signal/operation_unit_test.py +489 -0
  223. sigima/tests/signal/peakdetection_unit_test.py +145 -0
  224. sigima/tests/signal/processing_unit_test.py +657 -0
  225. sigima/tests/signal/pulse/__init__.py +112 -0
  226. sigima/tests/signal/pulse/crossing_times_unit_test.py +123 -0
  227. sigima/tests/signal/pulse/plateau_detection_unit_test.py +102 -0
  228. sigima/tests/signal/pulse/pulse_unit_test.py +1824 -0
  229. sigima/tests/signal/roi_advanced_unit_test.py +392 -0
  230. sigima/tests/signal/signalobj_unit_test.py +603 -0
  231. sigima/tests/signal/stability_unit_test.py +431 -0
  232. sigima/tests/signal/uncertainty_unit_test.py +611 -0
  233. sigima/tests/vistools.py +1030 -0
  234. sigima/tools/__init__.py +59 -0
  235. sigima/tools/checks.py +290 -0
  236. sigima/tools/coordinates.py +308 -0
  237. sigima/tools/datatypes.py +26 -0
  238. sigima/tools/image/__init__.py +97 -0
  239. sigima/tools/image/detection.py +451 -0
  240. sigima/tools/image/exposure.py +77 -0
  241. sigima/tools/image/extraction.py +48 -0
  242. sigima/tools/image/fourier.py +260 -0
  243. sigima/tools/image/geometry.py +190 -0
  244. sigima/tools/image/preprocessing.py +165 -0
  245. sigima/tools/signal/__init__.py +86 -0
  246. sigima/tools/signal/dynamic.py +254 -0
  247. sigima/tools/signal/features.py +135 -0
  248. sigima/tools/signal/filtering.py +171 -0
  249. sigima/tools/signal/fitting.py +1171 -0
  250. sigima/tools/signal/fourier.py +466 -0
  251. sigima/tools/signal/interpolation.py +70 -0
  252. sigima/tools/signal/peakdetection.py +126 -0
  253. sigima/tools/signal/pulse.py +1626 -0
  254. sigima/tools/signal/scaling.py +50 -0
  255. sigima/tools/signal/stability.py +258 -0
  256. sigima/tools/signal/windowing.py +90 -0
  257. sigima/worker.py +79 -0
  258. sigima-1.0.0.dist-info/METADATA +233 -0
  259. sigima-1.0.0.dist-info/RECORD +262 -0
  260. {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/licenses/LICENSE +29 -29
  261. sigima-0.0.1.dev0.dist-info/METADATA +0 -60
  262. sigima-0.0.1.dev0.dist-info/RECORD +0 -6
  263. {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/WHEEL +0 -0
  264. {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,420 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Mathematical operations on signals
5
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import warnings
11
+
12
+ import guidata.dataset as gds
13
+ import numpy as np
14
+
15
+ from sigima.config import _
16
+ from sigima.enums import AngleUnit
17
+ from sigima.objects import SignalObj
18
+ from sigima.proc.base import AngleUnitParam, PhaseParam, dst_1_to_1, dst_2_to_1
19
+ from sigima.proc.decorator import computation_function
20
+ from sigima.proc.signal.base import (
21
+ Wrap1to1Func,
22
+ is_uncertainty_data_available,
23
+ restore_data_outside_roi,
24
+ )
25
+ from sigima.tools import coordinates
26
+
27
+
28
+ @computation_function()
29
+ def transpose(src: SignalObj) -> SignalObj:
30
+ """Transpose signal (swap X and Y axes).
31
+
32
+ Args:
33
+ src: Source signal.
34
+
35
+ Returns:
36
+ Result signal object.
37
+ """
38
+ dst = dst_1_to_1(src, "transpose")
39
+ x, y = src.get_data()
40
+ dst.set_xydata(y, x, src.dy, src.dx)
41
+ dst.xlabel = src.ylabel
42
+ dst.ylabel = src.xlabel
43
+ dst.xunit = src.yunit
44
+ dst.yunit = src.xunit
45
+ return dst
46
+
47
+
48
+ @computation_function()
49
+ def inverse(src: SignalObj) -> SignalObj:
50
+ """Compute the element-wise inverse of a signal.
51
+
52
+ The function computes the reciprocal (1/y) of each element of the input signal.
53
+
54
+ .. note::
55
+
56
+ If the signal has a region of interest (ROI), the inverse is performed
57
+ only within the ROI.
58
+
59
+ .. note::
60
+
61
+ Uncertainties are propagated.
62
+
63
+ Args:
64
+ src: Input signal object.
65
+
66
+ Returns:
67
+ Result signal object representing the inverse of the input signal.
68
+ """
69
+ dst = dst_1_to_1(src, "invert")
70
+ x, y = src.get_data()
71
+ with warnings.catch_warnings():
72
+ warnings.simplefilter("ignore", category=RuntimeWarning)
73
+ dst.set_xydata(x, np.reciprocal(y))
74
+ dst.y[np.isinf(dst.y)] = np.nan
75
+ if is_uncertainty_data_available(src):
76
+ err = np.abs(dst.y) * (src.dy / np.abs(src.y))
77
+ err[np.isinf(err)] = np.nan
78
+ dst.dy = err
79
+ restore_data_outside_roi(dst, src)
80
+ return dst
81
+
82
+
83
+ @computation_function()
84
+ def absolute(src: SignalObj) -> SignalObj:
85
+ """Compute absolute value with :py:data:`numpy.absolute`
86
+
87
+ Args:
88
+ src: source signal
89
+
90
+ Returns:
91
+ Result signal object
92
+ """
93
+ return Wrap1to1Func(np.absolute)(src)
94
+
95
+
96
+ @computation_function()
97
+ def real(src: SignalObj) -> SignalObj:
98
+ """Compute real part with :py:func:`numpy.real`
99
+
100
+ Args:
101
+ src: source signal
102
+
103
+ Returns:
104
+ Result signal object
105
+ """
106
+ return Wrap1to1Func(np.real)(src)
107
+
108
+
109
+ @computation_function()
110
+ def imag(src: SignalObj) -> SignalObj:
111
+ """Compute imaginary part with :py:func:`numpy.imag`
112
+
113
+ Args:
114
+ src: source signal
115
+
116
+ Returns:
117
+ Result signal object
118
+ """
119
+ return Wrap1to1Func(np.imag)(src)
120
+
121
+
122
+ @computation_function()
123
+ def phase(src: SignalObj, p: PhaseParam) -> SignalObj:
124
+ """Compute the phase (argument) of a complex signal.
125
+
126
+ The function uses :py:func:`numpy.angle` to compute the argument and
127
+ :py:func:`numpy.unwrap` to unwrap it.
128
+
129
+ Args:
130
+ src: Input signal object.
131
+ p: Phase parameters.
132
+
133
+ Returns:
134
+ Signal object containing the phase, optionally unwrapped.
135
+ """
136
+ suffix = "unwrap" if p.unwrap else ""
137
+ dst = dst_1_to_1(src, "phase", suffix)
138
+ x, y = src.get_data()
139
+ argument = np.angle(y)
140
+ if p.unwrap:
141
+ argument = np.unwrap(argument)
142
+ if p.unit == AngleUnit.DEGREE:
143
+ argument = np.rad2deg(argument)
144
+ dst.set_xydata(x, argument, src.dx, None)
145
+ dst.yunit = p.unit
146
+ restore_data_outside_roi(dst, src)
147
+ return dst
148
+
149
+
150
+ @computation_function()
151
+ def complex_from_real_imag(src1: SignalObj, src2: SignalObj) -> SignalObj:
152
+ """Combine two real signals into a complex signal using real + i * imag.
153
+
154
+ .. warning::
155
+
156
+ The x coordinates of the two signals must be the same.
157
+
158
+ Args:
159
+ src1: Real part signal.
160
+ src2: Imaginary part signal.
161
+
162
+ Returns:
163
+ Result signal object with complex-valued y.
164
+ """
165
+ if not np.array_equal(src1.x, src2.x):
166
+ warnings.warn(
167
+ "The x coordinates of the two signals are not the same. "
168
+ "Results may be incorrect."
169
+ )
170
+ dst = dst_2_to_1(src1, src2, "real_imag")
171
+ y = src1.y + 1j * src2.y
172
+ dst.set_xydata(src1.x, y, src1.dx, None)
173
+ return dst
174
+
175
+
176
+ @computation_function()
177
+ def complex_from_magnitude_phase(
178
+ src1: SignalObj, src2: SignalObj, p: AngleUnitParam
179
+ ) -> SignalObj:
180
+ """Combine magnitude and phase signals into a complex signal.
181
+
182
+ .. warning::
183
+
184
+ The x coordinates of the two signals must be the same.
185
+
186
+ .. warning::
187
+
188
+ Negative values are not allowed for the radius and will be clipped to 0.
189
+
190
+ Args:
191
+ src1: Magnitude (module) signal.
192
+ src2: Phase (argument) signal.
193
+ p: Parameters (must provide unit for the phase).
194
+
195
+ Returns:
196
+ Result signal object with complex-valued y.
197
+ """
198
+ if not np.array_equal(src1.x, src2.x):
199
+ warnings.warn(
200
+ "The x coordinates of the two signals are not the same. "
201
+ "Results may be incorrect."
202
+ )
203
+ if np.any(src1.y < 0.0):
204
+ warnings.warn("Negative radius values are not allowed. They will be set to 0.")
205
+ src1.y = np.maximum(src1.y, 0.0)
206
+ dst = dst_2_to_1(src1, src2, "mag_phase")
207
+ assert p.unit is not None
208
+ y = coordinates.polar_to_complex(src1.y, src2.y, unit=p.unit)
209
+ dst.set_xydata(src1.x, y, src1.x, None)
210
+ return dst
211
+
212
+
213
+ class DataTypeSParam(gds.DataSet, title=_("Convert data type")):
214
+ """Convert signal data type parameters"""
215
+
216
+ dtype_str = gds.ChoiceItem(
217
+ _("Destination data type"),
218
+ list(zip(SignalObj.get_valid_dtypenames(), SignalObj.get_valid_dtypenames())),
219
+ help=_("Output image data type."),
220
+ )
221
+
222
+
223
+ @computation_function()
224
+ def astype(src: SignalObj, p: DataTypeSParam) -> SignalObj:
225
+ """Convert data type with :py:func:`numpy.astype`
226
+
227
+ Args:
228
+ src: source signal
229
+ p: parameters
230
+
231
+ Returns:
232
+ Result signal object
233
+ """
234
+ dst = dst_1_to_1(src, "astype", f"dtype={p.dtype_str}")
235
+ dst.xydata = src.xydata.astype(p.dtype_str)
236
+ return dst
237
+
238
+
239
+ @computation_function()
240
+ def log10(src: SignalObj) -> SignalObj:
241
+ """Compute Log10 with :py:data:`numpy.log10`
242
+
243
+ Args:
244
+ src: source signal
245
+
246
+ Returns:
247
+ Result signal object
248
+ """
249
+ dst = dst_1_to_1(src, "log10")
250
+ x, y = src.get_data()
251
+
252
+ # Compute result
253
+ result_y = np.log10(y)
254
+ dst.set_xydata(x, result_y, src.dx, src.dy)
255
+
256
+ # Uncertainty propagation: σ(log₁₀(y)) = σ(y) / (y * ln(10))
257
+ if is_uncertainty_data_available(src):
258
+ with warnings.catch_warnings():
259
+ warnings.simplefilter("ignore", category=RuntimeWarning)
260
+ dst.dy = src.dy / (y * np.log(10))
261
+ dst.dy[np.isinf(dst.dy) | np.isnan(dst.dy)] = np.nan
262
+
263
+ restore_data_outside_roi(dst, src)
264
+ return dst
265
+
266
+
267
+ @computation_function()
268
+ def exp(src: SignalObj) -> SignalObj:
269
+ """Compute exponential with :py:data:`numpy.exp`
270
+
271
+ Args:
272
+ src: source signal
273
+
274
+ Returns:
275
+ Result signal object
276
+ """
277
+ dst = dst_1_to_1(src, "exp")
278
+ x, y = src.get_data()
279
+
280
+ # Compute result
281
+ result_y = np.exp(y)
282
+ dst.set_xydata(x, result_y, src.dx, src.dy)
283
+
284
+ # Uncertainty propagation: σ(eʸ) = eʸ * σ(y)
285
+ if is_uncertainty_data_available(src):
286
+ dst.dy = np.abs(result_y) * src.dy
287
+
288
+ restore_data_outside_roi(dst, src)
289
+ return dst
290
+
291
+
292
+ @computation_function()
293
+ def sqrt(src: SignalObj) -> SignalObj:
294
+ """Compute square root with :py:data:`numpy.sqrt`
295
+
296
+ Args:
297
+ src: source signal
298
+
299
+ Returns:
300
+ Result signal object
301
+ """
302
+ dst = dst_1_to_1(src, "sqrt")
303
+ x, y = src.get_data()
304
+
305
+ # Compute result
306
+ result_y = np.sqrt(y)
307
+ dst.set_xydata(x, result_y, src.dx, src.dy)
308
+
309
+ # Uncertainty propagation: σ(√y) = σ(y) / (2√y)
310
+ if is_uncertainty_data_available(src):
311
+ with warnings.catch_warnings():
312
+ warnings.simplefilter("ignore", category=RuntimeWarning)
313
+ dst.dy = src.dy / (2 * np.sqrt(y))
314
+ dst.dy[np.isinf(dst.dy) | np.isnan(dst.dy)] = np.nan
315
+
316
+ restore_data_outside_roi(dst, src)
317
+ return dst
318
+
319
+
320
+ class PowerParam(gds.DataSet, title=_("Power")):
321
+ """Power parameters"""
322
+
323
+ power = gds.FloatItem(_("Power"), default=2.0)
324
+
325
+
326
+ @computation_function()
327
+ def power(src: SignalObj, p: PowerParam) -> SignalObj:
328
+ """Compute power with :py:data:`numpy.power`
329
+
330
+ Args:
331
+ src: source signal
332
+ p: parameters
333
+
334
+ Returns:
335
+ Result signal object
336
+ """
337
+ dst = dst_1_to_1(src, "^", str(p.power))
338
+ dst.y = np.power(src.y, p.power)
339
+
340
+ # Uncertainty propagation: σ(y^n) = |n * y^(n-1)| * σ(y)
341
+ if is_uncertainty_data_available(src):
342
+ with warnings.catch_warnings():
343
+ warnings.simplefilter("ignore", category=RuntimeWarning)
344
+ dst.dy *= np.abs(p.power * np.power(src.y, p.power - 1))
345
+ dst.dy[np.isinf(dst.dy) | np.isnan(dst.dy)] = np.nan
346
+
347
+ restore_data_outside_roi(dst, src)
348
+ return dst
349
+
350
+
351
+ @computation_function()
352
+ def to_polar(src: SignalObj, p: AngleUnitParam) -> SignalObj:
353
+ """Convert Cartesian coordinates to polar coordinates.
354
+
355
+ This function converts the x and y coordinates of a signal to polar coordinates
356
+ using :py:func:`sigima.tools.coordinates.to_polar`.
357
+
358
+ .. warning::
359
+
360
+ X and y must share the same units for the computation to make sense.
361
+
362
+ Args:
363
+ src: Source signal.
364
+ p: Parameters.
365
+
366
+ Returns:
367
+ Result signal object.
368
+
369
+ Raises:
370
+ ValueError: If the x and y units are not the same.
371
+ """
372
+ assert p.unit is not None
373
+ if src.xunit != src.yunit:
374
+ warnings.warn(
375
+ f"X and y units are not the same: {src.xunit} != {src.yunit}. "
376
+ "Results will be incorrect."
377
+ )
378
+ dst = dst_1_to_1(src, "Polar coordinates", f"unit={p.unit}")
379
+ x, y = src.get_data()
380
+ r, theta = coordinates.to_polar(x, y, p.unit)
381
+ dst.set_xydata(r, theta)
382
+ dst.xlabel = _("Radius")
383
+ dst.ylabel = _("Angle")
384
+ dst.yunit = p.unit
385
+ return dst
386
+
387
+
388
+ @computation_function()
389
+ def to_cartesian(src: SignalObj, p: AngleUnitParam) -> SignalObj:
390
+ """Convert polar coordinates to Cartesian coordinates.
391
+
392
+ This function converts the r and theta coordinates of a signal to Cartesian
393
+ coordinates using :py:func:`sigima.tools.coordinates.to_cartesian`.
394
+
395
+ .. note::
396
+
397
+ It is assumed that the x-axis represents the radius and the y-axis the angle.
398
+
399
+ .. warning::
400
+
401
+ Negative values are not allowed for the radius and will be clipped to 0.
402
+
403
+ Args:
404
+ src: Source signal.
405
+ p: Parameters.
406
+
407
+ Returns:
408
+ Result signal object.
409
+ """
410
+ dst = dst_1_to_1(src, "Cartesian coordinates", f"unit={p.unit}")
411
+ r, theta = src.get_data()
412
+ if np.any(r < 0.0):
413
+ warnings.warn("Negative radius values are not allowed. They will be set to 0.")
414
+ r = np.maximum(r, 0.0)
415
+ x, y = coordinates.to_cartesian(r, theta, p.unit)
416
+ dst.set_xydata(x, y)
417
+ dst.xlabel = _("x")
418
+ dst.ylabel = _("y")
419
+ dst.yunit = src.xunit
420
+ return dst