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,290 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ I/O signal formats
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import numpy as np
10
+ import pandas as pd
11
+ import scipy.io as sio
12
+ from guidata.io import HDF5Reader, HDF5Writer
13
+
14
+ from sigima.config import _
15
+ from sigima.io import ftlab
16
+ from sigima.io.base import FormatInfo
17
+ from sigima.io.common.converters import convert_array_to_valid_dtype
18
+ from sigima.io.signal import funcs
19
+ from sigima.io.signal.base import SignalFormatBase
20
+ from sigima.objects.signal import SignalObj
21
+ from sigima.objects.signal.constants import (
22
+ DATETIME_X_FORMAT_KEY,
23
+ DEFAULT_DATETIME_FORMAT,
24
+ )
25
+ from sigima.worker import CallbackWorkerProtocol
26
+
27
+
28
+ class HDF5SignalFormat(SignalFormatBase):
29
+ """Object representing a HDF5 signal file type"""
30
+
31
+ FORMAT_INFO = FormatInfo(
32
+ name=_("HDF5 files"),
33
+ extensions="*.h5sig",
34
+ readable=True,
35
+ writeable=True,
36
+ )
37
+ GROUP_NAME = "signal"
38
+
39
+ def read(
40
+ self, filename: str, worker: CallbackWorkerProtocol | None = None
41
+ ) -> list[SignalObj]:
42
+ """Read list of signal objects from file
43
+
44
+ Args:
45
+ filename: File name
46
+ worker: Callback worker object
47
+
48
+ Returns:
49
+ List of signal objects
50
+ """
51
+ reader = HDF5Reader(filename)
52
+ try:
53
+ with reader.group(self.GROUP_NAME):
54
+ obj = SignalObj()
55
+ obj.deserialize(reader)
56
+ except ValueError as exc:
57
+ raise ValueError("No valid signal data found") from exc
58
+ except Exception as exc: # pylint: disable=broad-except
59
+ raise RuntimeError(
60
+ f"Unexpected error reading HDF5 signal from {filename}"
61
+ ) from exc
62
+ finally:
63
+ reader.close()
64
+ return [obj]
65
+
66
+ def write(self, filename: str, obj: SignalObj) -> None:
67
+ """Write data to file
68
+
69
+ Args:
70
+ filename: Name of file to write
71
+ obj: Signal object to read data from
72
+ """
73
+ assert isinstance(obj, SignalObj), "Object is not a signal"
74
+ writer = HDF5Writer(filename)
75
+ with writer.group(self.GROUP_NAME):
76
+ obj.serialize(writer)
77
+ writer.close()
78
+
79
+
80
+ class CSVSignalFormat(SignalFormatBase):
81
+ """Object representing a CSV signal file type"""
82
+
83
+ FORMAT_INFO = FormatInfo(
84
+ name=_("CSV files"),
85
+ extensions="*.csv *.txt",
86
+ readable=True,
87
+ writeable=True,
88
+ )
89
+
90
+ def read(
91
+ self, filename: str, worker: CallbackWorkerProtocol | None = None
92
+ ) -> list[SignalObj]:
93
+ """Read list of signal objects from file
94
+
95
+ Args:
96
+ filename: File name
97
+ worker: Callback worker object
98
+
99
+ Returns:
100
+ List of signal objects
101
+ """
102
+ csv_data = funcs.read_csv(filename, worker)
103
+
104
+ if csv_data.ylabels:
105
+ # If y labels are present, we are sure that the data contains at least
106
+ # two columns (x and y)
107
+ objs = []
108
+ for i, (ylabel, yunit) in enumerate(zip(csv_data.ylabels, csv_data.yunits)):
109
+ obj = self.create_object(
110
+ filename, i if len(csv_data.ylabels) > 1 else None
111
+ )
112
+ obj.set_xydata(csv_data.xydata[:, 0], csv_data.xydata[:, i + 1])
113
+ obj.xlabel = csv_data.xlabel or ""
114
+ # Set xunit, defaulting to 's' if datetime signal and no unit specified
115
+ if csv_data.datetime_metadata and not csv_data.xunit:
116
+ obj.xunit = "s" # Default unit for datetime signals
117
+ else:
118
+ obj.xunit = csv_data.xunit or ""
119
+ obj.ylabel = ylabel or ""
120
+ obj.yunit = yunit or ""
121
+ if csv_data.header:
122
+ obj.metadata[self.HEADER_KEY] = csv_data.header
123
+ # Add datetime metadata if detected
124
+ if csv_data.datetime_metadata:
125
+ obj.metadata.update(csv_data.datetime_metadata)
126
+ # Add column metadata (constant-value columns like serial numbers)
127
+ if csv_data.column_metadata:
128
+ obj.metadata.update(csv_data.column_metadata)
129
+ objs.append(obj)
130
+ return objs
131
+ return self.create_signals_from(csv_data.xydata, filename)
132
+
133
+ def write(self, filename: str, obj: SignalObj) -> None:
134
+ """Write data to file
135
+
136
+ Args:
137
+ filename: Name of file to write
138
+ obj: Signal object to read data from
139
+ """
140
+ # If X is datetime, convert back to datetime strings for CSV
141
+ if obj.is_x_datetime():
142
+ datetime_values = obj.get_x_as_datetime()
143
+ # Convert to strings with appropriate format
144
+ datetime_format = obj.metadata.get(
145
+ DATETIME_X_FORMAT_KEY, DEFAULT_DATETIME_FORMAT
146
+ )
147
+ x_data = pd.to_datetime(datetime_values).strftime(datetime_format).values
148
+ # Create modified xydata with datetime strings in X column
149
+ # We'll write manually with pandas to preserve datetime strings
150
+ data_dict = {obj.xlabel or "Time": x_data, obj.ylabel or "Y": obj.y}
151
+ df = pd.DataFrame(data_dict)
152
+ df.to_csv(filename, index=False)
153
+ else:
154
+ funcs.write_csv(
155
+ filename,
156
+ obj.xydata,
157
+ obj.xlabel,
158
+ obj.xunit,
159
+ [obj.ylabel],
160
+ [obj.yunit],
161
+ obj.metadata.get(self.HEADER_KEY, ""),
162
+ )
163
+
164
+
165
+ class NumPySignalFormat(SignalFormatBase):
166
+ """Object representing a NumPy signal file type"""
167
+
168
+ FORMAT_INFO = FormatInfo(
169
+ name=_("NumPy binary files"),
170
+ extensions="*.npy",
171
+ readable=True,
172
+ writeable=True,
173
+ ) # pylint: disable=duplicate-code
174
+
175
+ def read_xydata(self, filename: str) -> np.ndarray:
176
+ """Read data and metadata from file, write metadata to object, return xydata
177
+
178
+ Args:
179
+ filename: Name of file to read
180
+
181
+ Returns:
182
+ NumPy array xydata
183
+ """
184
+ return convert_array_to_valid_dtype(np.load(filename), SignalObj.VALID_DTYPES)
185
+
186
+ def write(self, filename: str, obj: SignalObj) -> None:
187
+ """Write data to file
188
+
189
+ Args:
190
+ filename: Name of file to write
191
+ obj: Signal object to read data from
192
+ """
193
+ np.save(filename, obj.xydata.T)
194
+
195
+
196
+ class MatSignalFormat(SignalFormatBase):
197
+ """Object representing a MAT-File .mat signal file type"""
198
+
199
+ FORMAT_INFO = FormatInfo(
200
+ name=_("MAT-Files"),
201
+ extensions="*.mat",
202
+ readable=True,
203
+ writeable=True,
204
+ ) # pylint: disable=duplicate-code
205
+
206
+ def read(
207
+ self, filename: str, worker: CallbackWorkerProtocol | None = None
208
+ ) -> list[SignalObj]:
209
+ """Read data and metadata from file, write metadata to object, return xydata
210
+
211
+ Args:
212
+ filename: Name of file to read
213
+
214
+ Returns:
215
+ NumPy array xydata
216
+ """
217
+ mat = sio.loadmat(filename)
218
+ allsig: list[SignalObj] = []
219
+ for dname, data in mat.items():
220
+ if dname.startswith("__") or not isinstance(data, np.ndarray):
221
+ continue
222
+ for sig in self.create_signals_from(data.squeeze(), filename):
223
+ if dname != "sig":
224
+ sig.title += f" ({dname})"
225
+ allsig.append(sig)
226
+ return allsig
227
+
228
+ def write(self, filename: str, obj: SignalObj) -> None:
229
+ """Write data to file
230
+
231
+ Args:
232
+ filename: Name of file to write
233
+ obj: Signal object to read data from
234
+ """
235
+ # metadata cannot be saved as such as their type will be lost and
236
+ # cause problems when reading the file back
237
+ sio.savemat(filename, {"sig": obj.xydata.T})
238
+
239
+
240
+ class FTLabSignalFormat(SignalFormatBase):
241
+ """FT-Lab signal file."""
242
+
243
+ FORMAT_INFO = FormatInfo(
244
+ name=_("FT-Lab"),
245
+ extensions="*.sig",
246
+ readable=True,
247
+ writeable=False,
248
+ )
249
+
250
+ def read_xydata(self, filename: str) -> np.ndarray:
251
+ """Read data and metadata from file, populate metadata, return xydata.
252
+
253
+ Args:
254
+ filename: Path to FT-Lab file.
255
+
256
+ Returns:
257
+ Signal data.
258
+ """
259
+ return ftlab.sigread_ftlabsig(filename)
260
+
261
+
262
+ class MCASignalFormat(SignalFormatBase):
263
+ """Object representing a MCA signal file type"""
264
+
265
+ FORMAT_INFO = FormatInfo(
266
+ name=_("MCA files"),
267
+ extensions="*.mca",
268
+ readable=True,
269
+ writeable=False,
270
+ )
271
+
272
+ def read(
273
+ self, filename: str, worker: CallbackWorkerProtocol | None = None
274
+ ) -> list[SignalObj]:
275
+ """Read list of signal objects from file
276
+
277
+ Args:
278
+ filename: File name
279
+ worker: Callback worker object
280
+
281
+ Returns:
282
+ List of signal objects
283
+ """
284
+ mca = funcs.MCAFile(filename)
285
+ mca.read()
286
+ obj = self.create_object(filename)
287
+ obj.set_xydata(mca.x, mca.y)
288
+ obj.xlabel = mca.xlabel or ""
289
+ obj.metadata = mca.metadata
290
+ return [obj]