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,171 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """Test ROI geometry transformations"""
4
+
5
+ import numpy as np
6
+
7
+ from sigima.objects.image import ImageObj, ImageROI, RectangularROI
8
+ from sigima.proc.image import fliph, flipv, rotate90, rotate270, transpose
9
+ from sigima.tests.env import execenv
10
+
11
+
12
+ def test_roi_rotate90() -> None:
13
+ """Test ROI transformation with 90° rotation."""
14
+ # Create test image
15
+ data = np.random.rand(100, 80) # Height=100, Width=80
16
+ img = ImageObj(title="Test Image")
17
+ img.data = data
18
+
19
+ # Create rectangular ROI
20
+ roi_obj = ImageROI()
21
+ single_roi = RectangularROI([10, 20, 20, 20], indices=False) # x0, y0, dx, dy
22
+ roi_obj.add_roi(single_roi)
23
+ img.roi = roi_obj
24
+
25
+ # Apply rotation
26
+ img_rotated = rotate90(img)
27
+ roi_rotated = img_rotated.roi.single_rois[0]
28
+
29
+ # Verify ROI is properly transformed and dimensions change
30
+ assert img_rotated.roi is not None, "90° rotation should preserve ROI object"
31
+ assert len(img_rotated.roi.single_rois) == 1, (
32
+ "90° rotation should preserve ROI count"
33
+ )
34
+
35
+ # The exact coordinates depend on the transformation, but the ROI should be valid
36
+ coords_rotated = roi_rotated.get_physical_coords(img_rotated)
37
+ assert len(coords_rotated) == 4, "Rectangular ROI should have 4 coordinates"
38
+
39
+
40
+ def test_roi_rotate270() -> None:
41
+ """Test ROI transformation with 270° rotation."""
42
+ # Create test image
43
+ data = np.random.rand(100, 80)
44
+ img = ImageObj(title="Test Image")
45
+ img.data = data
46
+
47
+ # Create rectangular ROI
48
+ roi_obj = ImageROI()
49
+ single_roi = RectangularROI([10, 20, 20, 20], indices=False)
50
+ roi_obj.add_roi(single_roi)
51
+ img.roi = roi_obj
52
+
53
+ # Apply rotation
54
+ img_rotated = rotate270(img)
55
+
56
+ # Verify ROI is properly transformed
57
+ assert img_rotated.roi is not None, "270° rotation should preserve ROI object"
58
+ assert len(img_rotated.roi.single_rois) == 1, (
59
+ "270° rotation should preserve ROI count"
60
+ )
61
+
62
+
63
+ def test_roi_fliph() -> None:
64
+ """Test ROI transformation with horizontal flip."""
65
+ # Create test image
66
+ data = np.random.rand(100, 80)
67
+ img = ImageObj(title="Test Image")
68
+ img.data = data
69
+
70
+ # Create rectangular ROI
71
+ roi_obj = ImageROI()
72
+ single_roi = RectangularROI([10, 20, 20, 20], indices=False)
73
+ roi_obj.add_roi(single_roi)
74
+ img.roi = roi_obj
75
+
76
+ # Apply flip
77
+ img_flipped = fliph(img)
78
+
79
+ # Verify ROI is properly transformed
80
+ assert img_flipped.roi is not None, "Horizontal flip should preserve ROI object"
81
+ assert len(img_flipped.roi.single_rois) == 1, (
82
+ "Horizontal flip should preserve ROI count"
83
+ )
84
+
85
+
86
+ def test_roi_flipv() -> None:
87
+ """Test ROI transformation with vertical flip."""
88
+ # Create test image
89
+ data = np.random.rand(100, 80)
90
+ img = ImageObj(title="Test Image")
91
+ img.data = data
92
+
93
+ # Create rectangular ROI
94
+ roi_obj = ImageROI()
95
+ single_roi = RectangularROI([10, 20, 20, 20], indices=False)
96
+ roi_obj.add_roi(single_roi)
97
+ img.roi = roi_obj
98
+
99
+ # Apply flip
100
+ img_flipped = flipv(img)
101
+
102
+ # Verify ROI is properly transformed
103
+ assert img_flipped.roi is not None, "Vertical flip should preserve ROI object"
104
+ assert len(img_flipped.roi.single_rois) == 1, (
105
+ "Vertical flip should preserve ROI count"
106
+ )
107
+
108
+
109
+ def test_roi_transpose() -> None:
110
+ """Test ROI transformation with transpose."""
111
+ # Create test image
112
+ data = np.random.rand(100, 80)
113
+ img = ImageObj(title="Test Image")
114
+ img.data = data
115
+
116
+ # Create rectangular ROI
117
+ roi_obj = ImageROI()
118
+ single_roi = RectangularROI([10, 20, 20, 20], indices=False)
119
+ roi_obj.add_roi(single_roi)
120
+ img.roi = roi_obj
121
+
122
+ # Apply transpose
123
+ img_transposed = transpose(img)
124
+
125
+ # Verify ROI is properly transformed
126
+ assert img_transposed.roi is not None, "Transpose should preserve ROI object"
127
+ assert len(img_transposed.roi.single_rois) == 1, (
128
+ "Transpose should preserve ROI count"
129
+ )
130
+
131
+
132
+ def test_roi_comprehensive() -> None:
133
+ """Comprehensive test for all ROI transformations."""
134
+ execenv.print("Testing ROI geometry transformations:")
135
+
136
+ # Create test image
137
+ data = np.random.rand(100, 80) # Height=100, Width=80
138
+ img = ImageObj(title="Test Image")
139
+ img.data = data
140
+
141
+ # Create rectangular ROI
142
+ roi_obj = ImageROI()
143
+ single_roi = RectangularROI([10, 20, 20, 20], indices=False)
144
+ roi_obj.add_roi(single_roi)
145
+ img.roi = roi_obj
146
+
147
+ coords_original = single_roi.get_physical_coords(img)
148
+ execenv.print(f" Original ROI: {coords_original}")
149
+
150
+ # Test all transformations
151
+ transformations = [
152
+ (rotate90, "rotate90"),
153
+ (rotate270, "rotate270"),
154
+ (fliph, "fliph"),
155
+ (flipv, "flipv"),
156
+ (transpose, "transpose"),
157
+ ]
158
+
159
+ for transform_func, name in transformations:
160
+ img_transformed = transform_func(img)
161
+ roi_transformed = img_transformed.roi.single_rois[0]
162
+ coords_transformed = roi_transformed.get_physical_coords(img_transformed)
163
+ execenv.print(f" {name}: {coords_transformed}")
164
+
165
+ # Verify ROI is properly transformed
166
+ assert img_transformed.roi is not None, f"{name} should preserve ROI object"
167
+ assert len(img_transformed.roi.single_rois) == 1, (
168
+ f"{name} should preserve ROI count"
169
+ )
170
+
171
+ execenv.print(" ✅ All ROI transformations working correctly")
@@ -0,0 +1,142 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Unit tests for TableResultBuilder (sigima.objects.scalar).
5
+ """
6
+
7
+ from numpy import ma
8
+
9
+ from sigima.objects.scalar import TableResultBuilder
10
+ from sigima.objects.signal import SignalObj
11
+ from sigima.tests.data import create_paracetamol_signal, create_test_signal_rois
12
+
13
+
14
+ def create_dummy_signal() -> SignalObj:
15
+ """Create a simple SignalObj with a single ROI."""
16
+ sig = create_paracetamol_signal()
17
+ roi = list(create_test_signal_rois(sig))[0]
18
+ sig.roi = roi
19
+ return sig
20
+
21
+
22
+ class TestTableResultBuilder:
23
+ """Test class for TableResultBuilder basic functionality."""
24
+
25
+ def test_basic_functionality(self) -> None:
26
+ """Test basic TableResultBuilder API with a SignalObj."""
27
+ sig = create_dummy_signal()
28
+
29
+ builder = TableResultBuilder("Signal Stats")
30
+ builder.add(ma.min, "min")
31
+ builder.add(ma.max, "max")
32
+ builder.add(ma.mean, "mean")
33
+
34
+ table = builder.compute(sig)
35
+
36
+ assert table.title == "Signal Stats"
37
+ # [None, ROI_0] x 3 stats
38
+ assert len(table.data) == 2 and len(table.data[0]) == 3
39
+ assert list(table.headers) == ["min", "max", "mean"]
40
+ assert table.roi_indices[0] == -1 # NO_ROI
41
+ assert table.roi_indices[1] == 0
42
+
43
+ # Check actual values
44
+ row_none = table.data[0]
45
+ row_roi = table.data[1]
46
+ assert isinstance(row_none[0], float)
47
+ assert isinstance(row_roi[1], float)
48
+
49
+
50
+ class TestTableResultBuilderHideColumns:
51
+ """Test class for TableResultBuilder hide_columns functionality."""
52
+
53
+ def setup_method(self) -> None:
54
+ """Set up test data for each test method."""
55
+ # pylint: disable=attribute-defined-outside-init
56
+ self.sig = create_dummy_signal()
57
+
58
+ def _create_basic_builder(self) -> TableResultBuilder:
59
+ """Helper method to create a basic builder with standard columns."""
60
+ builder = TableResultBuilder("Signal Stats")
61
+ builder.add(ma.min, "min")
62
+ builder.add(ma.max, "max")
63
+ builder.add(ma.mean, "mean")
64
+ builder.add(ma.std, "std")
65
+ return builder
66
+
67
+ def _assert_display_preferences(
68
+ self, table, expected_prefs: dict[str, bool]
69
+ ) -> None:
70
+ """Helper method to check display preferences and visible headers."""
71
+ prefs = table.get_display_preferences()
72
+ assert prefs == expected_prefs
73
+
74
+ expected_visible = [name for name, visible in expected_prefs.items() if visible]
75
+ visible_headers = table.get_visible_headers()
76
+ assert set(visible_headers) == set(expected_visible)
77
+
78
+ def test_hide_some_columns(self) -> None:
79
+ """Test hiding some columns."""
80
+ builder = self._create_basic_builder()
81
+ builder.hide_columns(["max", "std"])
82
+
83
+ table = builder.compute(self.sig)
84
+
85
+ assert table.title == "Signal Stats"
86
+ # All headers still present
87
+ assert list(table.headers) == ["min", "max", "mean", "std"]
88
+
89
+ self._assert_display_preferences(
90
+ table, {"min": True, "max": False, "mean": True, "std": False}
91
+ )
92
+
93
+ def test_hide_nonexistent_columns(self) -> None:
94
+ """Test hiding non-existent columns."""
95
+ builder = TableResultBuilder("Signal Stats")
96
+ builder.add(ma.min, "min")
97
+ builder.add(ma.max, "max")
98
+
99
+ # Try to hide non-existent column - should not cause error
100
+ builder.hide_columns(["nonexistent", "min"])
101
+
102
+ table = builder.compute(self.sig)
103
+
104
+ self._assert_display_preferences(table, {"min": False, "max": True})
105
+
106
+ def test_hide_empty_list(self) -> None:
107
+ """Test hiding empty list of columns."""
108
+ builder = TableResultBuilder("Signal Stats")
109
+ builder.add(ma.min, "min")
110
+ builder.add(ma.max, "max")
111
+
112
+ builder.hide_columns([])
113
+
114
+ table = builder.compute(self.sig)
115
+
116
+ self._assert_display_preferences(table, {"min": True, "max": True})
117
+
118
+ def test_hide_multiple_calls(self) -> None:
119
+ """Test multiple hide_columns calls accumulate."""
120
+ builder = self._create_basic_builder()
121
+
122
+ # Hide columns in multiple calls
123
+ builder.hide_columns(["max"])
124
+ builder.hide_columns(["std"])
125
+
126
+ table = builder.compute(self.sig)
127
+
128
+ self._assert_display_preferences(
129
+ table, {"min": True, "max": False, "mean": True, "std": False}
130
+ )
131
+
132
+ def test_hide_all_columns(self) -> None:
133
+ """Test hiding all columns."""
134
+ builder = TableResultBuilder("Signal Stats")
135
+ builder.add(ma.min, "min")
136
+ builder.add(ma.max, "max")
137
+
138
+ builder.hide_columns(["min", "max"])
139
+
140
+ table = builder.compute(self.sig)
141
+
142
+ self._assert_display_preferences(table, {"min": False, "max": False})