rapidtide 3.0.11__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 (139) hide show
  1. rapidtide/Colortables.py +492 -27
  2. rapidtide/OrthoImageItem.py +1049 -46
  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 +25 -3
  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/decorators.py +91 -0
  23. rapidtide/dlfilter.py +2225 -108
  24. rapidtide/dlfiltertorch.py +4843 -0
  25. rapidtide/externaltools.py +327 -12
  26. rapidtide/fMRIData_class.py +79 -40
  27. rapidtide/filter.py +1899 -810
  28. rapidtide/fit.py +2004 -574
  29. rapidtide/genericmultiproc.py +93 -18
  30. rapidtide/happy_supportfuncs.py +2044 -171
  31. rapidtide/helper_classes.py +584 -43
  32. rapidtide/io.py +2363 -370
  33. rapidtide/linfitfiltpass.py +341 -75
  34. rapidtide/makelaggedtcs.py +211 -20
  35. rapidtide/maskutil.py +423 -53
  36. rapidtide/miscmath.py +827 -121
  37. rapidtide/multiproc.py +210 -22
  38. rapidtide/patchmatch.py +234 -33
  39. rapidtide/peakeval.py +32 -30
  40. rapidtide/ppgproc.py +2203 -0
  41. rapidtide/qualitycheck.py +352 -39
  42. rapidtide/refinedelay.py +422 -57
  43. rapidtide/refineregressor.py +498 -184
  44. rapidtide/resample.py +671 -185
  45. rapidtide/scripts/applyppgproc.py +28 -0
  46. rapidtide/simFuncClasses.py +1052 -77
  47. rapidtide/simfuncfit.py +260 -46
  48. rapidtide/stats.py +540 -238
  49. rapidtide/tests/happycomp +9 -0
  50. rapidtide/tests/test_dlfiltertorch.py +627 -0
  51. rapidtide/tests/test_findmaxlag.py +24 -8
  52. rapidtide/tests/test_fullrunhappy_v1.py +0 -2
  53. rapidtide/tests/test_fullrunhappy_v2.py +0 -2
  54. rapidtide/tests/test_fullrunhappy_v3.py +1 -0
  55. rapidtide/tests/test_fullrunhappy_v4.py +2 -2
  56. rapidtide/tests/test_fullrunrapidtide_v7.py +1 -1
  57. rapidtide/tests/test_simroundtrip.py +8 -8
  58. rapidtide/tests/utils.py +9 -8
  59. rapidtide/tidepoolTemplate.py +142 -38
  60. rapidtide/tidepoolTemplate_alt.py +165 -44
  61. rapidtide/tidepoolTemplate_big.py +189 -52
  62. rapidtide/util.py +1217 -118
  63. rapidtide/voxelData.py +684 -37
  64. rapidtide/wiener.py +19 -12
  65. rapidtide/wiener2.py +113 -7
  66. rapidtide/wiener_doc.py +255 -0
  67. rapidtide/workflows/adjustoffset.py +105 -3
  68. rapidtide/workflows/aligntcs.py +85 -2
  69. rapidtide/workflows/applydlfilter.py +87 -10
  70. rapidtide/workflows/applyppgproc.py +522 -0
  71. rapidtide/workflows/atlasaverage.py +210 -47
  72. rapidtide/workflows/atlastool.py +100 -3
  73. rapidtide/workflows/calcSimFuncMap.py +294 -64
  74. rapidtide/workflows/calctexticc.py +201 -9
  75. rapidtide/workflows/ccorrica.py +97 -4
  76. rapidtide/workflows/cleanregressor.py +168 -29
  77. rapidtide/workflows/delayvar.py +163 -10
  78. rapidtide/workflows/diffrois.py +81 -3
  79. rapidtide/workflows/endtidalproc.py +144 -4
  80. rapidtide/workflows/fdica.py +195 -15
  81. rapidtide/workflows/filtnifti.py +70 -3
  82. rapidtide/workflows/filttc.py +74 -3
  83. rapidtide/workflows/fitSimFuncMap.py +206 -48
  84. rapidtide/workflows/fixtr.py +73 -3
  85. rapidtide/workflows/gmscalc.py +113 -3
  86. rapidtide/workflows/happy.py +801 -199
  87. rapidtide/workflows/happy2std.py +144 -12
  88. rapidtide/workflows/happy_parser.py +138 -9
  89. rapidtide/workflows/histnifti.py +118 -2
  90. rapidtide/workflows/histtc.py +84 -3
  91. rapidtide/workflows/linfitfilt.py +117 -4
  92. rapidtide/workflows/localflow.py +328 -28
  93. rapidtide/workflows/mergequality.py +79 -3
  94. rapidtide/workflows/niftidecomp.py +322 -18
  95. rapidtide/workflows/niftistats.py +174 -4
  96. rapidtide/workflows/pairproc.py +88 -2
  97. rapidtide/workflows/pairwisemergenifti.py +85 -2
  98. rapidtide/workflows/parser_funcs.py +1421 -40
  99. rapidtide/workflows/physiofreq.py +137 -11
  100. rapidtide/workflows/pixelcomp.py +208 -5
  101. rapidtide/workflows/plethquality.py +103 -21
  102. rapidtide/workflows/polyfitim.py +151 -11
  103. rapidtide/workflows/proj2flow.py +75 -2
  104. rapidtide/workflows/rankimage.py +111 -4
  105. rapidtide/workflows/rapidtide.py +272 -15
  106. rapidtide/workflows/rapidtide2std.py +98 -2
  107. rapidtide/workflows/rapidtide_parser.py +109 -9
  108. rapidtide/workflows/refineDelayMap.py +143 -33
  109. rapidtide/workflows/refineRegressor.py +682 -93
  110. rapidtide/workflows/regressfrommaps.py +152 -31
  111. rapidtide/workflows/resamplenifti.py +85 -3
  112. rapidtide/workflows/resampletc.py +91 -3
  113. rapidtide/workflows/retrolagtcs.py +98 -6
  114. rapidtide/workflows/retroregress.py +165 -9
  115. rapidtide/workflows/roisummarize.py +173 -5
  116. rapidtide/workflows/runqualitycheck.py +71 -3
  117. rapidtide/workflows/showarbcorr.py +147 -4
  118. rapidtide/workflows/showhist.py +86 -2
  119. rapidtide/workflows/showstxcorr.py +160 -3
  120. rapidtide/workflows/showtc.py +159 -3
  121. rapidtide/workflows/showxcorrx.py +184 -4
  122. rapidtide/workflows/showxy.py +185 -15
  123. rapidtide/workflows/simdata.py +262 -36
  124. rapidtide/workflows/spatialfit.py +77 -2
  125. rapidtide/workflows/spatialmi.py +251 -27
  126. rapidtide/workflows/spectrogram.py +305 -32
  127. rapidtide/workflows/synthASL.py +154 -3
  128. rapidtide/workflows/tcfrom2col.py +76 -2
  129. rapidtide/workflows/tcfrom3col.py +74 -2
  130. rapidtide/workflows/tidepool.py +2969 -130
  131. rapidtide/workflows/utils.py +19 -14
  132. rapidtide/workflows/utils_doc.py +293 -0
  133. rapidtide/workflows/variabilityizer.py +116 -3
  134. {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/METADATA +3 -2
  135. {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/RECORD +139 -122
  136. {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/entry_points.txt +1 -0
  137. {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/WHEEL +0 -0
  138. {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/licenses/LICENSE +0 -0
  139. {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/top_level.txt +0 -0
@@ -16,7 +16,10 @@
16
16
  # limitations under the License.
17
17
  #
18
18
  #
19
+ from typing import Any, Callable
20
+
19
21
  import numpy as np
22
+ from numpy.typing import NDArray
20
23
  from scipy.special import factorial
21
24
  from tqdm import tqdm
22
25
 
@@ -27,8 +30,63 @@ import rapidtide.multiproc as tide_multiproc
27
30
 
28
31
 
29
32
  def _procOneRegressionFitItem(
30
- vox, theevs, thedata, rt_floatset=np.float64, rt_floattype="float64"
31
- ):
33
+ vox: int,
34
+ theevs: NDArray,
35
+ thedata: NDArray,
36
+ rt_floatset: type = np.float64,
37
+ rt_floattype: str = "float64",
38
+ ) -> tuple[int, Any, Any, Any, Any, Any, NDArray, NDArray]:
39
+ """
40
+ Perform single regression fit on voxel data and return fit results.
41
+
42
+ This function fits a linear regression model to the provided evs and data,
43
+ handling both univariate and multivariate cases. It computes fit coefficients,
44
+ R-squared value, and residual data.
45
+
46
+ Parameters
47
+ ----------
48
+ vox : int
49
+ Voxel index.
50
+ theevs : numpy.ndarray
51
+ Experimental design matrix. If 2D, dimension 0 is number of points,
52
+ dimension 1 is number of evs.
53
+ thedata : numpy.ndarray
54
+ Dependent variable data corresponding to the evs.
55
+ rt_floatset : type, optional
56
+ Data type for floating-point results, default is ``np.float64``.
57
+ rt_floattype : str, optional
58
+ String representation of the floating-point type, default is ``"float64"``.
59
+
60
+ Returns
61
+ -------
62
+ tuple[int, Any, Any, Any, Any, Any, numpy.ndarray, numpy.ndarray]
63
+ A tuple containing:
64
+ - voxel index (`int`)
65
+ - intercept term (`Any`)
66
+ - signed square root of R-squared (`Any`)
67
+ - R-squared value (`Any`)
68
+ - fit coefficients (`Any` or `numpy.ndarray`)
69
+ - normalized fit coefficients (`Any`)
70
+ - data removed by fitting (`numpy.ndarray`)
71
+ - residuals (`numpy.ndarray`)
72
+
73
+ Notes
74
+ -----
75
+ For multivariate regressions (2D `theevs`), the function computes the fit
76
+ using `tide_fit.mlregress`. If the fit fails, a zero matrix is returned.
77
+ For univariate regressions (1D `theevs`), the function directly computes
78
+ the fit and handles edge cases such as zero coefficients.
79
+
80
+ Examples
81
+ --------
82
+ >>> import numpy as np
83
+ >>> from tide_fit import mlregress
84
+ >>> theevs = np.array([[1, 2], [3, 4], [5, 6]], dtype=np.float64)
85
+ >>> thedata = np.array([1, 2, 3], dtype=np.float64)
86
+ >>> result = _procOneRegressionFitItem(0, theevs, thedata)
87
+ >>> print(result[0]) # voxel index
88
+ 0
89
+ """
32
90
  # NOTE: if theevs is 2D, dimension 0 is number of points, dimension 1 is number of evs
33
91
  thefit, R2 = tide_fit.mlregress(theevs, thedata)
34
92
  if theevs.ndim > 1:
@@ -78,36 +136,132 @@ def _procOneRegressionFitItem(
78
136
 
79
137
 
80
138
  def linfitfiltpass(
81
- numprocitems,
82
- fmri_data,
83
- threshval,
84
- theevs,
85
- meanvalue,
86
- rvalue,
87
- r2value,
88
- fitcoeff,
89
- fitNorm,
90
- datatoremove,
91
- filtereddata,
92
- nprocs=1,
93
- alwaysmultiproc=False,
94
- voxelspecific=True,
95
- confoundregress=False,
96
- coefficientsonly=False,
97
- procbyvoxel=True,
98
- showprogressbar=True,
99
- chunksize=1000,
100
- rt_floatset=np.float64,
101
- rt_floattype="float64",
102
- verbose=True,
103
- debug=False,
104
- ):
139
+ numprocitems: int,
140
+ fmri_data: NDArray,
141
+ threshval: float | None,
142
+ theevs: NDArray,
143
+ meanvalue: NDArray | None,
144
+ rvalue: NDArray | None,
145
+ r2value: NDArray,
146
+ fitcoeff: NDArray | None,
147
+ fitNorm: NDArray | None,
148
+ datatoremove: NDArray | None,
149
+ filtereddata: NDArray,
150
+ nprocs: int = 1,
151
+ alwaysmultiproc: bool = False,
152
+ constantevs: bool = False,
153
+ confoundregress: bool = False,
154
+ coefficientsonly: bool = False,
155
+ procbyvoxel: bool = True,
156
+ showprogressbar: bool = True,
157
+ chunksize: int = 1000,
158
+ rt_floatset: type = np.float64,
159
+ rt_floattype: str = "float64",
160
+ verbose: bool = True,
161
+ debug: bool = False,
162
+ ) -> int:
163
+ """
164
+ Perform linear regression fitting and filtering on fMRI data.
165
+
166
+ This function fits a linear model to fMRI data using specified experimental variables
167
+ and applies filtering to remove noise. It supports both voxel-wise and timepoint-wise
168
+ processing, with optional multiprocessing for performance.
169
+
170
+ Parameters
171
+ ----------
172
+ numprocitems : int
173
+ Number of items to process (voxels or timepoints depending on ``procbyvoxel``).
174
+ fmri_data : ndarray
175
+ Input fMRI data array with shape ``(n_voxels, n_timepoints)`` or ``(n_timepoints, n_voxels)``.
176
+ threshval : float, optional
177
+ Threshold value for masking. If ``None``, no masking is applied.
178
+ theevs : ndarray
179
+ Experimental variables (design matrix) with shape ``(n_voxels, n_timepoints)`` or ``(n_timepoints, n_voxels)``.
180
+ meanvalue : ndarray, optional
181
+ Array to store mean values of the data. Shape depends on ``procbyvoxel``.
182
+ rvalue : ndarray, optional
183
+ Array to store correlation coefficients. Shape depends on ``procbyvoxel``.
184
+ r2value : ndarray
185
+ Array to store R-squared values. Shape depends on ``procbyvoxel``.
186
+ fitcoeff : ndarray, optional
187
+ Array to store fit coefficients. Shape depends on ``procbyvoxel`` and ``constantevs``.
188
+ fitNorm : ndarray, optional
189
+ Array to store normalized fit coefficients. Shape depends on ``procbyvoxel``.
190
+ datatoremove : ndarray, optional
191
+ Array to store data to be removed after fitting. Shape depends on ``procbyvoxel``.
192
+ filtereddata : ndarray
193
+ Array to store filtered data after regression. Shape depends on ``procbyvoxel``.
194
+ nprocs : int, default: 1
195
+ Number of processes to use for multiprocessing. If 1 and ``alwaysmultiproc`` is False, uses single-threaded processing.
196
+ alwaysmultiproc : bool, default: False
197
+ If True, always use multiprocessing even if ``nprocs`` is 1.
198
+ constantevs : bool, default: False
199
+ If True, treat experimental variables as constant across voxels/timepoints.
200
+ confoundregress : bool, default: False
201
+ If True, perform confound regression only (no output of coefficients or residuals).
202
+ coefficientsonly : bool, default: False
203
+ If True, store only regression coefficients and R-squared values.
204
+ procbyvoxel : bool, default: True
205
+ If True, process data voxel-wise; otherwise, process by timepoint.
206
+ showprogressbar : bool, default: True
207
+ If True, display a progress bar during processing.
208
+ chunksize : int, default: 1000
209
+ Size of chunks for multiprocessing.
210
+ rt_floatset : type, default: np.float64
211
+ Data type for internal floating-point calculations.
212
+ rt_floattype : str, default: "float64"
213
+ String representation of the floating-point data type.
214
+ verbose : bool, default: True
215
+ If True, print verbose output.
216
+ debug : bool, default: False
217
+ If True, enable debug printing.
218
+
219
+ Returns
220
+ -------
221
+ int
222
+ Total number of items processed.
223
+
224
+ Notes
225
+ -----
226
+ - The function modifies the output arrays in-place.
227
+ - For ``confoundregress=True``, only ``r2value`` and ``filtereddata`` are populated.
228
+ - When ``coefficientsonly=True``, only ``meanvalue``, ``rvalue``, ``r2value``, ``fitcoeff``, and ``fitNorm`` are populated.
229
+ - If ``threshval`` is provided, a mask is generated based on mean or standard deviation of the data.
230
+
231
+ Examples
232
+ --------
233
+ >>> import numpy as np
234
+ >>> from typing import NDArray
235
+ >>> fmri_data = np.random.rand(100, 200)
236
+ >>> theevs = np.random.rand(100, 200)
237
+ >>> r2value = np.zeros(100)
238
+ >>> filtereddata = np.zeros_like(fmri_data)
239
+ >>> numprocitems = 100
240
+ >>> items_processed = linfitfiltpass(
241
+ ... numprocitems=numprocitems,
242
+ ... fmri_data=fmri_data,
243
+ ... threshval=None,
244
+ ... theevs=theevs,
245
+ ... meanvalue=None,
246
+ ... rvalue=None,
247
+ ... r2value=r2value,
248
+ ... fitcoeff=None,
249
+ ... fitNorm=None,
250
+ ... datatoremove=None,
251
+ ... filtereddata=filtereddata,
252
+ ... nprocs=4,
253
+ ... procbyvoxel=True,
254
+ ... showprogressbar=True
255
+ ... )
256
+ >>> print(f"Processed {items_processed} items.")
257
+ """
105
258
  inputshape = np.shape(fmri_data)
106
259
  if debug:
107
260
  print(f"{numprocitems=}")
108
261
  print(f"{fmri_data.shape=}")
109
262
  print(f"{threshval=}")
110
- print(f"{theevs.shape=}")
263
+ print(f"{theevs.shape=}, {np.min(theevs)=}, {np.max(theevs)=}")
264
+ print(f"{theevs=}")
111
265
  if procbyvoxel:
112
266
  indexaxis = 0
113
267
  procunit = "voxels"
@@ -143,7 +297,7 @@ def linfitfiltpass(
143
297
 
144
298
  # process and send the data
145
299
  if procbyvoxel:
146
- if confoundregress or (not voxelspecific):
300
+ if confoundregress or constantevs:
147
301
  outQ.put(
148
302
  _procOneRegressionFitItem(
149
303
  val,
@@ -164,7 +318,7 @@ def linfitfiltpass(
164
318
  )
165
319
  )
166
320
  else:
167
- if confoundregress or (not voxelspecific):
321
+ if confoundregress or constantevs:
168
322
  outQ.put(
169
323
  _procOneRegressionFitItem(
170
324
  val,
@@ -214,7 +368,7 @@ def linfitfiltpass(
214
368
  meanvalue[voxel[0]] = voxel[1]
215
369
  rvalue[voxel[0]] = voxel[2]
216
370
  r2value[voxel[0]] = voxel[3]
217
- if theevs.ndim > 1:
371
+ if fitcoeff.ndim > 1:
218
372
  fitcoeff[voxel[0], :] = voxel[4]
219
373
  fitNorm[voxel[0], :] = voxel[5]
220
374
  else:
@@ -226,7 +380,7 @@ def linfitfiltpass(
226
380
  meanvalue[voxel[0]] = voxel[1]
227
381
  rvalue[voxel[0]] = voxel[2]
228
382
  r2value[voxel[0]] = voxel[3]
229
- if theevs.ndim > 1:
383
+ if fitcoeff.ndim > 1:
230
384
  fitcoeff[voxel[0], :] = voxel[4]
231
385
  fitNorm[voxel[0], :] = voxel[5]
232
386
  else:
@@ -246,7 +400,7 @@ def linfitfiltpass(
246
400
  meanvalue[timepoint[0]] = timepoint[1]
247
401
  rvalue[timepoint[0]] = timepoint[2]
248
402
  r2value[timepoint[0]] = timepoint[3]
249
- if theevs.ndim > 1:
403
+ if fitcoeff.ndim > 1:
250
404
  fitcoeff[:, timepoint[0]] = timepoint[4]
251
405
  fitNorm[:, timepoint[0]] = timepoint[5]
252
406
  else:
@@ -258,7 +412,7 @@ def linfitfiltpass(
258
412
  meanvalue[timepoint[0]] = timepoint[1]
259
413
  rvalue[timepoint[0]] = timepoint[2]
260
414
  r2value[timepoint[0]] = timepoint[3]
261
- if theevs.ndim > 1:
415
+ if fitcoeff.ndim > 1:
262
416
  fitcoeff[:, timepoint[0]] = timepoint[4]
263
417
  fitNorm[:, timepoint[0]] = timepoint[5]
264
418
  else:
@@ -270,6 +424,7 @@ def linfitfiltpass(
270
424
 
271
425
  del data_out
272
426
  else:
427
+ # this is the single proc path
273
428
  itemstotal = 0
274
429
  if procbyvoxel:
275
430
  for vox in tqdm(
@@ -298,7 +453,7 @@ def linfitfiltpass(
298
453
  rt_floattype=rt_floattype,
299
454
  )
300
455
  elif coefficientsonly:
301
- if voxelspecific:
456
+ if not constantevs:
302
457
  (
303
458
  dummy,
304
459
  meanvalue[vox],
@@ -377,22 +532,40 @@ def linfitfiltpass(
377
532
  rt_floattype=rt_floattype,
378
533
  )
379
534
  elif coefficientsonly:
380
- (
381
- dummy,
382
- meanvalue[timepoint],
383
- rvalue[timepoint],
384
- r2value[timepoint],
385
- fitcoeff[timepoint],
386
- fitNorm[timepoint],
387
- dummy,
388
- dummy,
389
- ) = _procOneRegressionFitItem(
390
- timepoint,
391
- theevs[:, timepoint],
392
- thedata,
393
- rt_floatset=rt_floatset,
394
- rt_floattype=rt_floattype,
395
- )
535
+ if not constantevs:
536
+ (
537
+ dummy,
538
+ meanvalue[timepoint],
539
+ rvalue[timepoint],
540
+ r2value[timepoint],
541
+ fitcoeff[timepoint],
542
+ fitNorm[timepoint],
543
+ dummy,
544
+ dummy,
545
+ ) = _procOneRegressionFitItem(
546
+ timepoint,
547
+ theevs[:, timepoint],
548
+ thedata,
549
+ rt_floatset=rt_floatset,
550
+ rt_floattype=rt_floattype,
551
+ )
552
+ else:
553
+ (
554
+ dummy,
555
+ meanvalue[timepoint],
556
+ rvalue[timepoint],
557
+ r2value[timepoint],
558
+ fitcoeff[timepoint],
559
+ fitNorm[timepoint],
560
+ dummy,
561
+ dummy,
562
+ ) = _procOneRegressionFitItem(
563
+ timepoint,
564
+ theevs,
565
+ thedata,
566
+ rt_floatset=rt_floatset,
567
+ rt_floattype=rt_floattype,
568
+ )
396
569
  else:
397
570
  (
398
571
  dummy,
@@ -410,30 +583,56 @@ def linfitfiltpass(
410
583
  rt_floatset=rt_floatset,
411
584
  rt_floattype=rt_floattype,
412
585
  )
586
+
413
587
  itemstotal += 1
414
588
  if showprogressbar:
415
589
  print()
416
590
  return itemstotal
417
591
 
418
592
 
419
- def makevoxelspecificderivs(theevs, nderivs=1, debug=False):
420
- r"""Perform multicomponent expansion on theevs (each ev replaced by itself,
421
- its square, its cube, etc.).
593
+ def makevoxelspecificderivs(theevs: NDArray, nderivs: int = 1, debug: bool = False) -> NDArray:
594
+ """
595
+ Perform multicomponent expansion on voxel-specific explanatory variables by computing
596
+ derivatives up to a specified order.
597
+
598
+ This function takes an array of voxel-specific timecourses and expands each one
599
+ into a set of components representing the original signal and its derivatives.
600
+ Each component corresponds to a higher-order derivative of the signal, scaled by
601
+ the inverse factorial of the derivative order (Taylor series coefficients).
422
602
 
423
603
  Parameters
424
604
  ----------
425
605
  theevs : 2D numpy array
426
- NxP array of voxel specific explanatory variables (one timecourse per voxel)
427
- :param theevs:
606
+ NxP array of voxel-specific explanatory variables, where N is the number of voxels
607
+ and P is the number of timepoints.
608
+ nderivs : int, optional
609
+ Number of derivative components to compute for each voxel. Default is 1.
610
+ If 0, the original `theevs` are returned without modification.
611
+ debug : bool, optional
612
+ If True, print debugging information including input and output shapes.
613
+ Default is False.
428
614
 
429
- nderivs : integer
430
- Number of components to use for each ev. Each successive component is a
431
- higher power of the initial ev (initial, square, cube, etc.)
432
- :param nderivs:
615
+ Returns
616
+ -------
617
+ 3D numpy array
618
+ Array of shape (N, P, nderivs + 1) containing the original signal and its
619
+ derivatives up to order `nderivs` for each voxel. The first component is the
620
+ original signal, followed by the first, second, ..., up to `nderivs`-th derivative.
433
621
 
434
- debug: bool
435
- Flag to toggle debugging output
436
- :param debug:
622
+ Notes
623
+ -----
624
+ - The function uses `numpy.gradient` to compute numerical derivatives.
625
+ - Each derivative component is scaled by the inverse factorial of the derivative order
626
+ to align with Taylor series expansion coefficients.
627
+ - If `nderivs=0`, the function returns a copy of the input `theevs`.
628
+
629
+ Examples
630
+ --------
631
+ >>> import numpy as np
632
+ >>> theevs = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
633
+ >>> result = makevoxelspecificderivs(theevs, nderivs=2)
634
+ >>> print(result.shape)
635
+ (2, 4, 3)
437
636
  """
438
637
  if debug:
439
638
  print(f"{theevs.shape=}")
@@ -459,19 +658,86 @@ def makevoxelspecificderivs(theevs, nderivs=1, debug=False):
459
658
 
460
659
 
461
660
  def confoundregress(
462
- theregressors,
463
- theregressorlabels,
464
- thedataarray,
465
- tr,
466
- nprocs=1,
467
- orthogonalize=True,
468
- tcstart=0,
469
- tcend=-1,
470
- tchp=None,
471
- tclp=None,
472
- showprogressbar=True,
473
- debug=False,
474
- ):
661
+ theregressors: NDArray,
662
+ theregressorlabels: list[str],
663
+ thedataarray: NDArray,
664
+ tr: float,
665
+ nprocs: int = 1,
666
+ orthogonalize: bool = True,
667
+ tcstart: int = 0,
668
+ tcend: int = -1,
669
+ tchp: float | None = None,
670
+ tclp: float | None = None,
671
+ showprogressbar: bool = True,
672
+ debug: bool = False,
673
+ ) -> tuple[NDArray, list[str], NDArray, NDArray]:
674
+ """
675
+ Perform confound regression on fMRI data using linear regression.
676
+
677
+ This function applies confound regression to remove noise from fMRI time series
678
+ by regressing out specified confounding variables (e.g., motion parameters,
679
+ physiological signals). It supports optional filtering, orthogonalization of
680
+ regressors, and parallel processing for performance.
681
+
682
+ Parameters
683
+ ----------
684
+ theregressors : ndarray
685
+ Array of confounding variables with shape (n_regressors, n_timepoints).
686
+ theregressorlabels : list of str
687
+ List of labels corresponding to each regressor.
688
+ thedataarray : ndarray
689
+ 3D or 4D array of fMRI data with shape (n_voxels, n_timepoints) or
690
+ (n_voxels, n_timepoints, n_volumes).
691
+ tr : float
692
+ Repetition time (TR) in seconds.
693
+ nprocs : int, optional
694
+ Number of processes to use for parallel processing. Default is 1.
695
+ orthogonalize : bool, optional
696
+ If True, orthogonalize the regressors to reduce multicollinearity.
697
+ Default is True.
698
+ tcstart : int, optional
699
+ Start timepoint index for regressor data. Default is 0.
700
+ tcend : int, optional
701
+ End timepoint index for regressor data. If -1, use all timepoints
702
+ from `tcstart`. Default is -1.
703
+ tchp : float, optional
704
+ High-pass cutoff frequency for filtering. If None, no high-pass filtering
705
+ is applied.
706
+ tclp : float, optional
707
+ Low-pass cutoff frequency for filtering. If None, no low-pass filtering
708
+ is applied.
709
+ showprogressbar : bool, optional
710
+ If True, display a progress bar during processing. Default is True.
711
+ debug : bool, optional
712
+ If True, enable debug output. Default is False.
713
+
714
+ Returns
715
+ -------
716
+ tuple of (NDArray, list of str, NDArray, NDArray)
717
+ - `theregressors`: Processed regressors (possibly orthogonalized).
718
+ - `theregressorlabels`: Updated labels for the regressors.
719
+ - `filtereddata`: Data with confounds removed.
720
+ - `r2value`: R-squared values for each voxel (or None if not computed).
721
+
722
+ Notes
723
+ -----
724
+ - The function applies standard deviation normalization to regressors for
725
+ numerical stability.
726
+ - If `orthogonalize` is True, Gram-Schmidt orthogonalization is applied to
727
+ the regressors.
728
+ - Filtering is applied using a trapezoidal filter if `tchp` or `tclp` are provided.
729
+ - The function uses `linfitfiltpass` internally for the actual regression.
730
+
731
+ Examples
732
+ --------
733
+ >>> regressors = np.random.rand(3, 100)
734
+ >>> labels = ['motion_x', 'motion_y', 'motion_z']
735
+ >>> data = np.random.rand(50, 100)
736
+ >>> tr = 2.0
737
+ >>> processed_regressors, labels, filtered_data, r2 = confoundregress(
738
+ ... regressors, labels, data, tr, nprocs=4
739
+ ... )
740
+ """
475
741
  if tcend == -1:
476
742
  theregressors = theregressors[:, tcstart:]
477
743
  else: