junifer 0.0.5.dev183__py3-none-any.whl → 0.0.5.dev208__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.
- junifer/_version.py +2 -2
- junifer/datagrabber/tests/test_datalad_base.py +4 -4
- junifer/datagrabber/tests/test_pattern_datalad.py +4 -4
- junifer/markers/base.py +49 -23
- junifer/markers/brainprint.py +56 -265
- junifer/markers/complexity/complexity_base.py +23 -43
- junifer/markers/complexity/tests/test_hurst_exponent.py +4 -3
- junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +4 -3
- junifer/markers/complexity/tests/test_perm_entropy.py +4 -3
- junifer/markers/complexity/tests/test_range_entropy.py +4 -3
- junifer/markers/complexity/tests/test_range_entropy_auc.py +4 -3
- junifer/markers/complexity/tests/test_sample_entropy.py +4 -3
- junifer/markers/complexity/tests/test_weighted_perm_entropy.py +4 -3
- junifer/markers/ets_rss.py +24 -42
- junifer/markers/falff/falff_base.py +17 -46
- junifer/markers/falff/falff_parcels.py +53 -27
- junifer/markers/falff/falff_spheres.py +57 -29
- junifer/markers/falff/tests/test_falff_parcels.py +39 -23
- junifer/markers/falff/tests/test_falff_spheres.py +39 -23
- junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +36 -48
- junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +16 -10
- junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +13 -9
- junifer/markers/functional_connectivity/functional_connectivity_base.py +26 -40
- junifer/markers/functional_connectivity/functional_connectivity_parcels.py +6 -6
- junifer/markers/functional_connectivity/functional_connectivity_spheres.py +6 -6
- junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +8 -4
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +6 -3
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +6 -3
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +6 -3
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +10 -5
- junifer/markers/parcel_aggregation.py +40 -59
- junifer/markers/reho/reho_base.py +6 -27
- junifer/markers/reho/reho_parcels.py +23 -15
- junifer/markers/reho/reho_spheres.py +22 -16
- junifer/markers/reho/tests/test_reho_parcels.py +8 -3
- junifer/markers/reho/tests/test_reho_spheres.py +8 -3
- junifer/markers/sphere_aggregation.py +40 -59
- junifer/markers/temporal_snr/temporal_snr_base.py +20 -32
- junifer/markers/temporal_snr/temporal_snr_parcels.py +6 -6
- junifer/markers/temporal_snr/temporal_snr_spheres.py +6 -6
- junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +6 -3
- junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +6 -3
- junifer/markers/tests/test_brainprint.py +23 -12
- junifer/markers/tests/test_collection.py +9 -8
- junifer/markers/tests/test_ets_rss.py +15 -9
- junifer/markers/tests/test_markers_base.py +17 -18
- junifer/markers/tests/test_parcel_aggregation.py +93 -32
- junifer/markers/tests/test_sphere_aggregation.py +72 -19
- junifer/pipeline/pipeline_step_mixin.py +11 -1
- junifer/pipeline/tests/test_registry.py +1 -1
- {junifer-0.0.5.dev183.dist-info → junifer-0.0.5.dev208.dist-info}/METADATA +1 -1
- {junifer-0.0.5.dev183.dist-info → junifer-0.0.5.dev208.dist-info}/RECORD +57 -57
- {junifer-0.0.5.dev183.dist-info → junifer-0.0.5.dev208.dist-info}/WHEEL +1 -1
- {junifer-0.0.5.dev183.dist-info → junifer-0.0.5.dev208.dist-info}/AUTHORS.rst +0 -0
- {junifer-0.0.5.dev183.dist-info → junifer-0.0.5.dev208.dist-info}/LICENSE.md +0 -0
- {junifer-0.0.5.dev183.dist-info → junifer-0.0.5.dev208.dist-info}/entry_points.txt +0 -0
- {junifer-0.0.5.dev183.dist-info → junifer-0.0.5.dev208.dist-info}/top_level.txt +0 -0
@@ -39,13 +39,14 @@ def test_compute() -> None:
|
|
39
39
|
# Compute the marker
|
40
40
|
feature_map = marker.fit_transform(element_data)
|
41
41
|
# Assert the dimension of timeseries
|
42
|
-
assert feature_map["BOLD"]["data"].ndim == 2
|
42
|
+
assert feature_map["BOLD"]["complexity"]["data"].ndim == 2
|
43
43
|
|
44
44
|
|
45
45
|
def test_get_output_type() -> None:
|
46
46
|
"""Test MultiscaleEntropyAUC get_output_type()."""
|
47
|
-
|
48
|
-
|
47
|
+
assert "vector" == MultiscaleEntropyAUC(
|
48
|
+
parcellation=PARCELLATION
|
49
|
+
).get_output_type(input_type="BOLD", output_feature="complexity")
|
49
50
|
|
50
51
|
|
51
52
|
@pytest.mark.skipif(
|
@@ -39,13 +39,14 @@ def test_compute() -> None:
|
|
39
39
|
# Compute the marker
|
40
40
|
feature_map = marker.fit_transform(element_data)
|
41
41
|
# Assert the dimension of timeseries
|
42
|
-
assert feature_map["BOLD"]["data"].ndim == 2
|
42
|
+
assert feature_map["BOLD"]["complexity"]["data"].ndim == 2
|
43
43
|
|
44
44
|
|
45
45
|
def test_get_output_type() -> None:
|
46
46
|
"""Test PermEntropy get_output_type()."""
|
47
|
-
|
48
|
-
|
47
|
+
assert "vector" == PermEntropy(parcellation=PARCELLATION).get_output_type(
|
48
|
+
input_type="BOLD", output_feature="complexity"
|
49
|
+
)
|
49
50
|
|
50
51
|
|
51
52
|
@pytest.mark.skipif(
|
@@ -40,13 +40,14 @@ def test_compute() -> None:
|
|
40
40
|
# Compute the marker
|
41
41
|
feature_map = marker.fit_transform(element_data)
|
42
42
|
# Assert the dimension of timeseries
|
43
|
-
assert feature_map["BOLD"]["data"].ndim == 2
|
43
|
+
assert feature_map["BOLD"]["complexity"]["data"].ndim == 2
|
44
44
|
|
45
45
|
|
46
46
|
def test_get_output_type() -> None:
|
47
47
|
"""Test RangeEntropy get_output_type()."""
|
48
|
-
|
49
|
-
|
48
|
+
assert "vector" == RangeEntropy(parcellation=PARCELLATION).get_output_type(
|
49
|
+
input_type="BOLD", output_feature="complexity"
|
50
|
+
)
|
50
51
|
|
51
52
|
|
52
53
|
@pytest.mark.skipif(
|
@@ -40,13 +40,14 @@ def test_compute() -> None:
|
|
40
40
|
# Compute the marker
|
41
41
|
feature_map = marker.fit_transform(element_data)
|
42
42
|
# Assert the dimension of timeseries
|
43
|
-
assert feature_map["BOLD"]["data"].ndim == 2
|
43
|
+
assert feature_map["BOLD"]["complexity"]["data"].ndim == 2
|
44
44
|
|
45
45
|
|
46
46
|
def test_get_output_type() -> None:
|
47
47
|
"""Test RangeEntropyAUC get_output_type()."""
|
48
|
-
|
49
|
-
|
48
|
+
assert "vector" == RangeEntropyAUC(
|
49
|
+
parcellation=PARCELLATION
|
50
|
+
).get_output_type(input_type="BOLD", output_feature="complexity")
|
50
51
|
|
51
52
|
|
52
53
|
@pytest.mark.skipif(
|
@@ -39,13 +39,14 @@ def test_compute() -> None:
|
|
39
39
|
# Compute the marker
|
40
40
|
feature_map = marker.fit_transform(element_data)
|
41
41
|
# Assert the dimension of timeseries
|
42
|
-
assert feature_map["BOLD"]["data"].ndim == 2
|
42
|
+
assert feature_map["BOLD"]["complexity"]["data"].ndim == 2
|
43
43
|
|
44
44
|
|
45
45
|
def test_get_output_type() -> None:
|
46
46
|
"""Test SampleEntropy get_output_type()."""
|
47
|
-
|
48
|
-
|
47
|
+
assert "vector" == SampleEntropy(
|
48
|
+
parcellation=PARCELLATION
|
49
|
+
).get_output_type(input_type="BOLD", output_feature="complexity")
|
49
50
|
|
50
51
|
|
51
52
|
@pytest.mark.skipif(
|
@@ -39,13 +39,14 @@ def test_compute() -> None:
|
|
39
39
|
# Compute the marker
|
40
40
|
feature_map = marker.fit_transform(element_data)
|
41
41
|
# Assert the dimension of timeseries
|
42
|
-
assert feature_map["BOLD"]["data"].ndim == 2
|
42
|
+
assert feature_map["BOLD"]["complexity"]["data"].ndim == 2
|
43
43
|
|
44
44
|
|
45
45
|
def test_get_output_type() -> None:
|
46
46
|
"""Test WeightedPermEntropy get_output_type()."""
|
47
|
-
|
48
|
-
|
47
|
+
assert "vector" == WeightedPermEntropy(
|
48
|
+
parcellation=PARCELLATION
|
49
|
+
).get_output_type(input_type="BOLD", output_feature="complexity")
|
49
50
|
|
50
51
|
|
51
52
|
@pytest.mark.skipif(
|
junifer/markers/ets_rss.py
CHANGED
@@ -47,6 +47,12 @@ class RSSETSMarker(BaseMarker):
|
|
47
47
|
|
48
48
|
_DEPENDENCIES: ClassVar[Set[str]] = {"nilearn"}
|
49
49
|
|
50
|
+
_MARKER_INOUT_MAPPINGS: ClassVar[Dict[str, Dict[str, str]]] = {
|
51
|
+
"BOLD": {
|
52
|
+
"rss_ets": "timeseries",
|
53
|
+
},
|
54
|
+
}
|
55
|
+
|
50
56
|
def __init__(
|
51
57
|
self,
|
52
58
|
parcellation: Union[str, List[str]],
|
@@ -61,33 +67,6 @@ class RSSETSMarker(BaseMarker):
|
|
61
67
|
self.masks = masks
|
62
68
|
super().__init__(name=name)
|
63
69
|
|
64
|
-
def get_valid_inputs(self) -> List[str]:
|
65
|
-
"""Get valid data types for input.
|
66
|
-
|
67
|
-
Returns
|
68
|
-
-------
|
69
|
-
list of str
|
70
|
-
The list of data types that can be used as input for this marker.
|
71
|
-
|
72
|
-
"""
|
73
|
-
return ["BOLD"]
|
74
|
-
|
75
|
-
def get_output_type(self, input_type: str) -> str:
|
76
|
-
"""Get output type.
|
77
|
-
|
78
|
-
Parameters
|
79
|
-
----------
|
80
|
-
input_type : str
|
81
|
-
The data type input to the marker.
|
82
|
-
|
83
|
-
Returns
|
84
|
-
-------
|
85
|
-
str
|
86
|
-
The storage type output by the marker.
|
87
|
-
|
88
|
-
"""
|
89
|
-
return "timeseries"
|
90
|
-
|
91
70
|
def compute(
|
92
71
|
self,
|
93
72
|
input: Dict[str, Any],
|
@@ -109,8 +88,9 @@ class RSSETSMarker(BaseMarker):
|
|
109
88
|
Returns
|
110
89
|
-------
|
111
90
|
dict
|
112
|
-
The computed result as dictionary.
|
113
|
-
|
91
|
+
The computed result as dictionary. This will be either returned
|
92
|
+
to the user or stored in the storage by calling the store method
|
93
|
+
with this as a parameter. The dictionary has the following keys:
|
114
94
|
|
115
95
|
* ``data`` : the actual computed values as a numpy.ndarray
|
116
96
|
* ``col_names`` : the column labels for the computed values as list
|
@@ -124,20 +104,22 @@ class RSSETSMarker(BaseMarker):
|
|
124
104
|
|
125
105
|
"""
|
126
106
|
logger.debug("Calculating root sum of squares of edgewise timeseries.")
|
127
|
-
#
|
128
|
-
|
107
|
+
# Perform aggregation
|
108
|
+
aggregation = ParcelAggregation(
|
129
109
|
parcellation=self.parcellation,
|
130
110
|
method=self.agg_method,
|
131
111
|
method_params=self.agg_method_params,
|
132
112
|
masks=self.masks,
|
133
|
-
)
|
134
|
-
# Compute
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
113
|
+
).compute(input=input, extra_input=extra_input)
|
114
|
+
# Compute edgewise timeseries
|
115
|
+
edge_ts, _ = _ets(aggregation["aggregation"]["data"])
|
116
|
+
# Compute the RSS of edgewise timeseries
|
117
|
+
rss = np.sum(edge_ts**2, 1) ** 0.5
|
118
|
+
|
119
|
+
return {
|
120
|
+
"rss_ets": {
|
121
|
+
# Make it 2D
|
122
|
+
"data": rss[:, np.newaxis],
|
123
|
+
"col_names": ["root_sum_of_squares_ets"],
|
124
|
+
}
|
125
|
+
}
|
@@ -37,8 +37,6 @@ class ALFFBase(BaseMarker):
|
|
37
37
|
|
38
38
|
Parameters
|
39
39
|
----------
|
40
|
-
fractional : bool
|
41
|
-
Whether to compute fractional ALFF.
|
42
40
|
highpass : positive float
|
43
41
|
Highpass cutoff frequency.
|
44
42
|
lowpass : positive float
|
@@ -85,9 +83,15 @@ class ALFFBase(BaseMarker):
|
|
85
83
|
},
|
86
84
|
]
|
87
85
|
|
86
|
+
_MARKER_INOUT_MAPPINGS: ClassVar[Dict[str, Dict[str, str]]] = {
|
87
|
+
"BOLD": {
|
88
|
+
"alff": "vector",
|
89
|
+
"falff": "vector",
|
90
|
+
},
|
91
|
+
}
|
92
|
+
|
88
93
|
def __init__(
|
89
94
|
self,
|
90
|
-
fractional: bool,
|
91
95
|
highpass: float,
|
92
96
|
lowpass: float,
|
93
97
|
using: str,
|
@@ -110,45 +114,12 @@ class ALFFBase(BaseMarker):
|
|
110
114
|
)
|
111
115
|
self.using = using
|
112
116
|
self.tr = tr
|
113
|
-
self.fractional = fractional
|
114
|
-
|
115
|
-
# Create a name based on the class name if none is provided
|
116
|
-
if name is None:
|
117
|
-
suffix = "_fractional" if fractional else ""
|
118
|
-
name = f"{self.__class__.__name__}{suffix}"
|
119
117
|
super().__init__(on="BOLD", name=name)
|
120
118
|
|
121
|
-
def get_valid_inputs(self) -> List[str]:
|
122
|
-
"""Get valid data types for input.
|
123
|
-
|
124
|
-
Returns
|
125
|
-
-------
|
126
|
-
list of str
|
127
|
-
The list of data types that can be used as input for this marker.
|
128
|
-
|
129
|
-
"""
|
130
|
-
return ["BOLD"]
|
131
|
-
|
132
|
-
def get_output_type(self, input_type: str) -> str:
|
133
|
-
"""Get output type.
|
134
|
-
|
135
|
-
Parameters
|
136
|
-
----------
|
137
|
-
input_type : str
|
138
|
-
The data type input to the marker.
|
139
|
-
|
140
|
-
Returns
|
141
|
-
-------
|
142
|
-
str
|
143
|
-
The storage type output by the marker.
|
144
|
-
|
145
|
-
"""
|
146
|
-
return "vector"
|
147
|
-
|
148
119
|
def _compute(
|
149
120
|
self,
|
150
121
|
input_data: Dict[str, Any],
|
151
|
-
) -> Tuple["Nifti1Image", Path]:
|
122
|
+
) -> Tuple["Nifti1Image", "Nifti1Image", Path, Path]:
|
152
123
|
"""Compute ALFF and fALFF.
|
153
124
|
|
154
125
|
Parameters
|
@@ -161,9 +132,13 @@ class ALFFBase(BaseMarker):
|
|
161
132
|
Returns
|
162
133
|
-------
|
163
134
|
Niimg-like object
|
164
|
-
The ALFF
|
135
|
+
The ALFF as NIfTI.
|
136
|
+
Niimg-like object
|
137
|
+
The fALFF as NIfTI.
|
138
|
+
pathlib.Path
|
139
|
+
The path to the ALFF as NIfTI.
|
165
140
|
pathlib.Path
|
166
|
-
The path to the
|
141
|
+
The path to the fALFF as NIfTI.
|
167
142
|
|
168
143
|
"""
|
169
144
|
logger.debug("Calculating ALFF and fALFF")
|
@@ -186,11 +161,7 @@ class ALFFBase(BaseMarker):
|
|
186
161
|
# parcellation / coordinates to native space, else the
|
187
162
|
# path should be passed for use later if required.
|
188
163
|
# TODO(synchon): will be taken care in #292
|
189
|
-
if input_data["space"] == "native"
|
190
|
-
return falff, input_data["path"]
|
191
|
-
elif input_data["space"] == "native" and not self.fractional:
|
192
|
-
return alff, input_data["path"]
|
193
|
-
elif input_data["space"] != "native" and self.fractional:
|
194
|
-
return falff, falff_path
|
164
|
+
if input_data["space"] == "native":
|
165
|
+
return alff, falff, input_data["path"], input_data["path"]
|
195
166
|
else:
|
196
|
-
return alff, alff_path
|
167
|
+
return alff, falff, alff_path, falff_path
|
@@ -26,8 +26,6 @@ class ALFFParcels(ALFFBase):
|
|
26
26
|
parcellation : str or list of str
|
27
27
|
The name(s) of the parcellation(s). Check valid options by calling
|
28
28
|
:func:`.list_parcellations`.
|
29
|
-
fractional : bool
|
30
|
-
Whether to compute fractional ALFF.
|
31
29
|
using : {"junifer", "afni"}
|
32
30
|
Implementation to use for computing ALFF:
|
33
31
|
|
@@ -73,7 +71,6 @@ class ALFFParcels(ALFFBase):
|
|
73
71
|
def __init__(
|
74
72
|
self,
|
75
73
|
parcellation: Union[str, List[str]],
|
76
|
-
fractional: bool,
|
77
74
|
using: str,
|
78
75
|
highpass: float = 0.01,
|
79
76
|
lowpass: float = 0.1,
|
@@ -85,7 +82,6 @@ class ALFFParcels(ALFFBase):
|
|
85
82
|
) -> None:
|
86
83
|
# Superclass init first to validate `using` parameter
|
87
84
|
super().__init__(
|
88
|
-
fractional=fractional,
|
89
85
|
highpass=highpass,
|
90
86
|
lowpass=lowpass,
|
91
87
|
using=using,
|
@@ -114,33 +110,63 @@ class ALFFParcels(ALFFBase):
|
|
114
110
|
Returns
|
115
111
|
-------
|
116
112
|
dict
|
117
|
-
The computed result as dictionary.
|
118
|
-
|
113
|
+
The computed result as dictionary. This will be either returned
|
114
|
+
to the user or stored in the storage by calling the store method
|
115
|
+
with this as a parameter. The dictionary has the following keys:
|
119
116
|
|
120
|
-
* ``
|
121
|
-
|
117
|
+
* ``alff`` : dictionary with the following keys:
|
118
|
+
|
119
|
+
- ``data`` : ROI values as ``numpy.ndarray``
|
120
|
+
- ``col_names`` : ROI labels as list of str
|
121
|
+
|
122
|
+
* ``falff`` : dictionary with the following keys:
|
123
|
+
|
124
|
+
- ``data`` : ROI values as ``numpy.ndarray``
|
125
|
+
- ``col_names`` : ROI labels as list of str
|
122
126
|
|
123
127
|
"""
|
124
128
|
logger.info("Calculating ALFF / fALFF for parcels")
|
125
129
|
|
126
|
-
# Compute ALFF
|
127
|
-
|
128
|
-
|
129
|
-
# Initialize parcel aggregation
|
130
|
-
parcel_aggregation = ParcelAggregation(
|
131
|
-
parcellation=self.parcellation,
|
132
|
-
method=self.agg_method,
|
133
|
-
method_params=self.agg_method_params,
|
134
|
-
masks=self.masks,
|
135
|
-
on="BOLD",
|
136
|
-
)
|
137
|
-
# Perform aggregation on ALFF / fALFF
|
138
|
-
parcel_aggregation_input = dict(input.items())
|
139
|
-
parcel_aggregation_input["data"] = output_data
|
140
|
-
parcel_aggregation_input["path"] = output_file_path
|
141
|
-
output = parcel_aggregation.compute(
|
142
|
-
input=parcel_aggregation_input,
|
143
|
-
extra_input=extra_input,
|
130
|
+
# Compute ALFF + fALFF
|
131
|
+
alff_output, falff_output, alff_output_path, falff_output_path = (
|
132
|
+
self._compute(input_data=input)
|
144
133
|
)
|
145
134
|
|
146
|
-
|
135
|
+
# Perform aggregation on ALFF + fALFF
|
136
|
+
aggregation_alff_input = dict(input.items())
|
137
|
+
aggregation_falff_input = dict(input.items())
|
138
|
+
aggregation_alff_input["data"] = alff_output
|
139
|
+
aggregation_falff_input["data"] = falff_output
|
140
|
+
aggregation_alff_input["path"] = alff_output_path
|
141
|
+
aggregation_falff_input["path"] = falff_output_path
|
142
|
+
|
143
|
+
return {
|
144
|
+
"alff": {
|
145
|
+
**ParcelAggregation(
|
146
|
+
parcellation=self.parcellation,
|
147
|
+
method=self.agg_method,
|
148
|
+
method_params=self.agg_method_params,
|
149
|
+
masks=self.masks,
|
150
|
+
on="BOLD",
|
151
|
+
).compute(
|
152
|
+
input=aggregation_alff_input,
|
153
|
+
extra_input=extra_input,
|
154
|
+
)[
|
155
|
+
"aggregation"
|
156
|
+
],
|
157
|
+
},
|
158
|
+
"falff": {
|
159
|
+
**ParcelAggregation(
|
160
|
+
parcellation=self.parcellation,
|
161
|
+
method=self.agg_method,
|
162
|
+
method_params=self.agg_method_params,
|
163
|
+
masks=self.masks,
|
164
|
+
on="BOLD",
|
165
|
+
).compute(
|
166
|
+
input=aggregation_falff_input,
|
167
|
+
extra_input=extra_input,
|
168
|
+
)[
|
169
|
+
"aggregation"
|
170
|
+
],
|
171
|
+
},
|
172
|
+
}
|
@@ -26,8 +26,6 @@ class ALFFSpheres(ALFFBase):
|
|
26
26
|
coords : str
|
27
27
|
The name of the coordinates list to use. See
|
28
28
|
:func:`.list_coordinates` for options.
|
29
|
-
fractional : bool
|
30
|
-
Whether to compute fractional ALFF.
|
31
29
|
using : {"junifer", "afni"}
|
32
30
|
Implementation to use for computing ALFF:
|
33
31
|
|
@@ -80,7 +78,6 @@ class ALFFSpheres(ALFFBase):
|
|
80
78
|
def __init__(
|
81
79
|
self,
|
82
80
|
coords: str,
|
83
|
-
fractional: bool,
|
84
81
|
using: str,
|
85
82
|
radius: Optional[float] = None,
|
86
83
|
allow_overlap: bool = False,
|
@@ -94,7 +91,6 @@ class ALFFSpheres(ALFFBase):
|
|
94
91
|
) -> None:
|
95
92
|
# Superclass init first to validate `using` parameter
|
96
93
|
super().__init__(
|
97
|
-
fractional=fractional,
|
98
94
|
highpass=highpass,
|
99
95
|
lowpass=lowpass,
|
100
96
|
using=using,
|
@@ -125,35 +121,67 @@ class ALFFSpheres(ALFFBase):
|
|
125
121
|
Returns
|
126
122
|
-------
|
127
123
|
dict
|
128
|
-
The computed result as dictionary.
|
129
|
-
|
124
|
+
The computed result as dictionary. This will be either returned
|
125
|
+
to the user or stored in the storage by calling the store method
|
126
|
+
with this as a parameter. The dictionary has the following keys:
|
130
127
|
|
131
|
-
* ``
|
132
|
-
|
128
|
+
* ``alff`` : dictionary with the following keys:
|
129
|
+
|
130
|
+
- ``data`` : ROI values as ``numpy.ndarray``
|
131
|
+
- ``col_names`` : ROI labels as list of str
|
132
|
+
|
133
|
+
* ``falff`` : dictionary with the following keys:
|
134
|
+
|
135
|
+
- ``data`` : ROI values as ``numpy.ndarray``
|
136
|
+
- ``col_names`` : ROI labels as list of str
|
133
137
|
|
134
138
|
"""
|
135
139
|
logger.info("Calculating ALFF / fALFF for spheres")
|
136
140
|
|
137
|
-
# Compute ALFF
|
138
|
-
|
139
|
-
|
140
|
-
# Initialize sphere aggregation
|
141
|
-
sphere_aggregation = SphereAggregation(
|
142
|
-
coords=self.coords,
|
143
|
-
radius=self.radius,
|
144
|
-
allow_overlap=self.allow_overlap,
|
145
|
-
method=self.agg_method,
|
146
|
-
method_params=self.agg_method_params,
|
147
|
-
masks=self.masks,
|
148
|
-
on="BOLD",
|
149
|
-
)
|
150
|
-
# Perform aggregation on ALFF / fALFF
|
151
|
-
sphere_aggregation_input = dict(input.items())
|
152
|
-
sphere_aggregation_input["data"] = output_data
|
153
|
-
sphere_aggregation_input["path"] = output_file_path
|
154
|
-
output = sphere_aggregation.compute(
|
155
|
-
input=sphere_aggregation_input,
|
156
|
-
extra_input=extra_input,
|
141
|
+
# Compute ALFF + fALFF
|
142
|
+
alff_output, falff_output, alff_output_path, falff_output_path = (
|
143
|
+
self._compute(input_data=input)
|
157
144
|
)
|
158
145
|
|
159
|
-
|
146
|
+
# Perform aggregation on ALFF / fALFF
|
147
|
+
aggregation_alff_input = dict(input.items())
|
148
|
+
aggregation_falff_input = dict(input.items())
|
149
|
+
aggregation_alff_input["data"] = alff_output
|
150
|
+
aggregation_falff_input["data"] = falff_output
|
151
|
+
aggregation_alff_input["path"] = alff_output_path
|
152
|
+
aggregation_falff_input["path"] = falff_output_path
|
153
|
+
|
154
|
+
return {
|
155
|
+
"alff": {
|
156
|
+
**SphereAggregation(
|
157
|
+
coords=self.coords,
|
158
|
+
radius=self.radius,
|
159
|
+
allow_overlap=self.allow_overlap,
|
160
|
+
method=self.agg_method,
|
161
|
+
method_params=self.agg_method_params,
|
162
|
+
masks=self.masks,
|
163
|
+
on="BOLD",
|
164
|
+
).compute(
|
165
|
+
input=aggregation_alff_input,
|
166
|
+
extra_input=extra_input,
|
167
|
+
)[
|
168
|
+
"aggregation"
|
169
|
+
],
|
170
|
+
},
|
171
|
+
"falff": {
|
172
|
+
**SphereAggregation(
|
173
|
+
coords=self.coords,
|
174
|
+
radius=self.radius,
|
175
|
+
allow_overlap=self.allow_overlap,
|
176
|
+
method=self.agg_method,
|
177
|
+
method_params=self.agg_method_params,
|
178
|
+
masks=self.masks,
|
179
|
+
on="BOLD",
|
180
|
+
).compute(
|
181
|
+
input=aggregation_falff_input,
|
182
|
+
extra_input=extra_input,
|
183
|
+
)[
|
184
|
+
"aggregation"
|
185
|
+
],
|
186
|
+
},
|
187
|
+
}
|
@@ -21,6 +21,28 @@ from junifer.testing.datagrabbers import PartlyCloudyTestingDataGrabber
|
|
21
21
|
PARCELLATION = "TianxS1x3TxMNInonlinear2009cAsym"
|
22
22
|
|
23
23
|
|
24
|
+
@pytest.mark.parametrize(
|
25
|
+
"feature",
|
26
|
+
[
|
27
|
+
"alff",
|
28
|
+
"falff",
|
29
|
+
],
|
30
|
+
)
|
31
|
+
def test_ALFFParcels_get_output_type(feature: str) -> None:
|
32
|
+
"""Test ALFFParcels get_output_type().
|
33
|
+
|
34
|
+
Parameters
|
35
|
+
----------
|
36
|
+
feature : str
|
37
|
+
The parametrized feature name.
|
38
|
+
|
39
|
+
"""
|
40
|
+
assert "vector" == ALFFParcels(
|
41
|
+
parcellation=PARCELLATION,
|
42
|
+
using="junifer",
|
43
|
+
).get_output_type(input_type="BOLD", output_feature=feature)
|
44
|
+
|
45
|
+
|
24
46
|
def test_ALFFParcels(caplog: pytest.LogCaptureFixture, tmp_path: Path) -> None:
|
25
47
|
"""Test ALFFParcels.
|
26
48
|
|
@@ -41,7 +63,6 @@ def test_ALFFParcels(caplog: pytest.LogCaptureFixture, tmp_path: Path) -> None:
|
|
41
63
|
# Initialize marker
|
42
64
|
marker = ALFFParcels(
|
43
65
|
parcellation=PARCELLATION,
|
44
|
-
fractional=False,
|
45
66
|
using="junifer",
|
46
67
|
)
|
47
68
|
# Fit transform marker on data
|
@@ -51,15 +72,16 @@ def test_ALFFParcels(caplog: pytest.LogCaptureFixture, tmp_path: Path) -> None:
|
|
51
72
|
|
52
73
|
# Get BOLD output
|
53
74
|
assert "BOLD" in output
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
75
|
+
for feature in output["BOLD"].keys():
|
76
|
+
output_bold = output["BOLD"][feature]
|
77
|
+
# Assert BOLD output keys
|
78
|
+
assert "data" in output_bold
|
79
|
+
assert "col_names" in output_bold
|
58
80
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
81
|
+
output_bold_data = output_bold["data"]
|
82
|
+
# Assert BOLD output data dimension
|
83
|
+
assert output_bold_data.ndim == 2
|
84
|
+
assert output_bold_data.shape == (1, 16)
|
63
85
|
|
64
86
|
# Reset log capture
|
65
87
|
caplog.clear()
|
@@ -77,18 +99,13 @@ def test_ALFFParcels(caplog: pytest.LogCaptureFixture, tmp_path: Path) -> None:
|
|
77
99
|
@pytest.mark.skipif(
|
78
100
|
_check_afni() is False, reason="requires AFNI to be in PATH"
|
79
101
|
)
|
80
|
-
|
81
|
-
"fractional", [True, False], ids=["fractional", "non-fractional"]
|
82
|
-
)
|
83
|
-
def test_ALFFParcels_comparison(tmp_path: Path, fractional: bool) -> None:
|
102
|
+
def test_ALFFParcels_comparison(tmp_path: Path) -> None:
|
84
103
|
"""Test ALFFParcels implementation comparison.
|
85
104
|
|
86
105
|
Parameters
|
87
106
|
----------
|
88
107
|
tmp_path : pathlib.Path
|
89
108
|
The path to the test directory.
|
90
|
-
fractional : bool
|
91
|
-
Whether to compute fractional ALFF or not.
|
92
109
|
|
93
110
|
"""
|
94
111
|
with PartlyCloudyTestingDataGrabber() as dg:
|
@@ -99,7 +116,6 @@ def test_ALFFParcels_comparison(tmp_path: Path, fractional: bool) -> None:
|
|
99
116
|
# Initialize marker
|
100
117
|
junifer_marker = ALFFParcels(
|
101
118
|
parcellation=PARCELLATION,
|
102
|
-
fractional=fractional,
|
103
119
|
using="junifer",
|
104
120
|
)
|
105
121
|
# Fit transform marker on data
|
@@ -110,7 +126,6 @@ def test_ALFFParcels_comparison(tmp_path: Path, fractional: bool) -> None:
|
|
110
126
|
# Initialize marker
|
111
127
|
afni_marker = ALFFParcels(
|
112
128
|
parcellation=PARCELLATION,
|
113
|
-
fractional=fractional,
|
114
129
|
using="afni",
|
115
130
|
)
|
116
131
|
# Fit transform marker on data
|
@@ -118,9 +133,10 @@ def test_ALFFParcels_comparison(tmp_path: Path, fractional: bool) -> None:
|
|
118
133
|
# Get BOLD output
|
119
134
|
afni_output_bold = afni_output["BOLD"]
|
120
135
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
136
|
+
for feature in afni_output_bold.keys():
|
137
|
+
# Check for Pearson correlation coefficient
|
138
|
+
r, _ = sp.stats.pearsonr(
|
139
|
+
junifer_output_bold[feature]["data"][0],
|
140
|
+
afni_output_bold[feature]["data"][0],
|
141
|
+
)
|
142
|
+
assert r > 0.97
|