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
@@ -18,19 +18,54 @@
18
18
  #
19
19
  import argparse
20
20
  import sys
21
+ from typing import Any, Tuple, Union
21
22
 
22
23
  import matplotlib.pyplot as plt
23
24
  import numpy as np
24
25
  from mpl_toolkits.axes_grid1 import make_axes_locatable
25
- from scipy.signal import check_NOLA, stft
26
+ from numpy.typing import NDArray
27
+ from scipy.signal import ShortTimeFFT, check_NOLA, stft
26
28
 
27
29
  import rapidtide.io as tide_io
28
30
  from rapidtide.workflows.parser_funcs import is_float, is_int, is_valid_file
29
31
 
32
+ NPFloat2DArray = NDArray[Union[np.float32, np.float64]]
30
33
 
31
- def _get_parser():
34
+
35
+ def _get_parser() -> Any:
32
36
  """
33
- Argument parser for spectrogram
37
+ Argument parser for spectrogram.
38
+
39
+ This function creates and configures an argument parser for the spectrogram
40
+ command-line tool that computes and displays spectrograms from text files
41
+ containing timecourse data.
42
+
43
+ Returns
44
+ -------
45
+ argparse.ArgumentParser
46
+ Configured argument parser object with all required and optional
47
+ arguments for spectrogram computation.
48
+
49
+ Notes
50
+ -----
51
+ The parser expects a text file containing one data point per line and a
52
+ specified sample rate. The spectrogram is computed using the Short-Time
53
+ Fourier Transform (STFT) with configurable segment length.
54
+
55
+ Examples
56
+ --------
57
+ >>> parser = _get_parser()
58
+ >>> args = parser.parse_args(['input.txt', '44100'])
59
+ >>> print(args.textfilename)
60
+ 'input.txt'
61
+ >>> print(args.samplerate)
62
+ 44100
63
+
64
+ See Also
65
+ --------
66
+ is_valid_file : Validates input file existence and readability
67
+ is_float : Validates float conversion
68
+ is_int : Validates integer conversion
34
69
  """
35
70
  parser = argparse.ArgumentParser(
36
71
  prog="spectrogram",
@@ -38,15 +73,14 @@ def _get_parser():
38
73
  allow_abbrev=False,
39
74
  )
40
75
 
41
- # Required arguments
76
+ # Required argument
42
77
  parser.add_argument(
43
- "textfilename",
78
+ "inputfile",
44
79
  type=lambda x: is_valid_file(parser, x),
45
80
  help="The input data file (text file containing a timecourse, one point per line).",
46
81
  )
47
- parser.add_argument(
48
- "samplerate", type=lambda x: is_float(parser, x), help="Sample rate in Hz."
49
- )
82
+
83
+ # Optional arguments
50
84
  parser.add_argument(
51
85
  "--nperseg",
52
86
  dest="nperseg",
@@ -55,6 +89,15 @@ def _get_parser():
55
89
  help=("The number of points to include in each spectrogram (default is 128)."),
56
90
  default=128,
57
91
  )
92
+ parser.add_argument(
93
+ "--samplerate",
94
+ dest="samplerate",
95
+ metavar="RATE",
96
+ action="store",
97
+ type=lambda x: is_float(parser, x),
98
+ help="Sample rate in Hz.",
99
+ default=None,
100
+ )
58
101
  parser.add_argument(
59
102
  "--debug",
60
103
  dest="debug",
@@ -66,32 +109,138 @@ def _get_parser():
66
109
  return parser
67
110
 
68
111
 
69
- def calcspecgram(x, time, nperseg=32, windowtype="hann"):
70
- """Make and plot a log-scaled spectrogram"""
112
+ def calcspecgram(
113
+ x: NDArray[np.floating[Any]],
114
+ time: NDArray[np.floating[Any]],
115
+ nperseg: int = 32,
116
+ windowtype: str = "hann",
117
+ ) -> Tuple[NDArray, NDArray, NDArray, bool]:
118
+ """
119
+ Make and plot a log-scaled spectrogram.
120
+
121
+ This function computes a spectrogram using the Short-Time Fourier Transform (STFT)
122
+ with configurable window parameters and returns frequency, time, and STFT data
123
+ along with a check for invertibility.
124
+
125
+ Parameters
126
+ ----------
127
+ x : NDArray[np.floating[Any]]
128
+ Input signal data to compute the spectrogram for.
129
+ time : NDArray[np.floating[Any]]
130
+ Time vector corresponding to the input signal. Used to calculate sampling
131
+ frequency from the time differences.
132
+ nperseg : int, optional
133
+ Length of each segment for the STFT, by default 32.
134
+ windowtype : str, optional
135
+ Type of window to use for the STFT, by default "hann".
136
+
137
+ Returns
138
+ -------
139
+ freq : ndarray
140
+ Array of frequencies corresponding to the spectrogram rows.
141
+ segtimes : ndarray
142
+ Array of time points corresponding to the spectrogram columns.
143
+ thestft : ndarray
144
+ Short-Time Fourier Transform of the input signal.
145
+ isinvertable : bool
146
+ Boolean flag indicating whether the window satisfies the Non-Overlap
147
+ Additivity of Overlapped Windows (NOLA) constraint for invertibility.
148
+
149
+ Notes
150
+ -----
151
+ The function calculates the sampling frequency from the time vector and uses
152
+ the ShortTimeFFT library to compute the STFT. The window overlap is set to
153
+ ensure maximum overlap (nperseg - 1) for optimal spectrogram resolution.
154
+
155
+ Examples
156
+ --------
157
+ >>> import numpy as np
158
+ >>> from scipy.signal import chirp
159
+ >>> t = np.linspace(0, 1, 1000)
160
+ >>> x = chirp(t, f0=1, f1=10, t1=1, method='linear')
161
+ >>> freq, times, stft, invertible = calcspecgram(x, t)
162
+ >>> print(f"Frequency range: {freq[0]:.2f} to {freq[-1]:.2f} Hz")
163
+ >>> print(f"Time range: {times[0]:.2f} to {times[-1]:.2f} seconds")
164
+ """
71
165
  dt = np.diff(time)[0] # In days...
72
166
  fs = 1.0 / dt
73
- nfft = nperseg
74
167
  noverlap = nperseg - 1
75
168
 
76
- freq, segtimes, thestft = stft(
77
- x,
78
- fs=fs,
79
- window=windowtype,
80
- nperseg=nperseg,
81
- noverlap=noverlap,
82
- nfft=nfft,
83
- detrend="linear",
84
- return_onesided=True,
85
- boundary="zeros",
86
- padded=True,
87
- axis=-1,
169
+ SFT = ShortTimeFFT.from_window(
170
+ windowtype,
171
+ fs,
172
+ nperseg,
173
+ noverlap,
174
+ mfft=nperseg,
175
+ fft_mode="onesided",
176
+ scale_to="magnitude",
177
+ phase_shift=None,
88
178
  )
179
+ freq = SFT.f
180
+ thestft = SFT.stft(x, p0=0, p1=(len(x) - noverlap) // SFT.hop, k_offset=nperseg // 2)
181
+ segtimes = SFT.t(len(x), p0=0, p1=(len(x) - noverlap) // SFT.hop, k_offset=nperseg // 2)
89
182
 
90
183
  isinvertable = check_NOLA(windowtype, nperseg, noverlap, tol=1e-10)
91
184
  return freq, segtimes, thestft, isinvertable
92
185
 
93
186
 
94
- def showspecgram(thestft, time, freq, ax, fig, mode="mag"):
187
+ def showspecgram(
188
+ thestft: Any, time: Any, freq: Any, ax: Any, fig: Any, mode: str = "mag"
189
+ ) -> Tuple[Any, Any]:
190
+ """
191
+ Display a spectrogram plot based on the provided STFT data.
192
+
193
+ This function visualizes the Short-Time Fourier Transform (STFT) of a signal
194
+ in the form of a spectrogram. It supports multiple display modes including
195
+ magnitude, phase, real, and imaginary components. The function also handles
196
+ logarithmic scaling for amplitude values and includes a colorbar with appropriate
197
+ labeling.
198
+
199
+ Parameters
200
+ ----------
201
+ thestft : Any
202
+ The Short-Time Fourier Transform (STFT) of the signal. Typically a 2D array
203
+ where rows correspond to frequency bins and columns to time frames.
204
+ time : Any
205
+ Time vector corresponding to the STFT columns. Used for x-axis labeling.
206
+ freq : Any
207
+ Frequency vector corresponding to the STFT rows. Used for y-axis labeling.
208
+ ax : Any
209
+ Matplotlib axis object on which the spectrogram will be plotted.
210
+ fig : Any
211
+ Matplotlib figure object used to create the colorbar.
212
+ mode : str, optional
213
+ The mode of visualization. Options are:
214
+ - "mag": Magnitude of the STFT (default)
215
+ - "phase": Phase of the STFT
216
+ - "real": Real part of the STFT
217
+ - "imag": Imaginary part of the STFT
218
+
219
+ Returns
220
+ -------
221
+ Tuple[Any, Any]
222
+ A tuple containing:
223
+ - im: The image object returned by `pcolormesh`
224
+ - cbar: The colorbar object added to the plot
225
+
226
+ Notes
227
+ -----
228
+ - For magnitude mode, the data is log-scaled using `log10`.
229
+ - For phase mode, the data is scaled between -π and π.
230
+ - The y-axis is set to range from `freq[1]` to `freq.max()` to avoid potential
231
+ issues with zero frequency bins.
232
+ - X-axis tick labels are hidden for cleaner visualization.
233
+ - If an invalid `mode` is provided, the function will print an error and exit.
234
+
235
+ Examples
236
+ --------
237
+ >>> import numpy as np
238
+ >>> import matplotlib.pyplot as plt
239
+ >>> # Assuming `sft` is your STFT data, `t` is time, `f` is frequency
240
+ >>> fig, ax = plt.subplots()
241
+ >>> im, cbar = showspecgram(sft, t, f, ax, fig, mode="mag")
242
+ >>> plt.show()
243
+ """
95
244
  # Log scaling for amplitude values
96
245
  if mode == "mag":
97
246
  spec_img = np.log10(np.abs(thestft))
@@ -145,13 +294,84 @@ def showspecgram(thestft, time, freq, ax, fig, mode="mag"):
145
294
  return im, cbar
146
295
 
147
296
 
148
- def make_legend_axes(ax):
297
+ def make_legend_axes(ax: Any) -> object:
298
+ """
299
+ Create a new axes for legend placement next to the given axes.
300
+
301
+ This function creates a new axes object positioned to the right of the
302
+ provided axes, which can be used for placing legends. The new axes is
303
+ created using matplotlib's make_axes_locatable utility.
304
+
305
+ Parameters
306
+ ----------
307
+ ax : matplotlib.axes.Axes
308
+ The original axes object to which the legend axes will be appended.
309
+
310
+ Returns
311
+ -------
312
+ matplotlib.axes.Axes
313
+ The newly created axes object that can be used for legend placement.
314
+
315
+ Notes
316
+ -----
317
+ The legend axes is positioned to the right of the original axes with:
318
+ - Size: 0.4 inches width
319
+ - Padding: 0.2 inches from the original axes
320
+
321
+ Examples
322
+ --------
323
+ >>> import matplotlib.pyplot as plt
324
+ >>> fig, ax = plt.subplots()
325
+ >>> ax.plot([1, 2, 3], [1, 4, 9])
326
+ >>> legend_ax = make_legend_axes(ax)
327
+ >>> ax.legend(['data'], bbox_to_anchor=(1.05, 1), loc='upper left')
328
+ >>> plt.show()
329
+ """
149
330
  divider = make_axes_locatable(ax)
150
331
  legend_ax = divider.append_axes("right", 0.4, pad=0.2)
151
332
  return legend_ax
152
333
 
153
334
 
154
- def ndplot(x, time, thelabel, nperseg=32):
335
+ def ndplot(x: Any, time: Any, thelabel: Any, nperseg: int = 32) -> None:
336
+ """
337
+ Plot spectrogram magnitude, phase, and time-domain signal.
338
+
339
+ This function computes and displays a spectrogram of the input signal `x` using
340
+ the Short-Time Fourier Transform (STFT). It shows the magnitude and phase of
341
+ the spectrogram in separate subplots, and overlays the original time-domain
342
+ signal on a third subplot.
343
+
344
+ Parameters
345
+ ----------
346
+ x : array-like
347
+ Input signal to be analyzed.
348
+ time : array-like
349
+ Time vector corresponding to the signal `x`.
350
+ thelabel : str
351
+ Label used for plotting titles.
352
+ nperseg : int, optional
353
+ Length of each segment for the STFT. Default is 32.
354
+
355
+ Returns
356
+ -------
357
+ None
358
+ This function does not return any value. It displays the plot directly.
359
+
360
+ Notes
361
+ -----
362
+ - The function uses `calcspecgram` to compute the STFT and checks if the
363
+ spectrogram is invertible.
364
+ - The magnitude and phase are plotted in the first two subplots.
365
+ - The time-domain signal is overlaid in the third subplot.
366
+ - The function relies on `showspecgram` for plotting the spectrograms.
367
+
368
+ Examples
369
+ --------
370
+ >>> import numpy as np
371
+ >>> t = np.linspace(0, 1, 1000)
372
+ >>> x = np.sin(2 * np.pi * 50 * t)
373
+ >>> ndplot(x, t, "Example Signal")
374
+ """
155
375
  print("arrived in ndplot")
156
376
  fig = plt.figure()
157
377
 
@@ -196,7 +416,45 @@ def ndplot(x, time, thelabel, nperseg=32):
196
416
  # plt.subplots_adjust(hspace=0.0)
197
417
 
198
418
 
199
- def spectrogram(args):
419
+ def spectrogram(args: Any) -> None:
420
+ """
421
+ Compute and display spectrogram of time series data from text file.
422
+
423
+ This function reads time series data from a text file, computes its spectrogram
424
+ using Welch's method, and displays the result. The spectrogram shows how
425
+ the frequency content of the signal changes over time.
426
+
427
+ Parameters
428
+ ----------
429
+ args : Any
430
+ Command line arguments containing:
431
+ - textfilename : str
432
+ Path to the text file containing time series data
433
+ - samplerate : float
434
+ Sampling rate of the tidal data in Hz
435
+ - nperseg : int, optional
436
+ Length of each segment for FFT (default: 256)
437
+ - debug : bool, optional
438
+ Enable debug output (default: False)
439
+
440
+ Returns
441
+ -------
442
+ None
443
+ This function displays the spectrogram plot and does not return any value.
444
+
445
+ Notes
446
+ -----
447
+ The function uses Welch's method for spectral estimation, which divides the
448
+ signal into overlapping segments and averages their periodograms. The time
449
+ axis is automatically calculated based on the sampling rate and data length.
450
+
451
+ Examples
452
+ --------
453
+ >>> import argparse
454
+ >>> args = argparse.Namespace(textfilename='tidal_data.txt',
455
+ ... samplerate=10.0, nperseg=512, debug=False)
456
+ >>> spectrogram(args)
457
+ """
200
458
  # get the command line parameters
201
459
  try:
202
460
  args = _get_parser().parse_args()
@@ -206,12 +464,27 @@ def spectrogram(args):
206
464
  if args.debug:
207
465
  print(args)
208
466
 
209
- # handle required args first
210
- timestep = 1.0 / args.samplerate
467
+ # read in data
468
+ (
469
+ samplerate,
470
+ starttime,
471
+ colnames,
472
+ yvec,
473
+ compressed,
474
+ filetype,
475
+ ) = tide_io.readvectorsfromtextfile(args.inputfile, onecol=True)
476
+
477
+ # get the sample rate squared away
478
+ if args.samplerate is not None:
479
+ samplerate = args.samplerate
480
+ else:
481
+ if samplerate is None:
482
+ print("Sample rate must be specified in input file or with --samplerate")
483
+ sys.exit()
484
+ timestep = 1.0 / samplerate
211
485
 
212
- yvec = tide_io.readvec(args.textfilename)
213
- xvec = np.arange(0.0, len(yvec), 1.0) * timestep
486
+ xvec = np.arange(0.0, len(yvec), 1.0) * timestep + starttime
214
487
 
215
- thelabel = args.textfilename
488
+ thelabel = args.inputfile
216
489
  ndplot(yvec, xvec, thelabel, nperseg=args.nperseg)
217
490
  plt.show()
@@ -17,14 +17,42 @@
17
17
  #
18
18
  #
19
19
  import argparse
20
+ from argparse import Namespace
21
+ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
20
22
 
21
23
  import numpy as np
24
+ from numpy.typing import NDArray
22
25
 
23
26
  import rapidtide.io as tide_io
24
27
  from rapidtide.RapidtideDataset import RapidtideDataset
25
28
 
26
29
 
27
- def _get_parser():
30
+ def _get_parser() -> Any:
31
+ """
32
+ Get the argument parser for the synthASL command-line tool.
33
+
34
+ This function constructs and returns an `argparse.ArgumentParser` object configured
35
+ with the necessary arguments for running the synthASL tool, which uses rapidtide
36
+ output to predict ASL (Arterial Spin Labeling) images.
37
+
38
+ Returns
39
+ -------
40
+ argparse.ArgumentParser
41
+ Configured argument parser with required and optional arguments for synthASL.
42
+
43
+ Notes
44
+ -----
45
+ The parser includes both required positional arguments and several optional
46
+ arguments that control the ASL synthesis process. Default values are set according
47
+ to typical parameters used in ASL analysis.
48
+
49
+ Examples
50
+ --------
51
+ >>> parser = _get_parser()
52
+ >>> args = parser.parse_args(['dataset_name', 'output.nii.gz'])
53
+ >>> print(args.dataset)
54
+ 'dataset_name'
55
+ """
28
56
  # get the command line parameters
29
57
  parser = argparse.ArgumentParser(
30
58
  prog="synthASL",
@@ -70,7 +98,72 @@ def _get_parser():
70
98
  return parser
71
99
 
72
100
 
73
- def calcASL(lags, strengths, widths, mask, tagoffset=2.945, pld=1.8, TI=1.8, bloodT1=1.841):
101
+ def calcASL(
102
+ lags: Any,
103
+ strengths: Any,
104
+ widths: Any,
105
+ mask: Any,
106
+ tagoffset: float = 2.945,
107
+ pld: float = 1.8,
108
+ TI: float = 1.8,
109
+ bloodT1: float = 1.841,
110
+ ) -> None:
111
+ """
112
+ Calculate ASL (Arterial Spin Labeling) signal based on lags, strengths, and timing parameters.
113
+
114
+ This function computes the ASL signal by applying temporal dynamics to the input lags and
115
+ strengths, considering blood T1 relaxation effects and tagging timing parameters.
116
+
117
+ Parameters
118
+ ----------
119
+ lags : array-like
120
+ Time lags for the ASL signal calculation
121
+ strengths : array-like
122
+ Signal strengths corresponding to the lags
123
+ widths : array-like
124
+ Widths parameter (not used in current implementation)
125
+ mask : array-like
126
+ Binary mask for region of interest
127
+ tagoffset : float, optional
128
+ Tagging offset in seconds, default is 2.945
129
+ pld : float, optional
130
+ Preparation delay in seconds, default is 1.8
131
+ TI : float, optional
132
+ Inversion time in seconds, default is 1.8
133
+ bloodT1 : float, optional
134
+ Blood T1 relaxation time in seconds, default is 1.841
135
+
136
+ Returns
137
+ -------
138
+ tuple
139
+ A tuple containing:
140
+ - theaslimage : array-like
141
+ Calculated ASL image signal
142
+ - tagdecayfac : array-like
143
+ Tagging decay factor
144
+ - oxyfac : array-like
145
+ Oxygenation factor (constant value of 1.0)
146
+ - cbvfac : array-like
147
+ CBV (Cerebral Blood Volume) factor
148
+ - calcmask : array-like
149
+ Calculated mask with time constraints
150
+ - offsets : array-like
151
+ Time offsets after adding tagoffset
152
+
153
+ Notes
154
+ -----
155
+ The function applies exponential decay based on blood T1 relaxation and only considers
156
+ positive delays after the preparation delay (pld). The calculation uses a linear
157
+ interpolation over 50 time points between pld and pld + TI.
158
+
159
+ Examples
160
+ --------
161
+ >>> import numpy as np
162
+ >>> lags = np.array([0.5, 1.0, 1.5])
163
+ >>> strengths = np.array([1.0, 1.5, 2.0])
164
+ >>> mask = np.array([1, 1, 1])
165
+ >>> result = calcASL(lags, strengths, None, mask)
166
+ """
74
167
  theaslimage = lags * 0.0
75
168
 
76
169
  # convert rapidtide delays to time from tagging, and only keep positive delays after pld
@@ -85,7 +178,65 @@ def calcASL(lags, strengths, widths, mask, tagoffset=2.945, pld=1.8, TI=1.8, blo
85
178
  return theaslimage, tagdecayfac, oxyfac, cbvfac, calcmask, offsets
86
179
 
87
180
 
88
- def synthASL(args):
181
+ def synthASL(args: Any) -> None:
182
+ """
183
+ Generate synthetic ASL (Arterial Spin Labeling) images and associated parameters.
184
+
185
+ This function reads ASL dataset parameters from a specified input dataset,
186
+ computes synthetic ASL signal using the `calcASL` function, and saves the
187
+ resulting images and intermediate outputs as NIfTI files.
188
+
189
+ Parameters
190
+ ----------
191
+ args : Any
192
+ Command-line arguments object containing the following attributes:
193
+ - dataset : str
194
+ Path to the input dataset.
195
+ - outputfilename : str
196
+ Base name for output NIfTI files.
197
+ - bloodT1 : float
198
+ Blood T1 relaxation time in seconds.
199
+ - tagoffset : float
200
+ Tag offset in seconds.
201
+ - pld : float
202
+ Post-labeling delay in seconds.
203
+ - labelduration : float
204
+ Labeling pulse duration in seconds.
205
+
206
+ Returns
207
+ -------
208
+ None
209
+ This function does not return a value but writes multiple NIfTI files
210
+ to disk, including:
211
+ - `<outputfilename>_ASL.nii.gz`
212
+ - `<outputfilename>_tagdecayfac.nii.gz`
213
+ - `<outputfilename>_oxyfac.nii.gz`
214
+ - `<outputfilename>_cbvfac.nii.gz`
215
+ - `<outputfilename>_calcmask.nii.gz`
216
+ - `<outputfilename>_offsets.nii.gz`
217
+ - `<outputfilename>_lagmask.nii.gz`
218
+ - `<outputfilename>_lagtimes.nii.gz`
219
+ - `<outputfilename>_lagstrengths.nii.gz`
220
+
221
+ Notes
222
+ -----
223
+ The function relies on the `RapidtideDataset` class to load overlay data
224
+ and uses `calcASL` to compute the synthetic ASL signal. All outputs are
225
+ saved using `tide_io.savetonifti`.
226
+
227
+ Examples
228
+ --------
229
+ >>> import argparse
230
+ >>> args = argparse.Namespace(
231
+ ... dataset="path/to/dataset",
232
+ ... outputfilename="output",
233
+ ... bloodT1=1.6,
234
+ ... tagoffset=0.0,
235
+ ... pld=1.5,
236
+ ... labelduration=1.0
237
+ ... )
238
+ >>> synthASL(args)
239
+ """
89
240
  # get the command line parameters
90
241
  try:
91
242
  args = _get_parser().parse_args()
@@ -17,14 +17,42 @@
17
17
  #
18
18
  #
19
19
  import argparse
20
+ from argparse import Namespace
21
+ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
20
22
 
21
23
  import numpy as np
24
+ from numpy.typing import NDArray
22
25
 
23
26
  import rapidtide.io as tide_io
24
27
  import rapidtide.util as tide_util
25
28
 
26
29
 
27
- def _get_parser():
30
+ def _get_parser() -> Any:
31
+ """
32
+ Create and configure argument parser for tcfrom2col command line tool.
33
+
34
+ This function sets up an argument parser with required and optional arguments
35
+ for processing two-column data files into time course output.
36
+
37
+ Returns
38
+ -------
39
+ argparse.ArgumentParser
40
+ Configured argument parser object with all required and optional arguments
41
+ for the tcfrom2col tool.
42
+
43
+ Notes
44
+ -----
45
+ The parser includes the following required arguments:
46
+ - infilename: input two column file name
47
+ - timestep: time step of output time course in seconds
48
+ - numpoints: number of output time points
49
+ - outfilename: output time course file name
50
+
51
+ Examples
52
+ --------
53
+ >>> parser = _get_parser()
54
+ >>> args = parser.parse_args()
55
+ """
28
56
  # get the command line parameters
29
57
  parser = argparse.ArgumentParser(
30
58
  prog="tcfrom2col",
@@ -48,7 +76,53 @@ def _get_parser():
48
76
  return parser
49
77
 
50
78
 
51
- def tcfrom2col(args):
79
+ def tcfrom2col(args: Any) -> None:
80
+ """
81
+ Convert two-column data to tidal constituent data.
82
+
83
+ This function reads two-column input data, processes it to extract tidal constituents,
84
+ and writes the results to an output file. The input data is expected to be in a format
85
+ suitable for tidal analysis, and the output contains the computed tidal constituents.
86
+
87
+ Parameters
88
+ ----------
89
+ args : Any
90
+ An object containing the following attributes:
91
+ - infilename : str
92
+ Path to the input file containing two-column data
93
+ - outfilename : str
94
+ Path to the output file for writing tidal constituent data
95
+ - numpoints : int
96
+ Number of data points in the time series
97
+ - timestep : float
98
+ Time step between data points
99
+ - debug : bool
100
+ Flag to enable debug printing
101
+
102
+ Returns
103
+ -------
104
+ None
105
+ This function does not return a value but writes output to a file.
106
+
107
+ Notes
108
+ -----
109
+ The function uses `tide_io.readvecs` to read input data and `tide_util.maketcfrom2col`
110
+ to perform the tidal constituent calculation. The time axis is generated based on the
111
+ number of points and time step provided in the args object.
112
+
113
+ Examples
114
+ --------
115
+ >>> class Args:
116
+ ... def __init__(self):
117
+ ... self.infilename = 'input.txt'
118
+ ... self.outfilename = 'output.txt'
119
+ ... self.numpoints = 1000
120
+ ... self.timestep = 300.0
121
+ ... self.debug = False
122
+ ...
123
+ >>> args = Args()
124
+ >>> tcfrom2col(args)
125
+ """
52
126
  if args.debug:
53
127
  print(args)
54
128