rapidtide 3.0.10__py3-none-any.whl → 3.1__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 (141) hide show
  1. rapidtide/Colortables.py +492 -27
  2. rapidtide/OrthoImageItem.py +1053 -47
  3. rapidtide/RapidtideDataset.py +1533 -86
  4. rapidtide/_version.py +3 -3
  5. rapidtide/calccoherence.py +196 -29
  6. rapidtide/calcnullsimfunc.py +191 -40
  7. rapidtide/calcsimfunc.py +245 -42
  8. rapidtide/correlate.py +1210 -393
  9. rapidtide/data/examples/src/testLD +56 -0
  10. rapidtide/data/examples/src/testalign +1 -1
  11. rapidtide/data/examples/src/testdelayvar +0 -1
  12. rapidtide/data/examples/src/testfmri +19 -1
  13. rapidtide/data/examples/src/testglmfilt +5 -5
  14. rapidtide/data/examples/src/testhappy +30 -1
  15. rapidtide/data/examples/src/testppgproc +17 -0
  16. rapidtide/data/examples/src/testrolloff +11 -0
  17. rapidtide/data/models/model_cnn_pytorch/best_model.pth +0 -0
  18. rapidtide/data/models/model_cnn_pytorch/loss.png +0 -0
  19. rapidtide/data/models/model_cnn_pytorch/loss.txt +1 -0
  20. rapidtide/data/models/model_cnn_pytorch/model.pth +0 -0
  21. rapidtide/data/models/model_cnn_pytorch/model_meta.json +68 -0
  22. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm.nii.gz +0 -0
  23. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm_mask.nii.gz +0 -0
  24. rapidtide/decorators.py +91 -0
  25. rapidtide/dlfilter.py +2225 -108
  26. rapidtide/dlfiltertorch.py +4843 -0
  27. rapidtide/externaltools.py +327 -12
  28. rapidtide/fMRIData_class.py +79 -40
  29. rapidtide/filter.py +1899 -810
  30. rapidtide/fit.py +2004 -574
  31. rapidtide/genericmultiproc.py +93 -18
  32. rapidtide/happy_supportfuncs.py +2044 -171
  33. rapidtide/helper_classes.py +584 -43
  34. rapidtide/io.py +2363 -370
  35. rapidtide/linfitfiltpass.py +341 -75
  36. rapidtide/makelaggedtcs.py +211 -20
  37. rapidtide/maskutil.py +423 -53
  38. rapidtide/miscmath.py +827 -121
  39. rapidtide/multiproc.py +210 -22
  40. rapidtide/patchmatch.py +234 -33
  41. rapidtide/peakeval.py +32 -30
  42. rapidtide/ppgproc.py +2203 -0
  43. rapidtide/qualitycheck.py +352 -39
  44. rapidtide/refinedelay.py +422 -57
  45. rapidtide/refineregressor.py +498 -184
  46. rapidtide/resample.py +671 -185
  47. rapidtide/scripts/applyppgproc.py +28 -0
  48. rapidtide/simFuncClasses.py +1052 -77
  49. rapidtide/simfuncfit.py +260 -46
  50. rapidtide/stats.py +540 -238
  51. rapidtide/tests/happycomp +9 -0
  52. rapidtide/tests/test_dlfiltertorch.py +627 -0
  53. rapidtide/tests/test_findmaxlag.py +24 -8
  54. rapidtide/tests/test_fullrunhappy_v1.py +0 -2
  55. rapidtide/tests/test_fullrunhappy_v2.py +0 -2
  56. rapidtide/tests/test_fullrunhappy_v3.py +1 -0
  57. rapidtide/tests/test_fullrunhappy_v4.py +2 -2
  58. rapidtide/tests/test_fullrunrapidtide_v7.py +1 -1
  59. rapidtide/tests/test_simroundtrip.py +8 -8
  60. rapidtide/tests/utils.py +9 -8
  61. rapidtide/tidepoolTemplate.py +142 -38
  62. rapidtide/tidepoolTemplate_alt.py +165 -44
  63. rapidtide/tidepoolTemplate_big.py +189 -52
  64. rapidtide/util.py +1217 -118
  65. rapidtide/voxelData.py +684 -37
  66. rapidtide/wiener.py +19 -12
  67. rapidtide/wiener2.py +113 -7
  68. rapidtide/wiener_doc.py +255 -0
  69. rapidtide/workflows/adjustoffset.py +105 -3
  70. rapidtide/workflows/aligntcs.py +85 -2
  71. rapidtide/workflows/applydlfilter.py +87 -10
  72. rapidtide/workflows/applyppgproc.py +522 -0
  73. rapidtide/workflows/atlasaverage.py +210 -47
  74. rapidtide/workflows/atlastool.py +100 -3
  75. rapidtide/workflows/calcSimFuncMap.py +294 -64
  76. rapidtide/workflows/calctexticc.py +201 -9
  77. rapidtide/workflows/ccorrica.py +97 -4
  78. rapidtide/workflows/cleanregressor.py +168 -29
  79. rapidtide/workflows/delayvar.py +163 -10
  80. rapidtide/workflows/diffrois.py +81 -3
  81. rapidtide/workflows/endtidalproc.py +144 -4
  82. rapidtide/workflows/fdica.py +195 -15
  83. rapidtide/workflows/filtnifti.py +70 -3
  84. rapidtide/workflows/filttc.py +74 -3
  85. rapidtide/workflows/fitSimFuncMap.py +206 -48
  86. rapidtide/workflows/fixtr.py +73 -3
  87. rapidtide/workflows/gmscalc.py +113 -3
  88. rapidtide/workflows/happy.py +813 -201
  89. rapidtide/workflows/happy2std.py +144 -12
  90. rapidtide/workflows/happy_parser.py +149 -8
  91. rapidtide/workflows/histnifti.py +118 -2
  92. rapidtide/workflows/histtc.py +84 -3
  93. rapidtide/workflows/linfitfilt.py +117 -4
  94. rapidtide/workflows/localflow.py +328 -28
  95. rapidtide/workflows/mergequality.py +79 -3
  96. rapidtide/workflows/niftidecomp.py +322 -18
  97. rapidtide/workflows/niftistats.py +174 -4
  98. rapidtide/workflows/pairproc.py +88 -2
  99. rapidtide/workflows/pairwisemergenifti.py +85 -2
  100. rapidtide/workflows/parser_funcs.py +1421 -40
  101. rapidtide/workflows/physiofreq.py +137 -11
  102. rapidtide/workflows/pixelcomp.py +208 -5
  103. rapidtide/workflows/plethquality.py +103 -21
  104. rapidtide/workflows/polyfitim.py +151 -11
  105. rapidtide/workflows/proj2flow.py +75 -2
  106. rapidtide/workflows/rankimage.py +111 -4
  107. rapidtide/workflows/rapidtide.py +272 -15
  108. rapidtide/workflows/rapidtide2std.py +98 -2
  109. rapidtide/workflows/rapidtide_parser.py +109 -9
  110. rapidtide/workflows/refineDelayMap.py +143 -33
  111. rapidtide/workflows/refineRegressor.py +682 -93
  112. rapidtide/workflows/regressfrommaps.py +152 -31
  113. rapidtide/workflows/resamplenifti.py +85 -3
  114. rapidtide/workflows/resampletc.py +91 -3
  115. rapidtide/workflows/retrolagtcs.py +98 -6
  116. rapidtide/workflows/retroregress.py +165 -9
  117. rapidtide/workflows/roisummarize.py +173 -5
  118. rapidtide/workflows/runqualitycheck.py +71 -3
  119. rapidtide/workflows/showarbcorr.py +147 -4
  120. rapidtide/workflows/showhist.py +86 -2
  121. rapidtide/workflows/showstxcorr.py +160 -3
  122. rapidtide/workflows/showtc.py +159 -3
  123. rapidtide/workflows/showxcorrx.py +184 -4
  124. rapidtide/workflows/showxy.py +185 -15
  125. rapidtide/workflows/simdata.py +262 -36
  126. rapidtide/workflows/spatialfit.py +77 -2
  127. rapidtide/workflows/spatialmi.py +251 -27
  128. rapidtide/workflows/spectrogram.py +305 -32
  129. rapidtide/workflows/synthASL.py +154 -3
  130. rapidtide/workflows/tcfrom2col.py +76 -2
  131. rapidtide/workflows/tcfrom3col.py +74 -2
  132. rapidtide/workflows/tidepool.py +2972 -133
  133. rapidtide/workflows/utils.py +19 -14
  134. rapidtide/workflows/utils_doc.py +293 -0
  135. rapidtide/workflows/variabilityizer.py +116 -3
  136. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/METADATA +10 -9
  137. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/RECORD +141 -122
  138. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/entry_points.txt +1 -0
  139. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/WHEEL +0 -0
  140. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/licenses/LICENSE +0 -0
  141. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/top_level.txt +0 -0
rapidtide/voxelData.py CHANGED
@@ -17,8 +17,10 @@
17
17
  #
18
18
  #
19
19
  import copy
20
+ from typing import Any
20
21
 
21
22
  import numpy as np
23
+ from numpy.typing import NDArray
22
24
  from tqdm import tqdm
23
25
 
24
26
  import rapidtide.filter as tide_filt
@@ -40,11 +42,41 @@ class dataVolume:
40
42
 
41
43
  def __init__(
42
44
  self,
43
- shape,
44
- shared=False,
45
- dtype=np.float64,
46
- thepid=0,
47
- ):
45
+ shape: tuple,
46
+ shared: bool = False,
47
+ dtype: type = np.float64,
48
+ thepid: int = 0,
49
+ ) -> None:
50
+ """
51
+ Initialize a data container with specified shape and properties.
52
+
53
+ Parameters
54
+ ----------
55
+ shape : tuple
56
+ The shape of the data array. Must be either 3D (x, y, z) or 4D (x, y, z, t).
57
+ shared : bool, optional
58
+ Whether to create a shared memory array, by default False
59
+ dtype : type, optional
60
+ Data type of the array, by default np.float64
61
+ thepid : int, optional
62
+ Process ID for naming shared memory, by default 0
63
+
64
+ Returns
65
+ -------
66
+ None
67
+ This method initializes the object in-place and does not return a value.
68
+
69
+ Notes
70
+ -----
71
+ The function automatically determines the number of dimensions based on the shape tuple length.
72
+ For 3D shapes, timepoints is set to 1. For 4D shapes, timepoints is set to the fourth dimension.
73
+ Invalid shapes will trigger a print statement with the error message.
74
+
75
+ Examples
76
+ --------
77
+ >>> data_container = DataContainer((64, 64, 32))
78
+ >>> data_container = DataContainer((64, 64, 32, 10), shared=True, dtype=np.float32)
79
+ """
48
80
  if len(shape) == 3:
49
81
  self.xsize = int(shape[0])
50
82
  self.ysize = int(shape[1])
@@ -64,24 +96,131 @@ class dataVolume:
64
96
  self.data, self.data_shm = tide_util.allocarray(
65
97
  shape, self.dtype, shared=shared, name=f"filtereddata_{thepid}"
66
98
  )
67
- return self.data
68
99
 
69
- def byvol(self):
100
+ def byvol(self) -> NDArray:
101
+ """
102
+ Return the data array.
103
+
104
+ Returns
105
+ -------
106
+ NDArray
107
+ The underlying data array stored in the object.
108
+
109
+ Notes
110
+ -----
111
+ This method provides direct access to the internal data array.
112
+ The returned array is a view of the original data and modifications
113
+ to it will affect the original object.
114
+
115
+ Examples
116
+ --------
117
+ >>> obj = MyClass()
118
+ >>> data = obj.byvol()
119
+ >>> print(data.shape)
120
+ (100, 50)
121
+ """
70
122
  return self.data
71
123
 
72
- def byslice(self):
124
+ def byslice(self) -> NDArray:
125
+ """
126
+ Reshape data by slices for 2D processing.
127
+
128
+ Reshapes the internal data array to facilitate 2D processing operations
129
+ by combining the x and y dimensions while preserving slice information.
130
+
131
+ Parameters
132
+ ----------
133
+ self : object
134
+ The instance containing the data to be reshaped. Expected to have
135
+ attributes: dimensions (int), data (array-like), xsize (int),
136
+ ysize (int), and numslices (int).
137
+
138
+ Returns
139
+ -------
140
+ NDArray
141
+ Reshaped array with dimensions (xsize * ysize, -1). For 3D data,
142
+ the shape becomes (xsize * ysize, -1). For 4D data, the shape becomes
143
+ (xsize * ysize, numslices, -1).
144
+
145
+ Notes
146
+ -----
147
+ This function is useful for preparing data for 2D processing operations
148
+ where the spatial dimensions need to be flattened while maintaining
149
+ temporal or spectral slice information.
150
+
151
+ Examples
152
+ --------
153
+ >>> # For 3D data with shape (100, 100, 50)
154
+ >>> result = obj.byslice()
155
+ >>> # Result shape: (10000, 50)
156
+ >>>
157
+ >>> # For 4D data with shape (50, 50, 10, 20)
158
+ >>> result = obj.byslice()
159
+ >>> # Result shape: (2500, 10, 20)
160
+ """
73
161
  if self.dimensions == 3:
74
162
  return self.data.reshape(self.xsize * self.ysize, -1)
75
163
  else:
76
164
  return self.data.reshape(self.xsize * self.ysize, self.numslices, -1)
77
165
 
78
- def byvoxel(self):
166
+ def byvoxel(self) -> NDArray:
167
+ """
168
+ Reshape data to voxel format based on dimensions.
169
+
170
+ Returns
171
+ -------
172
+ NDArray
173
+ Reshaped array where each row represents a voxel. For 3D data, returns
174
+ a 1D array of shape (numspatiallocs,). For non-3D data, returns a 2D array
175
+ of shape (numspatiallocs, -1).
176
+
177
+ Notes
178
+ -----
179
+ This method reshapes the internal ``data`` attribute to a voxel-based
180
+ structure. The ``numspatiallocs`` attribute determines the first dimension
181
+ of the output array, while the second dimension is determined by the
182
+ remaining data dimensions.
183
+
184
+ Examples
185
+ --------
186
+ >>> # For 3D data
187
+ >>> result = obj.byvoxel()
188
+ >>> print(result.shape)
189
+ (1000,) # where 1000 = numspatiallocs
190
+
191
+ >>> # For 2D data
192
+ >>> result = obj.byvoxel()
193
+ >>> print(result.shape)
194
+ (1000, 5) # where 1000 = numspatiallocs, 5 = remaining dimensions
195
+ """
79
196
  if self.dimensions == 3:
80
197
  return self.data.reshape(self.numspatiallocs)
81
198
  else:
82
199
  return self.data.reshape(self.numspatiallocs, -1)
83
200
 
84
- def destroy(self):
201
+ def destroy(self) -> None:
202
+ """
203
+ Clean up and destroy the object's resources.
204
+
205
+ This method releases the internal data storage and performs cleanup of
206
+ shared memory resources if they exist.
207
+
208
+ Returns
209
+ -------
210
+ None
211
+ This method does not return any value.
212
+
213
+ Notes
214
+ -----
215
+ The method first deletes the internal `data` attribute, then checks if
216
+ `data_shm` (shared memory) exists and performs cleanup if it does.
217
+
218
+ Examples
219
+ --------
220
+ >>> obj = MyClass()
221
+ >>> obj.destroy()
222
+ >>> # Object resources have been cleaned up
223
+ """
85
224
  del self.data
86
225
  if self.data_shm is not None:
87
226
  tide_util.cleanup_shm(self.data_shm)
@@ -116,16 +255,90 @@ class VoxelData:
116
255
 
117
256
  def __init__(
118
257
  self,
119
- filename,
120
- timestep=0.0,
121
- validstart=None,
122
- validend=None,
123
- ):
258
+ filename: str,
259
+ timestep: float = 0.0,
260
+ validstart: int | None = None,
261
+ validend: int | None = None,
262
+ ) -> None:
263
+ """
264
+ Initialize the object with filename and optional data reading parameters.
265
+
266
+ Parameters
267
+ ----------
268
+ filename : str
269
+ Path to the data file to be read.
270
+ timestep : float, optional
271
+ Time step for data processing, default is 0.0.
272
+ validstart : int, optional
273
+ Starting index for valid data range, default is None (all data).
274
+ validend : int, optional
275
+ Ending index for valid data range, default is None (all data).
276
+
277
+ Returns
278
+ -------
279
+ None
280
+ This method initializes the object and reads data but does not return any value.
281
+
282
+ Notes
283
+ -----
284
+ This method calls `readdata()` internally with the provided parameters to load
285
+ and process the data from the specified file.
286
+
287
+ Examples
288
+ --------
289
+ >>> obj = MyClass("data.txt")
290
+ >>> obj = MyClass("data.txt", timestep=0.1, validstart=10, validend=100)
291
+ """
124
292
 
125
293
  self.filename = filename
126
294
  self.readdata(timestep, validstart, validend)
127
295
 
128
- def readdata(self, timestep, validstart, validend):
296
+ def readdata(self, timestep: float, validstart: int | None, validend: int | None) -> None:
297
+ """
298
+ Load and process data from a file based on its type (NIfTI, CIFTI, or text).
299
+
300
+ This function loads data using `self.load()` and determines the file type
301
+ (NIfTI, CIFTI, or text) to set appropriate attributes such as dimensions,
302
+ timepoints, and spatial locations. It also handles time-related parameters
303
+ like `timestep` and `toffset`, and sets valid time ranges.
304
+
305
+ Parameters
306
+ ----------
307
+ timestep : float
308
+ The time step size (in seconds) for the data. If <= 0.0, the function
309
+ will attempt to infer it from the file metadata (except for text files,
310
+ which require this to be explicitly set).
311
+ validstart : int, optional
312
+ The starting index of the valid time range. If None, defaults to the
313
+ beginning of the data.
314
+ validend : int, optional
315
+ The ending index of the valid time range. If None, defaults to the end
316
+ of the data.
317
+
318
+ Returns
319
+ -------
320
+ None
321
+ This function does not return a value but updates the instance attributes
322
+ of `self` based on the loaded data and parameters.
323
+
324
+ Notes
325
+ -----
326
+ - For text files, `timestep` must be provided explicitly; otherwise, a
327
+ `ValueError` is raised.
328
+ - For CIFTI files, the `timestep` is hardcoded to 0.72 seconds as a temporary
329
+ workaround until full XML parsing is implemented.
330
+ - The function sets various internal attributes such as `xsize`, `ysize`,
331
+ `numslices`, `timepoints`, `numspatiallocs`, and `nativespaceshape`
332
+ depending on the file type.
333
+
334
+ Examples
335
+ --------
336
+ >>> readdata(timestep=1.0, validstart=0, validend=100)
337
+ # Loads data with a 1-second timestep and valid time range from 0 to 100.
338
+
339
+ >>> readdata(timestep=0.0, validstart=None, validend=None)
340
+ # Loads data and infers timestep from file metadata (if not text).
341
+ """
129
342
  # load the data
130
343
  self.load()
131
344
 
@@ -193,7 +406,54 @@ class VoxelData:
193
406
  self.setvalidtimes(validstart, validend)
194
407
  self.resident = True
195
408
 
196
- def copyheader(self, numtimepoints=None, tr=None, toffset=None):
409
+ def copyheader(
410
+ self,
411
+ numtimepoints: int | None = None,
412
+ tr: float | None = None,
413
+ toffset: float | None = None,
414
+ ) -> Any | None:
415
+ """
416
+ Copy and modify header information for neuroimaging files.
417
+
418
+ This method creates a deep copy of the current header and modifies specific
419
+ dimensions and parameters based on the file type (CIFTI or other formats).
420
+ For text files, returns None immediately. For CIFTI files, modifies time and
421
+ space dimensions. For other file types, updates time dimensions and related
422
+ parameters.
423
+
424
+ Parameters
425
+ ----------
426
+ numtimepoints : int, optional
427
+ Number of time points to set in the header. If None, time dimension
428
+ remains unchanged for non-CIFTI files.
429
+ tr : float, optional
430
+ Repetition time (TR) to set in the header. If None, TR remains unchanged.
431
+ toffset : float, optional
432
+ Time offset to set in the header. If None, time offset remains unchanged.
433
+
434
+ Returns
435
+ -------
436
+ dict or None
437
+ Modified header dictionary for non-text files, or None for text files.
438
+ Returns None if the file type is "text".
439
+
440
+ Notes
441
+ -----
442
+ For CIFTI files:
443
+ - Time dimension is updated to numtimepoints
444
+ - Space dimension is set to self.numspatiallocs
445
+ For other file types:
446
+ - Time dimension is updated to numtimepoints (index 4)
447
+ - Dimension index 0 is updated based on numtimepoints (4 for >1, 3 for 1)
448
+ - TR is set in pixdim[4] if provided
449
+ - Time offset is set in toffset if provided
450
+
451
+ Examples
452
+ --------
453
+ >>> header = obj.copyheader(numtimepoints=100, tr=2.0)
454
+ >>> header = obj.copyheader(toffset=-5.0)
455
+ >>> header = obj.copyheader()
456
+ """
197
457
  if self.filetype == "text":
198
458
  return None
199
459
  else:
@@ -217,18 +477,127 @@ class VoxelData:
217
477
  thisheader["pixdim"][4] = tr
218
478
  return thisheader
219
479
 
220
- def getsizes(self):
480
+ def getsizes(self) -> tuple[float, float, float, float]:
481
+ """
482
+ Return the dimensions and spacing parameters of the data structure.
483
+
484
+ Returns
485
+ -------
486
+ tuple[float, float, float, float]
487
+ A tuple containing four float values in order:
488
+ - xdim: x-dimension size
489
+ - ydim: y-dimension size
490
+ - slicethickness: thickness of each slice
491
+ - timestep: time step between measurements
492
+
493
+ Notes
494
+ -----
495
+ This method provides access to the fundamental spatial and temporal
496
+ parameters of the data structure. The returned values represent the
497
+ physical dimensions and spacing characteristics that define the
498
+ coordinate system of the data.
499
+
500
+ Examples
501
+ --------
502
+ >>> sizes = obj.getsizes()
503
+ >>> print(sizes)
504
+ (100.0, 100.0, 1.0, 0.1)
505
+ >>> x_size, y_size, slice_thick, time_step = obj.getsizes()
506
+ """
221
507
  return self.xdim, self.ydim, self.slicethickness, self.timestep
222
508
 
223
- def getdims(self):
509
+ def getdims(self) -> tuple[int, int, int, int]:
510
+ """
511
+ Return the dimensions of the data structure.
512
+
513
+ Returns
514
+ -------
515
+ tuple[int, int, int, int]
516
+ A tuple containing four integers representing:
517
+ - xsize: width dimension
518
+ - ysize: height dimension
519
+ - numslices: number of slices
520
+ - timepoints: number of time points
521
+
522
+ Notes
523
+ -----
524
+ This method provides access to the fundamental spatial and temporal dimensions
525
+ of the data structure. The returned tuple follows the order (x, y, slices, time).
526
+
527
+ Examples
528
+ --------
529
+ >>> dims = obj.getdims()
530
+ >>> print(dims)
531
+ (640, 480, 32, 100)
532
+ >>> x, y, slices, time = obj.getdims()
533
+ >>> print(f"Data shape: {x} x {y} x {slices} x {time}")
534
+ Data shape: 640 x 480 x 32 x 100
535
+ """
224
536
  return self.xsize, self.ysize, self.numslices, self.timepoints
225
537
 
226
- def unload(self):
538
+ def unload(self) -> None:
539
+ """
540
+ Unload Nim data and clean up resources.
541
+
542
+ This method removes the Nim data and Nim object references from the instance
543
+ and marks the instance as not resident in memory.
544
+
545
+ Notes
546
+ -----
547
+ This method should be called to properly clean up resources when the Nim
548
+ data is no longer needed. The method deletes the internal references to
549
+ ``nim_data`` and ``nim`` objects and sets the ``resident`` flag to ``False``.
550
+
551
+ Examples
552
+ --------
553
+ >>> instance = MyClass()
554
+ >>> instance.load() # Load some data
555
+ >>> instance.unload() # Clean up resources
556
+ >>> instance.resident
557
+ False
558
+ """
227
559
  del self.nim_data
228
560
  del self.nim
229
561
  self.resident = False
230
562
 
231
- def load(self):
563
+ def load(self) -> None:
564
+ """
565
+ Load data from file based on file type detection.
566
+
567
+ This method loads data from the specified filename, automatically detecting
568
+ whether the file is text, CIFTI, or NIFTI format. The loaded data is stored
569
+ in instance variables for subsequent processing.
570
+
571
+ Parameters
572
+ ----------
573
+ self : object
574
+ The instance of the class containing this method. Expected to have
575
+ attributes: filename (str), filetype (str or None), and various data
576
+ storage attributes (nim_data, nim, cifti_hdr, nim_hdr, thedims, thesizes).
577
+
578
+ Returns
579
+ -------
580
+ None
581
+ This method does not return any value but updates instance attributes
582
+ with loaded data.
583
+
584
+ Notes
585
+ -----
586
+ - If filetype is not None, the method prints "reloading non-resident data"
587
+ - For text files, data is read using tide_io.readvecs()
588
+ - For CIFTI files, data is read using tide_io.readfromcifti() and stored
589
+ in multiple attributes including cifti_hdr and nim_hdr
590
+ - For NIFTI files, data is read using tide_io.readfromnifti() and stored
591
+ in nim, nim_data, nim_hdr, thedims, and thesizes attributes
592
+ - The method sets self.resident = True upon successful completion
593
+
594
+ Examples
595
+ --------
596
+ >>> loader = DataContainer()
597
+ >>> loader.filename = "data.nii.gz"
598
+ >>> loader.load()
599
+ loading data from data.nii.gz
600
+ """
232
601
  if self.filetype is not None:
233
602
  print("reloading non-resident data")
234
603
  else:
@@ -255,7 +624,41 @@ class VoxelData:
255
624
  )
256
625
  self.resident = True
257
626
 
258
- def setvalidtimes(self, validstart, validend):
627
+ def setvalidtimes(self, validstart: int | None, validend: int | None) -> None:
628
+ """
629
+ Set valid time points for the object based on start and end indices.
630
+
631
+ This method configures the valid time range for the object by setting
632
+ `validstart` and `validend` attributes. It also calculates the number of
633
+ real time points and updates the native fMRI shape based on the file type.
634
+
635
+ Parameters
636
+ ----------
637
+ validstart : int, optional
638
+ The starting index of valid time points. If None, defaults to 0.
639
+ validend : int, optional
640
+ The ending index of valid time points. If None, defaults to
641
+ `self.timepoints - 1`.
642
+
643
+ Returns
644
+ -------
645
+ None
646
+ This method modifies the object's attributes in-place and does not return anything.
647
+
648
+ Notes
649
+ -----
650
+ The method calculates `realtimepoints` as `validend - validstart + 1`.
651
+ The `nativefmrishape` is updated based on the `filetype` attribute:
652
+ - "nifti": (xsize, ysize, numslices, realtimepoints)
653
+ - "cifti": (1, 1, 1, realtimepoints, numspatiallocs)
654
+ - else: (xsize, realtimepoints)
655
+
656
+ Examples
657
+ --------
658
+ >>> obj.setvalidtimes(5, 15)
659
+ >>> obj.setvalidtimes(None, 10)
660
+ >>> obj.setvalidtimes(0, None)
661
+ """
259
662
  if validstart is None:
260
663
  self.validstart = 0
261
664
  else:
@@ -272,16 +675,96 @@ class VoxelData:
272
675
  else:
273
676
  self.nativefmrishape = (self.xsize, self.realtimepoints)
274
677
 
275
- def setvalidvoxels(self, validvoxels):
678
+ def setvalidvoxels(self, validvoxels: NDArray) -> None:
679
+ """
680
+ Set the valid voxels for the object.
681
+
682
+ Parameters
683
+ ----------
684
+ validvoxels : numpy.ndarray
685
+ Array containing the valid voxel coordinates. The first dimension
686
+ represents the number of valid spatial locations.
687
+
688
+ Returns
689
+ -------
690
+ None
691
+ This method does not return any value.
692
+
693
+ Notes
694
+ -----
695
+ This method updates two attributes:
696
+ - `self.validvoxels`: Stores the provided valid voxel array
697
+ - `self.numvalidspatiallocs`: Stores the number of valid spatial locations
698
+ (derived from the shape of the validvoxels array)
699
+
700
+ Examples
701
+ --------
702
+ >>> obj = MyClass()
703
+ >>> voxels = np.array([[0, 0, 0], [1, 1, 1], [2, 2, 2]])
704
+ >>> obj.setvalidvoxels(voxels)
705
+ >>> print(obj.numvalidspatiallocs)
706
+ 3
707
+ """
276
708
  self.validvoxels = validvoxels
277
709
  self.numvalidspatiallocs = np.shape(self.validvoxels)[0]
278
710
 
279
- def byvol(self):
711
+ def byvol(self) -> NDArray:
712
+ """
713
+ Return the nim_data array from the object.
714
+
715
+ If the object is not resident, it will be loaded first.
716
+
717
+ Returns
718
+ -------
719
+ NDArray
720
+ The nim_data array stored in the object.
721
+
722
+ Notes
723
+ -----
724
+ This method checks if the object is resident and loads it if necessary
725
+ before returning the nim_data array.
726
+
727
+ Examples
728
+ --------
729
+ >>> obj = MyClass()
730
+ >>> data = obj.byvol()
731
+ >>> print(data.shape)
732
+ (100, 100)
733
+ """
280
734
  if not self.resident:
281
735
  self.load()
282
736
  return self.nim_data
283
737
 
284
- def byvoltrimmed(self):
738
+ def byvoltrimmed(self) -> NDArray:
739
+ """
740
+ Return data with volume trimming applied based on valid time range.
741
+
742
+ This method returns the neuroimaging data with temporal dimensions trimmed
743
+ according to the valid start and end indices. The behavior varies depending
744
+ on the file type and dimensions of the data.
745
+
746
+ Returns
747
+ -------
748
+ NDArray
749
+ Trimmed neuroimaging data array. For NIfTI files with 4D data or
750
+ CIFTI/text files, returns data with shape (X, Y, Z, T) where T is
751
+ the trimmed temporal dimension. For other file types, returns data
752
+ with shape (X, Y, Z) or (X, T) depending on the data structure.
753
+
754
+ Notes
755
+ -----
756
+ - If the data is not resident in memory, it will be loaded automatically
757
+ - For NIfTI files with 4D data, CIFTI files, or text files, the temporal
758
+ dimension is trimmed using self.validstart and self.validend
759
+ - For other file types, only the temporal dimension is trimmed
760
+ - The validend index is inclusive in the returned data
761
+
762
+ Examples
763
+ --------
764
+ >>> data = obj.byvoltrimmed()
765
+ >>> print(data.shape)
766
+ (64, 64, 32, 100) # For 4D NIfTI data with 100 valid time points
767
+ """
285
768
  if not self.resident:
286
769
  self.load()
287
770
  if self.filetype == "nifti":
@@ -292,19 +775,106 @@ class VoxelData:
292
775
  else:
293
776
  return self.nim_data[:, self.validstart : self.validend + 1]
294
777
 
295
- def byvoxel(self):
778
+ def byvoxel(self) -> NDArray:
779
+ """
780
+ Reshape data by voxel across spatial locations.
781
+
782
+ This method reshapes the trimmed volume data to organize it by voxel
783
+ across all spatial locations. The output format depends on the
784
+ file type and dimensions of the data.
785
+
786
+ Returns
787
+ -------
788
+ NDArray
789
+ Reshaped array where each row represents a voxel and columns
790
+ represent time points or other dimensions. For 4D data or
791
+ CIFTI/text files, the shape is (numspatiallocs, -1), otherwise
792
+ (numspatiallocs,).
793
+
794
+ Notes
795
+ -----
796
+ - For 4D data, CIFTI files, or text files, the result is reshaped to
797
+ have an additional dimension for time points or other temporal
798
+ dimensions
799
+ - For other file types, the result is reshaped to a 2D array with
800
+ shape (numspatiallocs,)
801
+
802
+ Examples
803
+ --------
804
+ >>> data = MyDataClass()
805
+ >>> voxel_data = data.byvoxel()
806
+ >>> print(voxel_data.shape)
807
+ (numspatiallocs, num_timepoints)
808
+ """
296
809
  if self.dimensions == 4 or self.filetype == "cifti" or self.filetype == "text":
297
810
  return self.byvoltrimmed().reshape(self.numspatiallocs, -1)
298
811
  else:
299
812
  return self.byvoltrimmed().reshape(self.numspatiallocs)
300
813
 
301
- def byslice(self):
814
+ def byslice(self) -> NDArray:
815
+ """
816
+ Reshape data by slice dimensions.
817
+
818
+ Reshapes the data returned by `byvoltrimmed()` to organize data by slice
819
+ locations and slices. The output format depends on the file type and
820
+ dimensions of the data.
821
+
822
+ Returns
823
+ -------
824
+ NDArray
825
+ Reshaped array with dimensions (numslicelocs, numslices, -1) for
826
+ CIFTI or text files, or (numslicelocs, numslices) for other file types.
827
+
828
+ Notes
829
+ -----
830
+ This method is particularly useful for organizing volumetric data by
831
+ slice locations and slices. For CIFTI and text file types, the last
832
+ dimension is automatically expanded to accommodate additional data
833
+ dimensions.
834
+
835
+ Examples
836
+ --------
837
+ >>> data = MyClass()
838
+ >>> result = data.byslice()
839
+ >>> print(result.shape)
840
+ (10, 20, 100) # for CIFTI/text files
841
+ >>> print(result.shape)
842
+ (10, 20) # for other file types
843
+ """
302
844
  if self.dimensions == 4 or self.filetype == "cifti" or self.filetype == "text":
303
845
  return self.byvoltrimmed().reshape(self.numslicelocs, self.numslices, -1)
304
846
  else:
305
847
  return self.byvoltrimmed().reshape(self.numslicelocs, self.numslices)
306
848
 
307
- def validdata(self):
849
+ def validdata(self) -> NDArray:
850
+ """
851
+ Return valid voxel data based on validvoxels mask.
852
+
853
+ If validvoxels is None, returns all voxel data. Otherwise, returns
854
+ only the subset of voxel data indicated by the validvoxels mask.
855
+
856
+ Returns
857
+ -------
858
+ NDArray
859
+ Array containing voxel data. If validvoxels is None, returns
860
+ all voxel data from byvoxel() method. If validvoxels is not None,
861
+ returns subset of voxel data filtered by validvoxels mask.
862
+
863
+ Notes
864
+ -----
865
+ This method relies on the byvoxel() method to generate the base
866
+ voxel data array and applies filtering based on the validvoxels
867
+ attribute if it exists.
868
+
869
+ Examples
870
+ --------
871
+ >>> # Get all voxel data
872
+ >>> data = obj.validdata()
873
+ >>>
874
+ >>> # Get filtered voxel data
875
+ >>> obj.validvoxels = [0, 1, 2, 5, 10]
876
+ >>> data = obj.validdata()
877
+ """
308
878
  if self.validvoxels is None:
309
879
  return self.byvoxel()
310
880
  else:
@@ -318,14 +888,67 @@ class VoxelData:
318
888
 
319
889
  def smooth(
320
890
  self,
321
- gausssigma,
322
- brainmask=None,
323
- graymask=None,
324
- whitemask=None,
325
- premask=False,
326
- premasktissueonly=False,
327
- showprogressbar=False,
328
- ):
891
+ gausssigma: float,
892
+ brainmask: NDArray | None = None,
893
+ graymask: NDArray | None = None,
894
+ whitemask: NDArray | None = None,
895
+ premask: bool = False,
896
+ premasktissueonly: bool = False,
897
+ showprogressbar: bool = False,
898
+ ) -> float:
899
+ """
900
+ Apply Gaussian spatial smoothing to the data.
901
+
902
+ This function applies a Gaussian spatial filter to the data, with optional
903
+ pre-masking of brain or tissue regions. For CIFTI and text file types, the
904
+ smoothing is skipped by setting `gausssigma` to 0.0. If `gausssigma` is less
905
+ than 0.0, it is automatically set to the mean of the image dimensions divided
906
+ by 2.0.
907
+
908
+ Parameters
909
+ ----------
910
+ gausssigma : float
911
+ Standard deviation for the Gaussian kernel. If less than 0.0, it is
912
+ automatically calculated as the mean of image dimensions divided by 2.0.
913
+ brainmask : NDArray | None, optional
914
+ Binary mask for the brain region. Required if `premask` is True and
915
+ `premasktissueonly` is False.
916
+ graymask : NDArray | None, optional
917
+ Binary mask for gray matter. Required if `premask` is True and
918
+ `premasktissueonly` is True.
919
+ whitemask : NDArray | None, optional
920
+ Binary mask for white matter. Required if `premask` is True and
921
+ `premasktissueonly` is True.
922
+ premask : bool, optional
923
+ If True, applies the mask before smoothing. Default is False.
924
+ premasktissueonly : bool, optional
925
+ If True, applies the mask only to gray and white matter. Requires
926
+ `graymask` and `whitemask` to be provided. Default is False.
927
+ showprogressbar : bool, optional
928
+ If True, displays a progress bar during processing. Default is False.
929
+
930
+ Returns
931
+ -------
932
+ float
933
+ The actual `gausssigma` value used for smoothing.
934
+
935
+ Notes
936
+ -----
937
+ - For CIFTI and text file types, smoothing is skipped.
938
+ - The function modifies `self.nim_data` in-place.
939
+ - If `premask` is True, the mask is applied to the timepoints specified by
940
+ `self.validstart` to `self.validend`.
941
+
942
+ Examples
943
+ --------
944
+ >>> # Apply smoothing with automatic sigma
945
+ >>> smooth(-1.0)
946
+ 1.5
947
+
948
+ >>> # Apply smoothing with a custom sigma and pre-mask
949
+ >>> smooth(2.0, brainmask=mask, premask=True)
950
+ 2.0
951
+ """
329
952
  # do spatial filtering if requested
330
953
  if self.filetype == "cifti" or self.filetype == "text":
331
954
  gausssigma = 0.0
@@ -379,7 +1002,31 @@ class VoxelData:
379
1002
  )
380
1003
  return gausssigma
381
1004
 
382
- def summarize(self):
1005
+ def summarize(self) -> None:
1006
+ """
1007
+ Print a comprehensive summary of voxel data properties.
1008
+
1009
+ This method outputs detailed information about the voxel data structure,
1010
+ including image dimensions, spatial properties, temporal characteristics,
1011
+ and file metadata. The summary includes both geometric and temporal
1012
+ parameters that define the voxel space and data organization.
1013
+
1014
+ Notes
1015
+ -----
1016
+ The method prints to standard output and does not return any value.
1017
+ All attributes are accessed from the instance and displayed in a
1018
+ formatted manner for easy inspection of the data structure.
1019
+
1020
+ Examples
1021
+ --------
1022
+ >>> obj.summarize()
1023
+ Voxel data summary:
1024
+ self.nim=...
1025
+ self.nim_data.shape=...
1026
+ self.nim_hdr=...
1027
+ self.nim_affine=...
1028
+ ...
1029
+ """
383
1030
  print("Voxel data summary:")
384
1031
  print(f"\t{self.nim=}")
385
1032
  print(f"\t{self.nim_data.shape=}")