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,96 @@
1
+ """
2
+ Computation (:mod:`sigima.proc`)
3
+ --------------------------------
4
+
5
+ This package contains the Sigima computation functions that implement processing
6
+ features for signal, image and scalar objects. These functions are designed to operate
7
+ directly on :class:`sigima.objects.SignalObj`, :class:`sigima.objects.ImageObj`,
8
+ :class:`sigima.objects.GeometryResult` and :class:`sigima.objects.TableResult` objects,
9
+ which are defined in the :mod:`sigima.objects` package.
10
+
11
+ Even though these functions are primarily designed to be used in the Sigima pipeline,
12
+ they can also be used independently.
13
+
14
+ .. seealso::
15
+
16
+ See the :mod:`sigima.tools` package for some algorithms that operate directly on
17
+ NumPy arrays.
18
+
19
+ Each computation module defines a set of computation objects, that is, functions
20
+ that implement processing features and classes that implement the corresponding
21
+ parameters (in the form of :py:class:`guidata.dataset.datatypes.Dataset` subclasses).
22
+ The computation functions takes a signal or image object
23
+ (e.g. :py:class:`sigima.objects.SignalObj`)
24
+ and a parameter object (e.g. :py:class:`sigima.params.MovingAverageParam`) as input
25
+ and return a signal or image object as output (the result of the computation).
26
+ The parameter object is used to configure the computation function
27
+ (e.g. the size of the moving average window).
28
+
29
+ In Sigima overall architecture, the purpose of this package is to provide the
30
+ computation functions that are used by DataLab processor modules,
31
+ based on the algorithms defined in the :mod:`sigima.tools` module and on the
32
+ data model defined in the :mod:`sigima.objects` module.
33
+
34
+ The computation modules are organized in subpackages according to their purpose.
35
+ The following subpackages are available:
36
+
37
+ - :mod:`sigima.proc.base`: Common processing features
38
+ - :mod:`sigima.proc.signal`: Signal processing features
39
+ - :mod:`sigima.proc.image`: Image processing features (including transformations)
40
+
41
+ Common processing features
42
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
43
+
44
+ .. automodule:: sigima.proc.base
45
+ :members:
46
+
47
+ Signal processing features
48
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^
49
+
50
+ .. automodule:: sigima.proc.signal
51
+ :members:
52
+
53
+ Image processing features
54
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
55
+
56
+ .. automodule:: sigima.proc.image
57
+ :members:
58
+
59
+ Decorators and utilities
60
+ ^^^^^^^^^^^^^^^^^^^^^^^^
61
+
62
+ This package also provides some utility functions to help with the creation and
63
+ introspection of computation functions:
64
+
65
+ .. autofunction:: sigima.proc.decorator.computation_function
66
+ .. autofunction:: sigima.proc.decorator.is_computation_function
67
+ .. autofunction:: sigima.proc.decorator.get_computation_metadata
68
+ .. autofunction:: sigima.proc.decorator.find_computation_functions
69
+
70
+ Title Formatting System
71
+ ^^^^^^^^^^^^^^^^^^^^^^^
72
+
73
+ The title formatting system provides configurable title generation for computation
74
+ results, enabling different applications (Sigima standalone vs DataLab integration)
75
+ to use different title formatting strategies:
76
+
77
+ .. automodule:: sigima.proc.title_formatting
78
+ :members:
79
+ """
80
+
81
+ # Import title formatting components for easy access
82
+ from sigima.proc.title_formatting import (
83
+ PlaceholderTitleFormatter,
84
+ SimpleTitleFormatter,
85
+ TitleFormatter,
86
+ get_default_title_formatter,
87
+ set_default_title_formatter,
88
+ )
89
+
90
+ __all__ = [
91
+ "PlaceholderTitleFormatter",
92
+ "SimpleTitleFormatter",
93
+ "TitleFormatter",
94
+ "get_default_title_formatter",
95
+ "set_default_title_formatter",
96
+ ]
sigima/proc/base.py ADDED
@@ -0,0 +1,381 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ .. Common computation objects (see parent package :mod:`sigima.computation`)
5
+ """
6
+
7
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
8
+
9
+ # Note:
10
+ # ----
11
+ # All dataset classes must also be imported in the sigima.params module.
12
+
13
+ from __future__ import annotations
14
+
15
+ from typing import TypeVar, cast
16
+
17
+ import guidata.dataset as gds
18
+ import numpy as np
19
+
20
+ from sigima import ImageObj, SignalObj, create_signal
21
+ from sigima.config import _, options
22
+ from sigima.enums import (
23
+ AngleUnit,
24
+ FilterMode,
25
+ MathOperator,
26
+ NormalizationMethod,
27
+ SignalsToImageOrientation,
28
+ )
29
+ from sigima.proc.title_formatting import get_default_title_formatter
30
+
31
+ # NOTE: This module is a shared utilities library that defines common parameter classes
32
+ # used by multiple other modules (signal processing, image processing, etc.).
33
+ # Unlike other modules, the parameter classes DEFINED in this module should NOT be
34
+ # included in __all__ because they are imported and re-exported by the modules that
35
+ # use them, and including them here would create Sphinx cross-reference conflicts.
36
+ # The sigima.params module serves as the central API point that imports and re-exports
37
+ # all parameter classes from their canonical locations.
38
+ __all__ = [
39
+ "dst_1_to_1",
40
+ "dst_2_to_1",
41
+ "dst_n_to_1",
42
+ "new_signal_result",
43
+ ]
44
+
45
+
46
+ class ArithmeticParam(gds.DataSet, title=_("Arithmetic")):
47
+ """Arithmetic parameters"""
48
+
49
+ def get_operation(self) -> str:
50
+ """Return the operation string"""
51
+ o, a, b = self.operator, self.factor, self.constant
52
+ b_added = False
53
+ if a == 0.0:
54
+ if o in ("+", "-"):
55
+ txt = "obj3 = obj1"
56
+ elif b == 0.0:
57
+ txt = "obj3 = 0"
58
+ else:
59
+ txt = f"obj3 = {b}"
60
+ b_added = True
61
+ elif a == 1.0:
62
+ txt = f"obj3 = obj1 {o} obj2"
63
+ else:
64
+ txt = f"obj3 = (obj1 {o} obj2) × {a}"
65
+ if b != 0.0 and not b_added:
66
+ txt += f" + {b}"
67
+ return txt
68
+
69
+ def update_operation(self, _item, _value): # pylint: disable=unused-argument
70
+ """Update the operation item"""
71
+ self.operation = self.get_operation()
72
+
73
+ operator = gds.ChoiceItem(
74
+ _("Operator"), MathOperator, default=MathOperator.ADD
75
+ ).set_prop("display", callback=update_operation)
76
+ factor = (
77
+ gds.FloatItem(_("Factor"), default=1.0)
78
+ .set_pos(col=1)
79
+ .set_prop("display", callback=update_operation)
80
+ )
81
+ constant = (
82
+ gds.FloatItem(_("Constant"), default=0.0)
83
+ .set_pos(col=1)
84
+ .set_prop("display", callback=update_operation)
85
+ )
86
+ operation = gds.StringItem(_("Operation"), default="").set_prop(
87
+ "display", active=False
88
+ )
89
+ restore_dtype = gds.BoolItem(
90
+ _("Convert to `obj1` data type"), label=_("Result"), default=True
91
+ )
92
+
93
+
94
+ class GaussianParam(gds.DataSet, title=_("Gaussian filter")):
95
+ """Gaussian filter parameters."""
96
+
97
+ sigma = gds.FloatItem(
98
+ "σ",
99
+ default=1.0,
100
+ min=0.0,
101
+ help=_("Standard deviation of the Gaussian filter"),
102
+ )
103
+
104
+
105
+ HELP_MODE = _("""Mode of the filter:
106
+ - 'reflect': Reflect the data at the boundary
107
+ - 'constant': Pad with a constant value
108
+ - 'nearest': Pad with the nearest value
109
+ - 'mirror': Reflect the data at the boundary with the data itself
110
+ - 'wrap': Circular boundary""")
111
+
112
+
113
+ class MovingAverageParam(gds.DataSet, title=_("Moving average")):
114
+ """Moving average parameters"""
115
+
116
+ n = gds.IntItem(_("Size of the moving window"), default=3, min=1)
117
+ mode = gds.ChoiceItem(
118
+ _("Mode"), FilterMode, default=FilterMode.REFLECT, help=HELP_MODE
119
+ )
120
+
121
+
122
+ class MovingMedianParam(gds.DataSet, title=_("Moving median")):
123
+ """Moving median parameters"""
124
+
125
+ n = gds.IntItem(_("Size of the moving window"), default=3, min=1, even=False)
126
+ mode = gds.ChoiceItem(
127
+ _("Mode"), FilterMode, default=FilterMode.NEAREST, help=HELP_MODE
128
+ )
129
+
130
+
131
+ class ClipParam(gds.DataSet, title=_("Clip")):
132
+ """Data clipping parameters"""
133
+
134
+ lower = gds.FloatItem(_("Lower clipping value"), check=False)
135
+ upper = gds.FloatItem(_("Upper clipping value"), check=False)
136
+
137
+
138
+ class NormalizeParam(gds.DataSet, title=_("Normalize")):
139
+ """Normalize parameters"""
140
+
141
+ method = gds.ChoiceItem(_("Normalize with respect to"), NormalizationMethod)
142
+
143
+
144
+ class HistogramParam(gds.DataSet, title=_("Histogram")):
145
+ """Histogram parameters"""
146
+
147
+ def get_suffix(self, data: np.ndarray) -> str:
148
+ """Return suffix for the histogram computation
149
+
150
+ Args:
151
+ data: data array
152
+ """
153
+ suffix = f"bins={self.bins:d}"
154
+ if self.lower is not None:
155
+ suffix += f", ymin={self.lower:.3f}"
156
+ else:
157
+ self.lower = np.min(data)
158
+ if self.upper is not None:
159
+ suffix += f", ymax={self.upper:.3f}"
160
+ else:
161
+ self.upper = np.max(data)
162
+ return suffix
163
+
164
+ bins = gds.IntItem(_("Number of bins"), default=256, min=1)
165
+ lower = gds.FloatItem(_("Lower limit"), default=None, check=False)
166
+ upper = gds.FloatItem(_("Upper limit"), default=None, check=False)
167
+
168
+
169
+ class FFTParam(gds.DataSet, title=_("FFT")):
170
+ """FFT parameters"""
171
+
172
+ shift = gds.BoolItem(_("Shift"), help=_("Shift zero frequency to center"))
173
+
174
+ def __init__(self, *args, **kwargs):
175
+ super().__init__(*args, **kwargs)
176
+ self.shift = options.fft_shift_enabled.get()
177
+
178
+
179
+ class SpectrumParam(gds.DataSet, title=_("Spectrum")):
180
+ """Spectrum parameters."""
181
+
182
+ decibel = gds.BoolItem(_("Output in decibel (dB)"), default=False)
183
+
184
+
185
+ class ConstantParam(gds.DataSet, title=_("Constant")):
186
+ """Parameter used to set a constant value to used in operations"""
187
+
188
+ value = gds.FloatItem(_("Constant value"))
189
+
190
+
191
+ class AngleUnitParam(gds.DataSet, title=_("Angle unit")):
192
+ """Choice of angle unit."""
193
+
194
+ unit = gds.ChoiceItem(
195
+ _("Angle unit"),
196
+ AngleUnit,
197
+ default=AngleUnit.RADIAN,
198
+ help=_("Unit of angle measurement"),
199
+ )
200
+
201
+
202
+ class PhaseParam(gds.DataSet, title=_("Phase")):
203
+ """Parameters for phase computation."""
204
+
205
+ unwrap = gds.BoolItem(
206
+ "unwrap", default=True, help=_("Unwrapping removes discontinuities in phase")
207
+ )
208
+ unit = gds.ChoiceItem(
209
+ _("Unit"),
210
+ AngleUnit,
211
+ default=AngleUnit.DEGREE,
212
+ help=_("Unit of angle measurement"),
213
+ )
214
+
215
+
216
+ class SignalsToImageParam(gds.DataSet):
217
+ """Parameters for combining signals into an image."""
218
+
219
+ orientation = gds.ChoiceItem(
220
+ _("Orientation"),
221
+ SignalsToImageOrientation,
222
+ default=SignalsToImageOrientation.ROWS,
223
+ help=_("How to arrange signals: as rows or as columns"),
224
+ )
225
+ _prop = gds.GetAttrProp("normalize")
226
+ normalize = gds.BoolItem(
227
+ _("Normalize"),
228
+ default=False,
229
+ help=_("Normalize each signal before combining"),
230
+ )
231
+ normalize_method = gds.ChoiceItem(
232
+ _("Normalization method"),
233
+ NormalizationMethod,
234
+ default=NormalizationMethod.MAXIMUM,
235
+ help=_("Method used for normalization"),
236
+ ).set_prop("display", active=_prop)
237
+
238
+
239
+ # MARK: Helper functions for creating result objects -----------------------------------
240
+
241
+ Obj = TypeVar("Obj", bound="SignalObj | ImageObj")
242
+
243
+
244
+ def dst_1_to_1(src: Obj, name: str, suffix: str | None = None) -> Obj:
245
+ """Create a result object, for processing functions that take a single
246
+ signal or image object as input and return a single signal or image object (1-to-1).
247
+
248
+ .. note::
249
+
250
+ Data of the result object is copied from the source object (`src`).
251
+ This initial data is usually replaced by the processing function, but it may
252
+ also be used to initialize the result object as part of the processing function.
253
+
254
+ Args:
255
+ src: source signal or image object
256
+ name: name of the function. The title format depends on the configured
257
+ title formatter (SimpleTitleFormatter creates readable titles,
258
+ PlaceholderTitleFormatter creates DataLab-compatible placeholder titles).
259
+ suffix: suffix to add to the title. Optional.
260
+
261
+ Returns:
262
+ Result signal or image object
263
+ """
264
+ formatter = get_default_title_formatter()
265
+ title = formatter.format_1_to_1_title(name, suffix)
266
+ dst = src.copy(title=title)
267
+ return cast(Obj, dst)
268
+
269
+
270
+ def dst_n_to_1(src_list: list[Obj], name: str, suffix: str | None = None) -> Obj:
271
+ """Create a result object, for processing functions that take a list of signal or
272
+ image objects as input and return a single signal or image object (n-to-1).
273
+
274
+ .. note::
275
+
276
+ Data of the result object is copied from the first source object
277
+ (`src_list[0]`). This initial data is usually replaced by the processing
278
+ function, but it may also be used to initialize the result object as part
279
+ of the processing function.
280
+
281
+ Args:
282
+ src_list: list of input signal or image objects
283
+ name: name of the processing function. The title format depends on the
284
+ configured title formatter (SimpleTitleFormatter creates readable titles,
285
+ PlaceholderTitleFormatter creates DataLab-compatible placeholder titles).
286
+ suffix: suffix to add to the title
287
+
288
+ Returns:
289
+ Result signal or image object
290
+ """
291
+ if not isinstance(src_list, list) or len(src_list) <= 1:
292
+ raise ValueError("src_list must be a list of at least 2 objects")
293
+ all_sigs = all(isinstance(obj, SignalObj) for obj in src_list)
294
+ all_imgs = all(isinstance(obj, ImageObj) for obj in src_list)
295
+ if not (all_sigs or all_imgs):
296
+ raise ValueError("src_list must be a list of SignalObj or ImageObj objects")
297
+
298
+ formatter = get_default_title_formatter()
299
+ title = formatter.format_n_to_1_title(name, len(src_list), suffix)
300
+
301
+ if any(np.issubdtype(obj.data.dtype, complex) for obj in src_list):
302
+ dst_dtype = complex
303
+ else:
304
+ dst_dtype = float
305
+ dst = src_list[0].copy(title=title, dtype=dst_dtype)
306
+ dst.roi = None
307
+ for src_obj in src_list:
308
+ if src_obj.roi is not None:
309
+ if dst.roi is None:
310
+ dst.roi = src_obj.roi.copy()
311
+ else:
312
+ dst.roi.add_roi(src_obj.roi)
313
+ return dst
314
+
315
+
316
+ # Note about `src2` parameter:
317
+ # ----------------------------
318
+ # The `src2` parameter is currently not used in the function, but it is included
319
+ # to maintain a consistent interface with other similar functions (e.g., `dst_n_to_1`).
320
+ # This may be useful in the future if we want to extend the functionality.
321
+ #
322
+ # pylint: disable=unused-argument
323
+ def dst_2_to_1(src1: Obj, src2: Obj, name: str, suffix: str | None = None) -> Obj:
324
+ """Create a result object, for processing functions that take two signal or
325
+ image objects as input and return a single signal or image object (2-to-1).
326
+
327
+ .. note::
328
+
329
+ Data of the result object is copied from the first source object (`src1`).
330
+ This initial data is usually replaced by the processing function, but it may
331
+ also be used to initialize the result object as part of the processing function.
332
+
333
+ Args:
334
+ src1: input signal or image object
335
+ src2: input signal or image object
336
+ name: name of the processing function. The title format depends on the
337
+ configured title formatter (SimpleTitleFormatter creates readable titles,
338
+ PlaceholderTitleFormatter creates DataLab-compatible placeholder titles).
339
+ suffix: suffix to add to the title
340
+
341
+ Returns:
342
+ Output signal or image object
343
+ """
344
+ formatter = get_default_title_formatter()
345
+ title = formatter.format_2_to_1_title(name, suffix)
346
+ dst = src1.copy(title=title)
347
+ return dst
348
+
349
+
350
+ def new_signal_result(
351
+ src: SignalObj | ImageObj,
352
+ name: str,
353
+ suffix: str | None = None,
354
+ units: tuple[str, str] | None = None,
355
+ labels: tuple[str, str] | None = None,
356
+ ) -> SignalObj:
357
+ """Create new signal object as a result of a `compute_1_to_1` function
358
+
359
+ As opposed to the `dst_1_to_1` functions, this function creates a new signal object
360
+ without copying the original object metadata, except for the "source" entry.
361
+
362
+ Args:
363
+ src: input signal or image object
364
+ name: name of the processing function. The title format depends on the
365
+ configured title formatter (SimpleTitleFormatter creates readable titles,
366
+ PlaceholderTitleFormatter creates DataLab-compatible placeholder titles).
367
+ suffix: suffix to add to the title
368
+ units: units of the output signal
369
+ labels: labels of the output signal
370
+
371
+ Returns:
372
+ Output signal object
373
+ """
374
+ formatter = get_default_title_formatter()
375
+ title = formatter.format_1_to_1_title(name, suffix)
376
+ dst = create_signal(title=title, units=units, labels=labels)
377
+ if suffix is not None:
378
+ dst.title += "|" + suffix
379
+ if (source := src.metadata.get("source")) is not None:
380
+ dst.metadata["source"] = source
381
+ return dst