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,57 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Scalar results subpackage
5
+ =========================
6
+
7
+ This subpackage provides classes and functions for handling scalar results in Sigima.
8
+
9
+ The subpackage is split into two main modules:
10
+
11
+ - :mod:`sigima.objects.scalar.table`: Table results and related utilities
12
+ - :mod:`sigima.objects.scalar.geometry`: Geometry results and related utilities
13
+
14
+ For backward compatibility, all public symbols are re-exported from this __init__.py
15
+ file, so existing imports like:
16
+
17
+ .. code-block:: python
18
+
19
+ from sigima.objects.scalar import TableResult, GeometryResult
20
+
21
+ continue to work as expected.
22
+ """
23
+
24
+ # Import all public symbols from both modules
25
+ from sigima.objects.scalar.geometry import (
26
+ GeometryResult,
27
+ KindShape,
28
+ concat_geometries,
29
+ filter_geometry_by_roi,
30
+ )
31
+ from sigima.objects.scalar.table import (
32
+ NO_ROI,
33
+ ResultHtmlGenerator,
34
+ TableKind,
35
+ TableResult,
36
+ TableResultBuilder,
37
+ calc_table_from_data,
38
+ concat_tables,
39
+ filter_table_by_roi,
40
+ )
41
+
42
+ # Define __all__ to specify what gets imported with
43
+ # "from sigima.objects.scalar import *"
44
+ __all__ = [
45
+ "NO_ROI",
46
+ "GeometryResult",
47
+ "KindShape",
48
+ "ResultHtmlGenerator",
49
+ "TableKind",
50
+ "TableResult",
51
+ "TableResultBuilder",
52
+ "calc_table_from_data",
53
+ "concat_geometries",
54
+ "concat_tables",
55
+ "filter_geometry_by_roi",
56
+ "filter_table_by_roi",
57
+ ]
@@ -0,0 +1,215 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Common utilities for scalar result objects
5
+ ==========================================
6
+
7
+ This module provides shared functionality for TableResult and GeometryResult classes
8
+ without using inheritance or mixins, maintaining their dataclass integrity.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from typing import TYPE_CHECKING
14
+
15
+ import pandas as pd
16
+
17
+ if TYPE_CHECKING:
18
+ from sigima.objects import GeometryResult, ImageObj, SignalObj, TableResult
19
+
20
+ # Sentinel value for "full signal/image / no ROI" rows in result tables
21
+ NO_ROI: int = -1
22
+
23
+
24
+ class DisplayPreferencesManager:
25
+ """Manages display preferences for result objects."""
26
+
27
+ @staticmethod
28
+ def get_display_preferences(
29
+ result: GeometryResult | TableResult,
30
+ headers: list[str],
31
+ attr_name: str = "hidden_headers",
32
+ ) -> dict[str, bool]:
33
+ """Get display preferences for headers.
34
+
35
+ Args:
36
+ result: The result object containing attrs
37
+ headers: List of header names
38
+ attr_name: Name of the attribute storing hidden headers
39
+
40
+ Returns:
41
+ Dictionary mapping header names to visibility (True=visible, False=hidden)
42
+ """
43
+ prefs = {}
44
+ hidden_headers = result.attrs.get(attr_name, set())
45
+ if isinstance(hidden_headers, (list, tuple)):
46
+ hidden_headers = set(hidden_headers)
47
+
48
+ for header in headers:
49
+ prefs[header] = header not in hidden_headers
50
+ return prefs
51
+
52
+ @staticmethod
53
+ def set_display_preferences(
54
+ result: GeometryResult | TableResult,
55
+ preferences: dict[str, bool],
56
+ headers: list[str],
57
+ attr_name: str = "hidden_headers",
58
+ ) -> None:
59
+ """Set display preferences for headers.
60
+
61
+ Args:
62
+ result: The result object to modify
63
+ preferences: Dictionary mapping header names to visibility
64
+ headers: List of valid header names
65
+ attr_name: Name of the attribute to store hidden headers
66
+ """
67
+ hidden_headers = {
68
+ header
69
+ for header, visible in preferences.items()
70
+ if not visible and header in headers
71
+ }
72
+ if hidden_headers:
73
+ result.attrs[attr_name] = list(hidden_headers)
74
+ elif attr_name in result.attrs:
75
+ del result.attrs[attr_name]
76
+
77
+ @staticmethod
78
+ def get_visible_headers(
79
+ result: GeometryResult | TableResult,
80
+ headers: list[str],
81
+ attr_name: str = "hidden_headers",
82
+ ) -> list[str]:
83
+ """Get list of currently visible headers.
84
+
85
+ Args:
86
+ result: The result object
87
+ headers: List of all header names
88
+ attr_name: Name of the attribute storing hidden headers
89
+
90
+ Returns:
91
+ List of header names that should be displayed
92
+ """
93
+ prefs = DisplayPreferencesManager.get_display_preferences(
94
+ result, headers, attr_name
95
+ )
96
+ return [header for header in headers if prefs.get(header, True)]
97
+
98
+
99
+ class DataFrameManager:
100
+ """Manages DataFrame operations for result objects."""
101
+
102
+ @staticmethod
103
+ def apply_visible_only_filter(
104
+ df: pd.DataFrame, visible_headers: list[str]
105
+ ) -> pd.DataFrame:
106
+ """Apply visible-only filter to a DataFrame.
107
+
108
+ Args:
109
+ df: DataFrame to filter
110
+ visible_headers: List of headers that should be visible
111
+
112
+ Returns:
113
+ Filtered DataFrame with only visible columns
114
+ """
115
+ # Keep roi_index column if present
116
+ if "roi_index" in df.columns:
117
+ visible_headers = ["roi_index"] + visible_headers
118
+
119
+ # Filter to only available visible columns
120
+ available_headers = [col for col in visible_headers if col in df.columns]
121
+ if available_headers:
122
+ return df[available_headers]
123
+ return df
124
+
125
+
126
+ class ResultHtmlGenerator:
127
+ """Utility class for generating HTML from result objects using composition."""
128
+
129
+ @staticmethod
130
+ def generate_html(
131
+ result: GeometryResult | TableResult,
132
+ obj: SignalObj | ImageObj,
133
+ visible_only: bool = True,
134
+ transpose_single_row: bool = True,
135
+ **kwargs,
136
+ ) -> str:
137
+ """Generate HTML from a result object.
138
+
139
+ Args:
140
+ result: The result object (TableResult or GeometryResult)
141
+ obj: SignalObj or ImageObj for ROI title extraction
142
+ visible_only: If True, include only visible headers based on display
143
+ preferences. Default is False.
144
+ transpose_single_row: If True, transpose the table when there's only one row
145
+ **kwargs: Additional arguments passed to DataFrame.to_html()
146
+
147
+ Returns:
148
+ HTML representation of the result
149
+ """
150
+ df = result.to_dataframe(visible_only=visible_only)
151
+
152
+ # Remove roi_index column for display
153
+ if "roi_index" in df.columns:
154
+ roi_indices = df["roi_index"].tolist()
155
+ df = df.drop(columns=["roi_index"])
156
+ else:
157
+ roi_indices = None
158
+
159
+ # Create row headers
160
+ row_headers = ResultHtmlGenerator._get_row_headers(result, roi_indices, obj)
161
+
162
+ # Transpose if single row and flag is set
163
+ if transpose_single_row and len(df) == 1:
164
+ # Transpose the dataframe
165
+ df_t = df.T
166
+ df_t.columns = [row_headers[0] if row_headers[0] else "Value"]
167
+ df_t.index.name = "Item"
168
+ # Get labels for the transposed view
169
+ display_labels = list(df.columns)
170
+ df_t.index = display_labels
171
+ text = f'<u><b style="color: blue">{result.title}</b></u>:'
172
+ html_kwargs = {"border": 0}
173
+ html_kwargs.update(kwargs)
174
+ # Format numeric columns only, avoiding float_format on mixed data types
175
+ for col in df_t.select_dtypes(include=["number"]).columns:
176
+ df_t[col] = df_t[col].map(lambda x: f"{x:.3g}" if pd.notna(x) else x)
177
+ text += df_t.to_html(**html_kwargs)
178
+ else:
179
+ # Standard horizontal layout
180
+ df.index = row_headers
181
+ text = f'<u><b style="color: blue">{result.title}</b></u>:'
182
+ html_kwargs = {"border": 0}
183
+ html_kwargs.update(kwargs)
184
+ # Format numeric columns only, avoiding float_format on mixed data types
185
+ for col in df.select_dtypes(include=["number"]).columns:
186
+ df[col] = df[col].map(lambda x: f"{x:.3g}" if pd.notna(x) else x)
187
+ text += df.to_html(**html_kwargs)
188
+
189
+ return text
190
+
191
+ @staticmethod
192
+ def _get_row_headers(
193
+ result: TableResult | "GeometryResult",
194
+ roi_indices: list[int] | None,
195
+ obj: SignalObj | ImageObj,
196
+ ) -> list[str]:
197
+ """Create row headers from ROI indices."""
198
+ row_headers = []
199
+ if roi_indices is not None:
200
+ for roi_idx in roi_indices:
201
+ if roi_idx == NO_ROI:
202
+ header = ""
203
+ else:
204
+ header = f"ROI {roi_idx}"
205
+ # Try to get ROI title from object if available
206
+ if obj.roi is not None:
207
+ header = obj.roi.get_single_roi_title(roi_idx)
208
+ row_headers.append(header)
209
+ else:
210
+ # Need to get DataFrame to know the number of rows
211
+ df = result.to_dataframe()
212
+ if "roi_index" in df.columns:
213
+ df = df.drop(columns=["roi_index"])
214
+ row_headers = [""] * len(df)
215
+ return row_headers