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.
- rapidtide/Colortables.py +492 -27
- rapidtide/OrthoImageItem.py +1053 -47
- rapidtide/RapidtideDataset.py +1533 -86
- rapidtide/_version.py +3 -3
- rapidtide/calccoherence.py +196 -29
- rapidtide/calcnullsimfunc.py +191 -40
- rapidtide/calcsimfunc.py +245 -42
- rapidtide/correlate.py +1210 -393
- rapidtide/data/examples/src/testLD +56 -0
- rapidtide/data/examples/src/testalign +1 -1
- rapidtide/data/examples/src/testdelayvar +0 -1
- rapidtide/data/examples/src/testfmri +19 -1
- rapidtide/data/examples/src/testglmfilt +5 -5
- rapidtide/data/examples/src/testhappy +30 -1
- rapidtide/data/examples/src/testppgproc +17 -0
- rapidtide/data/examples/src/testrolloff +11 -0
- rapidtide/data/models/model_cnn_pytorch/best_model.pth +0 -0
- rapidtide/data/models/model_cnn_pytorch/loss.png +0 -0
- rapidtide/data/models/model_cnn_pytorch/loss.txt +1 -0
- rapidtide/data/models/model_cnn_pytorch/model.pth +0 -0
- rapidtide/data/models/model_cnn_pytorch/model_meta.json +68 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm.nii.gz +0 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm_mask.nii.gz +0 -0
- rapidtide/decorators.py +91 -0
- rapidtide/dlfilter.py +2225 -108
- rapidtide/dlfiltertorch.py +4843 -0
- rapidtide/externaltools.py +327 -12
- rapidtide/fMRIData_class.py +79 -40
- rapidtide/filter.py +1899 -810
- rapidtide/fit.py +2004 -574
- rapidtide/genericmultiproc.py +93 -18
- rapidtide/happy_supportfuncs.py +2044 -171
- rapidtide/helper_classes.py +584 -43
- rapidtide/io.py +2363 -370
- rapidtide/linfitfiltpass.py +341 -75
- rapidtide/makelaggedtcs.py +211 -20
- rapidtide/maskutil.py +423 -53
- rapidtide/miscmath.py +827 -121
- rapidtide/multiproc.py +210 -22
- rapidtide/patchmatch.py +234 -33
- rapidtide/peakeval.py +32 -30
- rapidtide/ppgproc.py +2203 -0
- rapidtide/qualitycheck.py +352 -39
- rapidtide/refinedelay.py +422 -57
- rapidtide/refineregressor.py +498 -184
- rapidtide/resample.py +671 -185
- rapidtide/scripts/applyppgproc.py +28 -0
- rapidtide/simFuncClasses.py +1052 -77
- rapidtide/simfuncfit.py +260 -46
- rapidtide/stats.py +540 -238
- rapidtide/tests/happycomp +9 -0
- rapidtide/tests/test_dlfiltertorch.py +627 -0
- rapidtide/tests/test_findmaxlag.py +24 -8
- rapidtide/tests/test_fullrunhappy_v1.py +0 -2
- rapidtide/tests/test_fullrunhappy_v2.py +0 -2
- rapidtide/tests/test_fullrunhappy_v3.py +1 -0
- rapidtide/tests/test_fullrunhappy_v4.py +2 -2
- rapidtide/tests/test_fullrunrapidtide_v7.py +1 -1
- rapidtide/tests/test_simroundtrip.py +8 -8
- rapidtide/tests/utils.py +9 -8
- rapidtide/tidepoolTemplate.py +142 -38
- rapidtide/tidepoolTemplate_alt.py +165 -44
- rapidtide/tidepoolTemplate_big.py +189 -52
- rapidtide/util.py +1217 -118
- rapidtide/voxelData.py +684 -37
- rapidtide/wiener.py +19 -12
- rapidtide/wiener2.py +113 -7
- rapidtide/wiener_doc.py +255 -0
- rapidtide/workflows/adjustoffset.py +105 -3
- rapidtide/workflows/aligntcs.py +85 -2
- rapidtide/workflows/applydlfilter.py +87 -10
- rapidtide/workflows/applyppgproc.py +522 -0
- rapidtide/workflows/atlasaverage.py +210 -47
- rapidtide/workflows/atlastool.py +100 -3
- rapidtide/workflows/calcSimFuncMap.py +294 -64
- rapidtide/workflows/calctexticc.py +201 -9
- rapidtide/workflows/ccorrica.py +97 -4
- rapidtide/workflows/cleanregressor.py +168 -29
- rapidtide/workflows/delayvar.py +163 -10
- rapidtide/workflows/diffrois.py +81 -3
- rapidtide/workflows/endtidalproc.py +144 -4
- rapidtide/workflows/fdica.py +195 -15
- rapidtide/workflows/filtnifti.py +70 -3
- rapidtide/workflows/filttc.py +74 -3
- rapidtide/workflows/fitSimFuncMap.py +206 -48
- rapidtide/workflows/fixtr.py +73 -3
- rapidtide/workflows/gmscalc.py +113 -3
- rapidtide/workflows/happy.py +813 -201
- rapidtide/workflows/happy2std.py +144 -12
- rapidtide/workflows/happy_parser.py +149 -8
- rapidtide/workflows/histnifti.py +118 -2
- rapidtide/workflows/histtc.py +84 -3
- rapidtide/workflows/linfitfilt.py +117 -4
- rapidtide/workflows/localflow.py +328 -28
- rapidtide/workflows/mergequality.py +79 -3
- rapidtide/workflows/niftidecomp.py +322 -18
- rapidtide/workflows/niftistats.py +174 -4
- rapidtide/workflows/pairproc.py +88 -2
- rapidtide/workflows/pairwisemergenifti.py +85 -2
- rapidtide/workflows/parser_funcs.py +1421 -40
- rapidtide/workflows/physiofreq.py +137 -11
- rapidtide/workflows/pixelcomp.py +208 -5
- rapidtide/workflows/plethquality.py +103 -21
- rapidtide/workflows/polyfitim.py +151 -11
- rapidtide/workflows/proj2flow.py +75 -2
- rapidtide/workflows/rankimage.py +111 -4
- rapidtide/workflows/rapidtide.py +272 -15
- rapidtide/workflows/rapidtide2std.py +98 -2
- rapidtide/workflows/rapidtide_parser.py +109 -9
- rapidtide/workflows/refineDelayMap.py +143 -33
- rapidtide/workflows/refineRegressor.py +682 -93
- rapidtide/workflows/regressfrommaps.py +152 -31
- rapidtide/workflows/resamplenifti.py +85 -3
- rapidtide/workflows/resampletc.py +91 -3
- rapidtide/workflows/retrolagtcs.py +98 -6
- rapidtide/workflows/retroregress.py +165 -9
- rapidtide/workflows/roisummarize.py +173 -5
- rapidtide/workflows/runqualitycheck.py +71 -3
- rapidtide/workflows/showarbcorr.py +147 -4
- rapidtide/workflows/showhist.py +86 -2
- rapidtide/workflows/showstxcorr.py +160 -3
- rapidtide/workflows/showtc.py +159 -3
- rapidtide/workflows/showxcorrx.py +184 -4
- rapidtide/workflows/showxy.py +185 -15
- rapidtide/workflows/simdata.py +262 -36
- rapidtide/workflows/spatialfit.py +77 -2
- rapidtide/workflows/spatialmi.py +251 -27
- rapidtide/workflows/spectrogram.py +305 -32
- rapidtide/workflows/synthASL.py +154 -3
- rapidtide/workflows/tcfrom2col.py +76 -2
- rapidtide/workflows/tcfrom3col.py +74 -2
- rapidtide/workflows/tidepool.py +2972 -133
- rapidtide/workflows/utils.py +19 -14
- rapidtide/workflows/utils_doc.py +293 -0
- rapidtide/workflows/variabilityizer.py +116 -3
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/METADATA +10 -9
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/RECORD +141 -122
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/entry_points.txt +1 -0
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/WHEEL +0 -0
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/licenses/LICENSE +0 -0
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/top_level.txt +0 -0
|
@@ -18,9 +18,12 @@
|
|
|
18
18
|
#
|
|
19
19
|
import argparse
|
|
20
20
|
import os
|
|
21
|
+
from argparse import Namespace
|
|
22
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
|
21
23
|
|
|
22
24
|
import matplotlib.pyplot as plt
|
|
23
25
|
import numpy as np
|
|
26
|
+
from numpy.typing import NDArray
|
|
24
27
|
from scipy.signal import savgol_filter, welch
|
|
25
28
|
|
|
26
29
|
import rapidtide.filter as tide_filt
|
|
@@ -29,7 +32,32 @@ import rapidtide.io as tide_io
|
|
|
29
32
|
import rapidtide.miscmath as tide_math
|
|
30
33
|
|
|
31
34
|
|
|
32
|
-
def _get_parser():
|
|
35
|
+
def _get_parser() -> Any:
|
|
36
|
+
"""
|
|
37
|
+
Create and configure argument parser for physiofreq command line tool.
|
|
38
|
+
|
|
39
|
+
This function initializes an ArgumentParser object with all necessary
|
|
40
|
+
command line arguments for the physiofreq tool, which is designed to
|
|
41
|
+
find the dominant frequency in cardiac or respiratory waveforms.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
argparse.ArgumentParser
|
|
46
|
+
Configured argument parser object with all required arguments
|
|
47
|
+
for the physiofreq tool.
|
|
48
|
+
|
|
49
|
+
Notes
|
|
50
|
+
-----
|
|
51
|
+
The parser includes arguments for input file specification, display options,
|
|
52
|
+
sampling rate, frequency range constraints, and smoothing settings.
|
|
53
|
+
|
|
54
|
+
Examples
|
|
55
|
+
--------
|
|
56
|
+
>>> parser = _get_parser()
|
|
57
|
+
>>> args = parser.parse_args(['input.txt', '--display', '--samplerate', '2.0'])
|
|
58
|
+
>>> print(args.textfilename)
|
|
59
|
+
'input.txt'
|
|
60
|
+
"""
|
|
33
61
|
parser = argparse.ArgumentParser(
|
|
34
62
|
prog="physiofreq",
|
|
35
63
|
description="Finds the dominant frequency in a cardiac or respiratory waveform.",
|
|
@@ -75,15 +103,65 @@ def _get_parser():
|
|
|
75
103
|
|
|
76
104
|
|
|
77
105
|
def getwavefreq(
|
|
78
|
-
thewaveform,
|
|
79
|
-
thesamplerate,
|
|
80
|
-
minpermin=40.0,
|
|
81
|
-
maxpermin=140.0,
|
|
82
|
-
smooth=True,
|
|
83
|
-
smoothlen=101,
|
|
84
|
-
debug=False,
|
|
85
|
-
displayplots=False,
|
|
86
|
-
):
|
|
106
|
+
thewaveform: Any,
|
|
107
|
+
thesamplerate: Any,
|
|
108
|
+
minpermin: float = 40.0,
|
|
109
|
+
maxpermin: float = 140.0,
|
|
110
|
+
smooth: bool = True,
|
|
111
|
+
smoothlen: int = 101,
|
|
112
|
+
debug: bool = False,
|
|
113
|
+
displayplots: bool = False,
|
|
114
|
+
) -> None:
|
|
115
|
+
"""
|
|
116
|
+
Compute the fundamental frequency of a waveform using Welch's method and spectral analysis.
|
|
117
|
+
|
|
118
|
+
This function estimates the fundamental frequency of a given waveform by computing
|
|
119
|
+
its power spectrum using Welch's method, applying filtering and smoothing, and
|
|
120
|
+
identifying the peak within a specified frequency range. The result is returned in
|
|
121
|
+
beats per minute (BPM).
|
|
122
|
+
|
|
123
|
+
Parameters
|
|
124
|
+
----------
|
|
125
|
+
thewaveform : array-like
|
|
126
|
+
Input waveform data to analyze.
|
|
127
|
+
thesamplerate : float
|
|
128
|
+
Sampling rate of the waveform in Hz.
|
|
129
|
+
minpermin : float, optional
|
|
130
|
+
Minimum allowed frequency in BPM. Default is 40.0.
|
|
131
|
+
maxpermin : float, optional
|
|
132
|
+
Maximum allowed frequency in BPM. Default is 140.0.
|
|
133
|
+
smooth : bool, optional
|
|
134
|
+
If True, apply Savitzky-Golay smoothing to the spectrum. Default is True.
|
|
135
|
+
smoothlen : int, optional
|
|
136
|
+
Length of the smoothing window for Savitzky-Golay filter. Default is 101.
|
|
137
|
+
debug : bool, optional
|
|
138
|
+
If True, print debug information during computation. Default is False.
|
|
139
|
+
displayplots : bool, optional
|
|
140
|
+
If True, display intermediate plots of the power spectrum. Default is False.
|
|
141
|
+
|
|
142
|
+
Returns
|
|
143
|
+
-------
|
|
144
|
+
float
|
|
145
|
+
Estimated fundamental frequency in BPM.
|
|
146
|
+
|
|
147
|
+
Notes
|
|
148
|
+
-----
|
|
149
|
+
- The function internally uses `scipy.signal.welch` for power spectral density estimation.
|
|
150
|
+
- A Hamming window and detrending are applied before spectral analysis.
|
|
151
|
+
- The frequency range is constrained to the interval [minpermin, maxpermin].
|
|
152
|
+
- If `displayplots` is True, two plots will be shown:
|
|
153
|
+
1. Initial power spectrum with peak marked.
|
|
154
|
+
2. Smoothed spectrum with final peak marked.
|
|
155
|
+
|
|
156
|
+
Examples
|
|
157
|
+
--------
|
|
158
|
+
>>> import numpy as np
|
|
159
|
+
>>> from scipy.signal import chirp
|
|
160
|
+
>>> t = np.linspace(0, 5, 1000, endpoint=False)
|
|
161
|
+
>>> signal = chirp(t, f0=60, f1=120, t1=5, method='linear')
|
|
162
|
+
>>> freq = getwavefreq(signal, thesamplerate=1000, debug=True)
|
|
163
|
+
>>> print(f"Estimated frequency: {freq} BPM")
|
|
164
|
+
"""
|
|
87
165
|
if len(thewaveform) % 2 == 1:
|
|
88
166
|
thewaveform = thewaveform[:-1]
|
|
89
167
|
if len(thewaveform) > 1024:
|
|
@@ -141,7 +219,55 @@ def getwavefreq(
|
|
|
141
219
|
return peakfreq
|
|
142
220
|
|
|
143
221
|
|
|
144
|
-
def physiofreq(args):
|
|
222
|
+
def physiofreq(args: Any) -> None:
|
|
223
|
+
"""
|
|
224
|
+
Calculate and display the dominant frequency of physiological data.
|
|
225
|
+
|
|
226
|
+
This function reads physiological time series data from a file and determines
|
|
227
|
+
the peak frequency using wavelet analysis. It supports both JSON and standard
|
|
228
|
+
text file formats, and displays the results in Hz, BPM, and period in seconds.
|
|
229
|
+
|
|
230
|
+
Parameters
|
|
231
|
+
----------
|
|
232
|
+
args : Any
|
|
233
|
+
An object containing command line arguments with the following attributes:
|
|
234
|
+
- textfilename : str
|
|
235
|
+
Path to the input file containing physiological data
|
|
236
|
+
- samplerate : float, optional
|
|
237
|
+
Sampling rate of the data (used when file is not in JSON format)
|
|
238
|
+
- lowestbpm : float, optional
|
|
239
|
+
Minimum allowed heart rate in beats per minute (default: 30)
|
|
240
|
+
- highestbpm : float, optional
|
|
241
|
+
Maximum allowed heart rate in beats per minute (default: 200)
|
|
242
|
+
- nosmooth : bool, optional
|
|
243
|
+
If True, disables smoothing of the frequency spectrum
|
|
244
|
+
- displayplots : bool, optional
|
|
245
|
+
If True, displays frequency plots
|
|
246
|
+
|
|
247
|
+
Returns
|
|
248
|
+
-------
|
|
249
|
+
None
|
|
250
|
+
This function prints the frequency analysis results to stdout and does not return a value.
|
|
251
|
+
|
|
252
|
+
Notes
|
|
253
|
+
-----
|
|
254
|
+
The function automatically detects the file format based on the extension:
|
|
255
|
+
- JSON files are processed using `tide_io.readbidstsv()`
|
|
256
|
+
- Other formats are processed using `tide_io.readvecs()`
|
|
257
|
+
|
|
258
|
+
Examples
|
|
259
|
+
--------
|
|
260
|
+
>>> args = type('Args', (), {
|
|
261
|
+
... 'textfilename': 'data.txt',
|
|
262
|
+
... 'samplerate': 100.0,
|
|
263
|
+
... 'lowestbpm': 40,
|
|
264
|
+
... 'highestbpm': 180,
|
|
265
|
+
... 'nosmooth': False,
|
|
266
|
+
... 'displayplots': False
|
|
267
|
+
... })()
|
|
268
|
+
>>> physiofreq(args)
|
|
269
|
+
data.txt: 0.83 Hz, 49.80 per minute, period is 1.20 seconds
|
|
270
|
+
"""
|
|
145
271
|
textfileinfo, textfilecolspec = tide_io.parsefilespec(args.textfilename)
|
|
146
272
|
filebase, extension = os.path.splitext(textfileinfo[0])
|
|
147
273
|
if extension == ".json":
|
rapidtide/workflows/pixelcomp.py
CHANGED
|
@@ -25,12 +25,62 @@ from numpy.polynomial import Polynomial
|
|
|
25
25
|
import rapidtide.io as tide_io
|
|
26
26
|
|
|
27
27
|
mpl.use("Agg")
|
|
28
|
+
from argparse import Namespace
|
|
29
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
|
30
|
+
|
|
28
31
|
import matplotlib.pyplot as plt
|
|
32
|
+
from numpy.typing import NDArray
|
|
29
33
|
|
|
30
34
|
|
|
31
|
-
def _get_parser():
|
|
35
|
+
def _get_parser() -> Any:
|
|
32
36
|
"""
|
|
33
|
-
Argument parser for pixelcomp
|
|
37
|
+
Argument parser for pixelcomp.
|
|
38
|
+
|
|
39
|
+
This function creates and configures an argument parser for the pixelcomp tool,
|
|
40
|
+
which is used to compare two NIfTI files voxel by voxel and generate either
|
|
41
|
+
a contour plot or a scatter plot of the differences.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
argparse.ArgumentParser
|
|
46
|
+
Configured argument parser object with all required and optional arguments
|
|
47
|
+
for the pixelcomp tool.
|
|
48
|
+
|
|
49
|
+
Notes
|
|
50
|
+
-----
|
|
51
|
+
The parser supports the following positional arguments:
|
|
52
|
+
|
|
53
|
+
- ``inputfilename1`` : str
|
|
54
|
+
The name of the first input image NIfTI file.
|
|
55
|
+
- ``maskfilename1`` : str
|
|
56
|
+
The name of the first input mask NIfTI file.
|
|
57
|
+
- ``inputfilename2`` : str
|
|
58
|
+
The name of the second input image NIfTI file.
|
|
59
|
+
- ``maskfilename2`` : str
|
|
60
|
+
The name of the second input mask NIfTI file.
|
|
61
|
+
- ``outputroot`` : str
|
|
62
|
+
The root name of the output files.
|
|
63
|
+
|
|
64
|
+
And the following optional arguments:
|
|
65
|
+
|
|
66
|
+
- ``--scatter`` : bool, optional
|
|
67
|
+
Do a scatter plot instead of a contour plot. Default is False.
|
|
68
|
+
- ``--fitonly`` : bool, optional
|
|
69
|
+
Perform fit only - do not generate graph. Default is False.
|
|
70
|
+
- ``--nodisplay`` : bool, optional
|
|
71
|
+
Save graphs to file only - do not display. Default is True.
|
|
72
|
+
- ``--fitorder`` : int, optional
|
|
73
|
+
Order of line fit - default is 1 (linear). Default is 1.
|
|
74
|
+
- ``--usex`` : bool, optional
|
|
75
|
+
Use x instead of (y + x)/2 in Bland-Altman plot. Default is False.
|
|
76
|
+
- ``--histbins`` : int, optional
|
|
77
|
+
Number of bins per dimension for the contour plot - default is 51.
|
|
78
|
+
Default is 51.
|
|
79
|
+
|
|
80
|
+
Examples
|
|
81
|
+
--------
|
|
82
|
+
>>> parser = _get_parser()
|
|
83
|
+
>>> args = parser.parse_args()
|
|
34
84
|
"""
|
|
35
85
|
parser = argparse.ArgumentParser(
|
|
36
86
|
prog="pixelcomp",
|
|
@@ -99,7 +149,58 @@ def _get_parser():
|
|
|
99
149
|
return parser
|
|
100
150
|
|
|
101
151
|
|
|
102
|
-
def bland_altman_plot(
|
|
152
|
+
def bland_altman_plot(
|
|
153
|
+
data1: Any, data2: Any, usex: bool = False, *args: Any, **kwargs: Any
|
|
154
|
+
) -> None:
|
|
155
|
+
"""
|
|
156
|
+
Create a Bland-Altman plot for comparing two sets of measurements.
|
|
157
|
+
|
|
158
|
+
This function generates a scatter plot showing the difference between two
|
|
159
|
+
measurements against their mean. The plot includes horizontal lines indicating
|
|
160
|
+
the mean difference and ±2 standard deviations, which are commonly used to
|
|
161
|
+
assess agreement between two measurement methods.
|
|
162
|
+
|
|
163
|
+
Parameters
|
|
164
|
+
----------
|
|
165
|
+
data1 : array-like
|
|
166
|
+
First set of measurements (X values in the plot).
|
|
167
|
+
data2 : array-like
|
|
168
|
+
Second set of measurements (Y values in the plot).
|
|
169
|
+
usex : bool, optional
|
|
170
|
+
If True, use data1 as the x-values for the plot. If False (default),
|
|
171
|
+
use the mean of data1 and data2 as x-values.
|
|
172
|
+
*args : tuple
|
|
173
|
+
Additional arguments to pass to matplotlib's scatter function.
|
|
174
|
+
**kwargs : dict
|
|
175
|
+
Additional keyword arguments to pass to matplotlib's scatter function.
|
|
176
|
+
|
|
177
|
+
Returns
|
|
178
|
+
-------
|
|
179
|
+
None
|
|
180
|
+
This function displays the plot but does not return any value.
|
|
181
|
+
|
|
182
|
+
Notes
|
|
183
|
+
-----
|
|
184
|
+
The Bland-Altman plot is used to assess the agreement between two different
|
|
185
|
+
measurement methods. The mean difference (MD) is plotted on the y-axis, and
|
|
186
|
+
the mean of the two measurements is plotted on the x-axis. The horizontal
|
|
187
|
+
lines represent:
|
|
188
|
+
- Mean difference (MD)
|
|
189
|
+
- Mean difference ± 2 standard deviations (±2SD)
|
|
190
|
+
|
|
191
|
+
Examples
|
|
192
|
+
--------
|
|
193
|
+
>>> import numpy as np
|
|
194
|
+
>>> import matplotlib.pyplot as plt
|
|
195
|
+
>>> data1 = np.array([1, 2, 3, 4, 5])
|
|
196
|
+
>>> data2 = np.array([1.1, 2.2, 2.8, 4.1, 4.9])
|
|
197
|
+
>>> bland_altman_plot(data1, data2)
|
|
198
|
+
>>> plt.show()
|
|
199
|
+
|
|
200
|
+
>>> # Using custom scatter plot properties
|
|
201
|
+
>>> bland_altman_plot(data1, data2, c='red', alpha=0.7)
|
|
202
|
+
>>> plt.show()
|
|
203
|
+
"""
|
|
103
204
|
# data1 is X, data2 is Y
|
|
104
205
|
data1 = np.asarray(data1)
|
|
105
206
|
data2 = np.asarray(data2)
|
|
@@ -117,7 +218,47 @@ def bland_altman_plot(data1, data2, usex=False, *args, **kwargs):
|
|
|
117
218
|
plt.axhline(md - 2 * sd, color="gray", linestyle="--")
|
|
118
219
|
|
|
119
220
|
|
|
120
|
-
def pairdata(input1_data, input2_data, totalmask):
|
|
221
|
+
def pairdata(input1_data: Any, input2_data: Any, totalmask: Any) -> None:
|
|
222
|
+
"""
|
|
223
|
+
Pair corresponding elements from two 3D arrays based on a mask.
|
|
224
|
+
|
|
225
|
+
This function extracts elements from two 3D input arrays where the mask
|
|
226
|
+
has non-zero values, creating pairs of corresponding elements.
|
|
227
|
+
|
|
228
|
+
Parameters
|
|
229
|
+
----------
|
|
230
|
+
input1_data : array-like
|
|
231
|
+
First 3D array from which elements will be extracted.
|
|
232
|
+
input2_data : array-like
|
|
233
|
+
Second 3D array from which elements will be extracted.
|
|
234
|
+
totalmask : array-like
|
|
235
|
+
3D mask array where non-zero values indicate positions to pair.
|
|
236
|
+
|
|
237
|
+
Returns
|
|
238
|
+
-------
|
|
239
|
+
numpy.ndarray
|
|
240
|
+
2D array where each row contains a pair of corresponding elements
|
|
241
|
+
from input1_data and input2_data at positions where totalmask > 0.
|
|
242
|
+
|
|
243
|
+
Notes
|
|
244
|
+
-----
|
|
245
|
+
- The function assumes all input arrays have the same shape
|
|
246
|
+
- Only positions where totalmask > 0 are considered
|
|
247
|
+
- The returned array has shape (n_pairs, 2) where n_pairs is the number
|
|
248
|
+
of non-zero mask positions
|
|
249
|
+
|
|
250
|
+
Examples
|
|
251
|
+
--------
|
|
252
|
+
>>> import numpy as np
|
|
253
|
+
>>> input1 = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
|
|
254
|
+
>>> input2 = np.array([[[9, 10], [11, 12]], [[13, 14], [15, 16]]])
|
|
255
|
+
>>> mask = np.array([[[1, 0], [0, 1]], [[1, 1], [0, 0]]])
|
|
256
|
+
>>> pairdata(input1, input2, mask)
|
|
257
|
+
array([[ 1, 9],
|
|
258
|
+
[ 4, 12],
|
|
259
|
+
[ 5, 13],
|
|
260
|
+
[ 6, 14]])
|
|
261
|
+
"""
|
|
121
262
|
nonzeropoints = np.where(totalmask > 0)
|
|
122
263
|
pairlist = []
|
|
123
264
|
for i in range(0, len(nonzeropoints[0])):
|
|
@@ -131,7 +272,69 @@ def pairdata(input1_data, input2_data, totalmask):
|
|
|
131
272
|
return np.asarray(pairlist)
|
|
132
273
|
|
|
133
274
|
|
|
134
|
-
def pixelcomp(args):
|
|
275
|
+
def pixelcomp(args: Any) -> None:
|
|
276
|
+
"""
|
|
277
|
+
Compare pixel values from two input images using masks and generate statistical plots.
|
|
278
|
+
|
|
279
|
+
This function reads two NIfTI images and their corresponding masks, performs a pixel-wise
|
|
280
|
+
comparison, and generates either a scatter plot or a 2D histogram of the paired data.
|
|
281
|
+
It also fits a polynomial to the data and optionally produces a Bland-Altman plot.
|
|
282
|
+
|
|
283
|
+
Parameters
|
|
284
|
+
----------
|
|
285
|
+
args : Any
|
|
286
|
+
An object containing the following attributes:
|
|
287
|
+
- inputfilename1 : str
|
|
288
|
+
Path to the first input NIfTI image file.
|
|
289
|
+
- maskfilename1 : str
|
|
290
|
+
Path to the first mask NIfTI file.
|
|
291
|
+
- inputfilename2 : str
|
|
292
|
+
Path to the second input NIfTI image file.
|
|
293
|
+
- maskfilename2 : str
|
|
294
|
+
Path to the second mask NIfTI file.
|
|
295
|
+
- outputroot : str
|
|
296
|
+
Root name for output files.
|
|
297
|
+
- histbins : int
|
|
298
|
+
Number of bins for the 2D histogram.
|
|
299
|
+
- fitorder : int
|
|
300
|
+
Order of the polynomial to fit.
|
|
301
|
+
- display : bool
|
|
302
|
+
If True, display plots; otherwise, save them to files.
|
|
303
|
+
- scatter : bool
|
|
304
|
+
If True, generate a scatter plot; otherwise, generate a contour plot.
|
|
305
|
+
- fitonly : bool
|
|
306
|
+
If True, only perform the polynomial fit and save coefficients.
|
|
307
|
+
|
|
308
|
+
Returns
|
|
309
|
+
-------
|
|
310
|
+
None
|
|
311
|
+
This function does not return any value. It saves plots and data to files.
|
|
312
|
+
|
|
313
|
+
Notes
|
|
314
|
+
-----
|
|
315
|
+
- The function requires both input images and masks to have matching spatial dimensions.
|
|
316
|
+
- The output includes:
|
|
317
|
+
* A scatter or contour plot saved as PNG.
|
|
318
|
+
* A file with polynomial coefficients.
|
|
319
|
+
* Optionally, a Bland-Altman plot saved as PNG.
|
|
320
|
+
- If a RankWarning occurs during polynomial fitting, the coefficients are set to [0.0, 0.0].
|
|
321
|
+
|
|
322
|
+
Examples
|
|
323
|
+
--------
|
|
324
|
+
>>> class Args:
|
|
325
|
+
... inputfilename1 = "image1.nii.gz"
|
|
326
|
+
... maskfilename1 = "mask1.nii.gz"
|
|
327
|
+
... inputfilename2 = "image2.nii.gz"
|
|
328
|
+
... maskfilename2 = "mask2.nii.gz"
|
|
329
|
+
... outputroot = "output"
|
|
330
|
+
... histbins = 50
|
|
331
|
+
... fitorder = 1
|
|
332
|
+
... display = False
|
|
333
|
+
... scatter = False
|
|
334
|
+
... fitonly = False
|
|
335
|
+
>>> args = Args()
|
|
336
|
+
>>> pixelcomp(args)
|
|
337
|
+
"""
|
|
135
338
|
if args.display:
|
|
136
339
|
mpl.use("TkAgg")
|
|
137
340
|
|
|
@@ -18,17 +18,39 @@
|
|
|
18
18
|
#
|
|
19
19
|
import argparse
|
|
20
20
|
import sys
|
|
21
|
+
from argparse import Namespace
|
|
22
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
|
21
23
|
|
|
22
24
|
import numpy as np
|
|
25
|
+
from numpy.typing import NDArray
|
|
23
26
|
from scipy.stats import skew
|
|
24
27
|
|
|
25
28
|
import rapidtide.io as tide_io
|
|
26
29
|
import rapidtide.workflows.parser_funcs as pf
|
|
27
30
|
|
|
28
31
|
|
|
29
|
-
def _get_parser():
|
|
32
|
+
def _get_parser() -> Any:
|
|
30
33
|
"""
|
|
31
|
-
Argument parser for plethquality
|
|
34
|
+
Argument parser for plethquality.
|
|
35
|
+
|
|
36
|
+
This function creates and configures an argument parser for the plethquality
|
|
37
|
+
command-line tool that calculates quality metrics from cardiac text files.
|
|
38
|
+
|
|
39
|
+
Returns
|
|
40
|
+
-------
|
|
41
|
+
argparse.ArgumentParser
|
|
42
|
+
Configured argument parser object with all required and optional
|
|
43
|
+
arguments for plethquality functionality.
|
|
44
|
+
|
|
45
|
+
Notes
|
|
46
|
+
-----
|
|
47
|
+
The parser includes both required and optional arguments for processing
|
|
48
|
+
cardiac text files and generating quality metrics.
|
|
49
|
+
|
|
50
|
+
Examples
|
|
51
|
+
--------
|
|
52
|
+
>>> parser = _get_parser()
|
|
53
|
+
>>> args = parser.parse_args(['input.txt', 'output.txt'])
|
|
32
54
|
"""
|
|
33
55
|
parser = argparse.ArgumentParser(
|
|
34
56
|
prog="plethquality",
|
|
@@ -57,32 +79,50 @@ def _get_parser():
|
|
|
57
79
|
return parser
|
|
58
80
|
|
|
59
81
|
|
|
60
|
-
def plethquality(waveform, Fs, S_windowsecs=5.0, debug=False):
|
|
82
|
+
def plethquality(waveform: Any, Fs: Any, S_windowsecs: float = 5.0, debug: bool = False) -> None:
|
|
61
83
|
"""
|
|
84
|
+
Calculate the windowed skewness quality metrics for a photoplethysmogram (PPG) signal.
|
|
85
|
+
|
|
86
|
+
This function computes the signal quality index based on the skewness of the PPG waveform
|
|
87
|
+
over a sliding window, as described in Elgendi, M. "Optimal Signal Quality Index for
|
|
88
|
+
Photoplethysmogram Signals". Bioengineering 2016, Vol. 3, Page 21 (2016).
|
|
62
89
|
|
|
63
90
|
Parameters
|
|
64
91
|
----------
|
|
65
|
-
waveform: array-like
|
|
66
|
-
The cardiac waveform to be assessed
|
|
67
|
-
Fs: float
|
|
68
|
-
The sample rate of the data
|
|
69
|
-
S_windowsecs: float
|
|
70
|
-
Window duration in seconds.
|
|
71
|
-
debug:
|
|
72
|
-
Turn on extended output
|
|
92
|
+
waveform : array-like
|
|
93
|
+
The cardiac waveform to be assessed.
|
|
94
|
+
Fs : float
|
|
95
|
+
The sample rate of the data in Hz.
|
|
96
|
+
S_windowsecs : float, optional
|
|
97
|
+
Window duration in seconds. Defaults to 5.0.
|
|
98
|
+
debug : bool, optional
|
|
99
|
+
Turn on extended output for debugging purposes. Defaults to False.
|
|
73
100
|
|
|
74
101
|
Returns
|
|
75
102
|
-------
|
|
76
|
-
S_sqi_mean: float
|
|
77
|
-
The mean value of the quality index over all time
|
|
78
|
-
|
|
79
|
-
The standard deviation of the quality index over all time
|
|
80
|
-
S_waveform: array
|
|
81
|
-
The quality metric over all timepoints
|
|
82
|
-
|
|
103
|
+
S_sqi_mean : float
|
|
104
|
+
The mean value of the quality index over all time.
|
|
105
|
+
S_sqi_std : float
|
|
106
|
+
The standard deviation of the quality index over all time.
|
|
107
|
+
S_waveform : array
|
|
108
|
+
The quality metric computed over all timepoints.
|
|
109
|
+
|
|
110
|
+
Notes
|
|
111
|
+
-----
|
|
112
|
+
The window size is rounded to the nearest odd number of samples to ensure symmetric
|
|
113
|
+
sliding windows around each point. The skewness is calculated using `scipy.stats.skew`
|
|
114
|
+
with `nan_policy="omit"` to ignore NaN values.
|
|
115
|
+
|
|
116
|
+
Examples
|
|
117
|
+
--------
|
|
118
|
+
>>> import numpy as np
|
|
119
|
+
>>> from scipy.stats import skew
|
|
120
|
+
>>> waveform = np.random.randn(1000)
|
|
121
|
+
>>> Fs = 100.0
|
|
122
|
+
>>> mean_sqi, std_sqi, sqi_waveform = plethquality(waveform, Fs)
|
|
123
|
+
>>> print(f"Mean SQI: {mean_sqi:.3f}")
|
|
124
|
+
Mean SQI: 0.000
|
|
83
125
|
|
|
84
|
-
Calculates the windowed skewness quality metrics described in Elgendi, M. "Optimal Signal Quality Index for
|
|
85
|
-
Photoplethysmogram Signals". Bioengineering 2016, Vol. 3, Page 21 3, 21 (2016).
|
|
86
126
|
"""
|
|
87
127
|
# calculate S_sqi over a sliding window. Window size should be an odd number of points.
|
|
88
128
|
S_windowpts = int(np.round(S_windowsecs * Fs, 0))
|
|
@@ -103,7 +143,49 @@ def plethquality(waveform, Fs, S_windowsecs=5.0, debug=False):
|
|
|
103
143
|
return S_sqi_mean, S_sqi_std, S_waveform
|
|
104
144
|
|
|
105
145
|
|
|
106
|
-
def plethquality(args):
|
|
146
|
+
def plethquality(args: Any) -> None:
|
|
147
|
+
"""
|
|
148
|
+
Calculate plethysmography quality score and optionally display results.
|
|
149
|
+
|
|
150
|
+
This function reads plethysmography data from a text file, calculates a quality
|
|
151
|
+
score based on the signal characteristics, and writes the quality scores to an
|
|
152
|
+
output file. Optionally displays the quality score plot.
|
|
153
|
+
|
|
154
|
+
Parameters
|
|
155
|
+
----------
|
|
156
|
+
args : Any
|
|
157
|
+
An object containing command line arguments with the following attributes:
|
|
158
|
+
- infilename : str
|
|
159
|
+
Input filename containing plethysmography data
|
|
160
|
+
- outfilename : str
|
|
161
|
+
Output filename for quality scores
|
|
162
|
+
- samplerate : float, optional
|
|
163
|
+
Sampling rate of the data (if not specified, will be read from file)
|
|
164
|
+
- display : bool
|
|
165
|
+
Whether to display the quality score plot
|
|
166
|
+
|
|
167
|
+
Returns
|
|
168
|
+
-------
|
|
169
|
+
None
|
|
170
|
+
This function does not return a value but writes results to files and
|
|
171
|
+
optionally displays plots.
|
|
172
|
+
|
|
173
|
+
Notes
|
|
174
|
+
-----
|
|
175
|
+
The function uses `tide_io.readvectorsfromtextfile` to read data and
|
|
176
|
+
`tide_io.writevec` to write quality scores. Quality scores are calculated
|
|
177
|
+
using an internal `plethquality` function that analyzes signal characteristics.
|
|
178
|
+
|
|
179
|
+
Examples
|
|
180
|
+
--------
|
|
181
|
+
>>> args = argparse.Namespace(
|
|
182
|
+
... infilename='pleth_data.txt',
|
|
183
|
+
... outfilename='quality_scores.txt',
|
|
184
|
+
... samplerate=100.0,
|
|
185
|
+
... display=True
|
|
186
|
+
... )
|
|
187
|
+
>>> plethquality(args)
|
|
188
|
+
"""
|
|
107
189
|
if args.display:
|
|
108
190
|
import matplotlib as mpl
|
|
109
191
|
|