junifer 0.0.3.dev186__py3-none-any.whl → 0.0.4__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 +14 -2
- junifer/api/cli.py +162 -17
- junifer/api/functions.py +87 -419
- junifer/api/parser.py +24 -0
- junifer/api/queue_context/__init__.py +8 -0
- junifer/api/queue_context/gnu_parallel_local_adapter.py +258 -0
- junifer/api/queue_context/htcondor_adapter.py +365 -0
- junifer/api/queue_context/queue_context_adapter.py +60 -0
- junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +192 -0
- junifer/api/queue_context/tests/test_htcondor_adapter.py +257 -0
- junifer/api/res/afni/run_afni_docker.sh +6 -6
- junifer/api/res/ants/ResampleImage +3 -0
- junifer/api/res/ants/antsApplyTransforms +3 -0
- junifer/api/res/ants/antsApplyTransformsToPoints +3 -0
- junifer/api/res/ants/run_ants_docker.sh +39 -0
- junifer/api/res/fsl/applywarp +3 -0
- junifer/api/res/fsl/flirt +3 -0
- junifer/api/res/fsl/img2imgcoord +3 -0
- junifer/api/res/fsl/run_fsl_docker.sh +39 -0
- junifer/api/res/fsl/std2imgcoord +3 -0
- junifer/api/res/run_conda.sh +4 -4
- junifer/api/res/run_venv.sh +22 -0
- junifer/api/tests/data/partly_cloudy_agg_mean_tian.yml +16 -0
- junifer/api/tests/test_api_utils.py +21 -3
- junifer/api/tests/test_cli.py +232 -9
- junifer/api/tests/test_functions.py +211 -439
- junifer/api/tests/test_parser.py +1 -1
- junifer/configs/juseless/datagrabbers/aomic_id1000_vbm.py +6 -1
- junifer/configs/juseless/datagrabbers/camcan_vbm.py +6 -1
- junifer/configs/juseless/datagrabbers/ixi_vbm.py +6 -1
- junifer/configs/juseless/datagrabbers/tests/test_ucla.py +8 -8
- junifer/configs/juseless/datagrabbers/ucla.py +44 -26
- junifer/configs/juseless/datagrabbers/ukb_vbm.py +6 -1
- junifer/data/VOIs/meta/AutobiographicalMemory_VOIs.txt +23 -0
- junifer/data/VOIs/meta/Power2013_MNI_VOIs.tsv +264 -0
- junifer/data/__init__.py +4 -0
- junifer/data/coordinates.py +298 -31
- junifer/data/masks.py +360 -28
- junifer/data/parcellations.py +621 -188
- junifer/data/template_spaces.py +190 -0
- junifer/data/tests/test_coordinates.py +34 -3
- junifer/data/tests/test_data_utils.py +1 -0
- junifer/data/tests/test_masks.py +202 -86
- junifer/data/tests/test_parcellations.py +266 -55
- junifer/data/tests/test_template_spaces.py +104 -0
- junifer/data/utils.py +4 -2
- junifer/datagrabber/__init__.py +1 -0
- junifer/datagrabber/aomic/id1000.py +111 -70
- junifer/datagrabber/aomic/piop1.py +116 -53
- junifer/datagrabber/aomic/piop2.py +116 -53
- junifer/datagrabber/aomic/tests/test_id1000.py +27 -27
- junifer/datagrabber/aomic/tests/test_piop1.py +27 -27
- junifer/datagrabber/aomic/tests/test_piop2.py +27 -27
- junifer/datagrabber/base.py +62 -10
- junifer/datagrabber/datalad_base.py +0 -2
- junifer/datagrabber/dmcc13_benchmark.py +372 -0
- junifer/datagrabber/hcp1200/datalad_hcp1200.py +5 -0
- junifer/datagrabber/hcp1200/hcp1200.py +30 -13
- junifer/datagrabber/pattern.py +133 -27
- junifer/datagrabber/pattern_datalad.py +111 -13
- junifer/datagrabber/tests/test_base.py +57 -6
- junifer/datagrabber/tests/test_datagrabber_utils.py +204 -76
- junifer/datagrabber/tests/test_datalad_base.py +0 -6
- junifer/datagrabber/tests/test_dmcc13_benchmark.py +256 -0
- junifer/datagrabber/tests/test_multiple.py +43 -10
- junifer/datagrabber/tests/test_pattern.py +125 -178
- junifer/datagrabber/tests/test_pattern_datalad.py +44 -25
- junifer/datagrabber/utils.py +151 -16
- junifer/datareader/default.py +36 -10
- junifer/external/nilearn/junifer_nifti_spheres_masker.py +6 -0
- junifer/markers/base.py +25 -16
- junifer/markers/collection.py +35 -16
- junifer/markers/complexity/__init__.py +27 -0
- junifer/markers/complexity/complexity_base.py +149 -0
- junifer/markers/complexity/hurst_exponent.py +136 -0
- junifer/markers/complexity/multiscale_entropy_auc.py +140 -0
- junifer/markers/complexity/perm_entropy.py +132 -0
- junifer/markers/complexity/range_entropy.py +136 -0
- junifer/markers/complexity/range_entropy_auc.py +145 -0
- junifer/markers/complexity/sample_entropy.py +134 -0
- junifer/markers/complexity/tests/test_complexity_base.py +19 -0
- junifer/markers/complexity/tests/test_hurst_exponent.py +69 -0
- junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +68 -0
- junifer/markers/complexity/tests/test_perm_entropy.py +68 -0
- junifer/markers/complexity/tests/test_range_entropy.py +69 -0
- junifer/markers/complexity/tests/test_range_entropy_auc.py +69 -0
- junifer/markers/complexity/tests/test_sample_entropy.py +68 -0
- junifer/markers/complexity/tests/test_weighted_perm_entropy.py +68 -0
- junifer/markers/complexity/weighted_perm_entropy.py +133 -0
- junifer/markers/falff/_afni_falff.py +153 -0
- junifer/markers/falff/_junifer_falff.py +142 -0
- junifer/markers/falff/falff_base.py +91 -84
- junifer/markers/falff/falff_parcels.py +61 -45
- junifer/markers/falff/falff_spheres.py +64 -48
- junifer/markers/falff/tests/test_falff_parcels.py +89 -121
- junifer/markers/falff/tests/test_falff_spheres.py +92 -127
- junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +1 -0
- junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +1 -0
- junifer/markers/functional_connectivity/functional_connectivity_base.py +1 -0
- junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +46 -44
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +34 -39
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +40 -52
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +62 -70
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +99 -85
- junifer/markers/parcel_aggregation.py +60 -38
- junifer/markers/reho/_afni_reho.py +192 -0
- junifer/markers/reho/_junifer_reho.py +281 -0
- junifer/markers/reho/reho_base.py +69 -34
- junifer/markers/reho/reho_parcels.py +26 -16
- junifer/markers/reho/reho_spheres.py +23 -9
- junifer/markers/reho/tests/test_reho_parcels.py +93 -92
- junifer/markers/reho/tests/test_reho_spheres.py +88 -86
- junifer/markers/sphere_aggregation.py +54 -9
- junifer/markers/temporal_snr/temporal_snr_base.py +1 -0
- junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +38 -37
- junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +34 -38
- junifer/markers/tests/test_collection.py +43 -42
- junifer/markers/tests/test_ets_rss.py +29 -37
- junifer/markers/tests/test_parcel_aggregation.py +587 -468
- junifer/markers/tests/test_sphere_aggregation.py +209 -157
- junifer/markers/utils.py +2 -40
- junifer/onthefly/read_transform.py +13 -6
- junifer/pipeline/__init__.py +1 -0
- junifer/pipeline/pipeline_step_mixin.py +105 -41
- junifer/pipeline/registry.py +17 -0
- junifer/pipeline/singleton.py +45 -0
- junifer/pipeline/tests/test_pipeline_step_mixin.py +139 -51
- junifer/pipeline/tests/test_update_meta_mixin.py +1 -0
- junifer/pipeline/tests/test_workdir_manager.py +104 -0
- junifer/pipeline/update_meta_mixin.py +8 -2
- junifer/pipeline/utils.py +154 -15
- junifer/pipeline/workdir_manager.py +246 -0
- junifer/preprocess/__init__.py +3 -0
- junifer/preprocess/ants/__init__.py +4 -0
- junifer/preprocess/ants/ants_apply_transforms_warper.py +185 -0
- junifer/preprocess/ants/tests/test_ants_apply_transforms_warper.py +56 -0
- junifer/preprocess/base.py +96 -69
- junifer/preprocess/bold_warper.py +265 -0
- junifer/preprocess/confounds/fmriprep_confound_remover.py +91 -134
- junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +106 -111
- junifer/preprocess/fsl/__init__.py +4 -0
- junifer/preprocess/fsl/apply_warper.py +179 -0
- junifer/preprocess/fsl/tests/test_apply_warper.py +45 -0
- junifer/preprocess/tests/test_bold_warper.py +159 -0
- junifer/preprocess/tests/test_preprocess_base.py +6 -6
- junifer/preprocess/warping/__init__.py +6 -0
- junifer/preprocess/warping/_ants_warper.py +167 -0
- junifer/preprocess/warping/_fsl_warper.py +109 -0
- junifer/preprocess/warping/space_warper.py +213 -0
- junifer/preprocess/warping/tests/test_space_warper.py +198 -0
- junifer/stats.py +18 -4
- junifer/storage/base.py +9 -1
- junifer/storage/hdf5.py +8 -3
- junifer/storage/pandas_base.py +2 -1
- junifer/storage/sqlite.py +1 -0
- junifer/storage/tests/test_hdf5.py +2 -1
- junifer/storage/tests/test_sqlite.py +8 -8
- junifer/storage/tests/test_utils.py +6 -6
- junifer/storage/utils.py +1 -0
- junifer/testing/datagrabbers.py +11 -7
- junifer/testing/utils.py +1 -0
- junifer/tests/test_stats.py +2 -0
- junifer/utils/__init__.py +1 -0
- junifer/utils/helpers.py +53 -0
- junifer/utils/logging.py +14 -3
- junifer/utils/tests/test_helpers.py +35 -0
- {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/METADATA +59 -28
- junifer-0.0.4.dist-info/RECORD +257 -0
- {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/WHEEL +1 -1
- junifer/markers/falff/falff_estimator.py +0 -334
- junifer/markers/falff/tests/test_falff_estimator.py +0 -238
- junifer/markers/reho/reho_estimator.py +0 -515
- junifer/markers/reho/tests/test_reho_estimator.py +0 -260
- junifer-0.0.3.dev186.dist-info/RECORD +0 -199
- {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/AUTHORS.rst +0 -0
- {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/LICENSE.md +0 -0
- {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/entry_points.txt +0 -0
- {junifer-0.0.3.dev186.dist-info → junifer-0.0.4.dist-info}/top_level.txt +0 -0
@@ -4,11 +4,23 @@
|
|
4
4
|
# License: AGPL
|
5
5
|
|
6
6
|
|
7
|
-
from
|
7
|
+
from pathlib import Path
|
8
|
+
from typing import (
|
9
|
+
TYPE_CHECKING,
|
10
|
+
Any,
|
11
|
+
ClassVar,
|
12
|
+
Dict,
|
13
|
+
List,
|
14
|
+
Optional,
|
15
|
+
Tuple,
|
16
|
+
Type,
|
17
|
+
Union,
|
18
|
+
)
|
8
19
|
|
9
20
|
from ...utils import logger, raise_error
|
10
21
|
from ..base import BaseMarker
|
11
|
-
from .
|
22
|
+
from ._afni_reho import AFNIReHo
|
23
|
+
from ._junifer_reho import JuniferReHo
|
12
24
|
|
13
25
|
|
14
26
|
if TYPE_CHECKING:
|
@@ -20,32 +32,47 @@ class ReHoBase(BaseMarker):
|
|
20
32
|
|
21
33
|
Parameters
|
22
34
|
----------
|
23
|
-
|
24
|
-
|
25
|
-
|
35
|
+
using : {"junifer", "afni"}
|
36
|
+
Implementation to use for computing ReHo:
|
37
|
+
|
38
|
+
* "junifer" : Use ``junifer``'s own ReHo implementation
|
39
|
+
* "afni" : Use AFNI's ``3dReHo``
|
40
|
+
|
26
41
|
name : str, optional
|
27
42
|
The name of the marker. If None, it will use the class name
|
28
43
|
(default None).
|
29
44
|
|
45
|
+
Raises
|
46
|
+
------
|
47
|
+
ValueError
|
48
|
+
If ``using`` is invalid.
|
49
|
+
|
30
50
|
"""
|
31
51
|
|
32
|
-
|
33
|
-
List[Dict[str, Union[str, bool, List[str]]]]
|
34
|
-
] = [
|
52
|
+
_CONDITIONAL_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, Type]]]] = [
|
35
53
|
{
|
36
|
-
"
|
37
|
-
"
|
38
|
-
|
54
|
+
"using": "afni",
|
55
|
+
"depends_on": AFNIReHo,
|
56
|
+
},
|
57
|
+
{
|
58
|
+
"using": "junifer",
|
59
|
+
"depends_on": JuniferReHo,
|
39
60
|
},
|
40
61
|
]
|
41
62
|
|
42
63
|
def __init__(
|
43
64
|
self,
|
44
|
-
|
65
|
+
using: str,
|
45
66
|
name: Optional[str] = None,
|
46
67
|
) -> None:
|
68
|
+
# Validate `using` parameter
|
69
|
+
valid_using = [dep["using"] for dep in self._CONDITIONAL_DEPENDENCIES]
|
70
|
+
if using not in valid_using:
|
71
|
+
raise_error(
|
72
|
+
f"Invalid value for `using`, should be one of: {valid_using}"
|
73
|
+
)
|
74
|
+
self.using = using
|
47
75
|
super().__init__(on="BOLD", name=name)
|
48
|
-
self.use_afni = use_afni
|
49
76
|
|
50
77
|
def get_valid_inputs(self) -> List[str]:
|
51
78
|
"""Get valid data types for input.
|
@@ -74,12 +101,12 @@ class ReHoBase(BaseMarker):
|
|
74
101
|
"""
|
75
102
|
return "vector"
|
76
103
|
|
77
|
-
def
|
104
|
+
def _compute(
|
78
105
|
self,
|
79
|
-
|
106
|
+
input_data: Dict[str, Any],
|
80
107
|
**reho_params: Any,
|
81
|
-
) -> "Nifti1Image":
|
82
|
-
"""Compute.
|
108
|
+
) -> Tuple["Nifti1Image", Path]:
|
109
|
+
"""Compute voxel-wise ReHo.
|
83
110
|
|
84
111
|
Calculates Kendall's W per voxel using neighborhood voxels.
|
85
112
|
Instead of the time series values themselves, Kendall's W uses the
|
@@ -90,7 +117,7 @@ class ReHoBase(BaseMarker):
|
|
90
117
|
|
91
118
|
Parameters
|
92
119
|
----------
|
93
|
-
|
120
|
+
input_data : dict
|
94
121
|
The BOLD data as dictionary.
|
95
122
|
**reho_params : dict
|
96
123
|
Extra keyword arguments for ReHo.
|
@@ -98,6 +125,10 @@ class ReHoBase(BaseMarker):
|
|
98
125
|
Returns
|
99
126
|
-------
|
100
127
|
Niimg-like object
|
128
|
+
The ReHo map as NIfTI.
|
129
|
+
pathlib.Path
|
130
|
+
The path to the ReHo map as NIfTI or the input data path if the
|
131
|
+
input data space is "native".
|
101
132
|
|
102
133
|
References
|
103
134
|
----------
|
@@ -108,21 +139,25 @@ class ReHoBase(BaseMarker):
|
|
108
139
|
https://doi.org/10.1177/1073858415595004
|
109
140
|
|
110
141
|
"""
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
reho_estimator = ReHoEstimator()
|
122
|
-
# Fit-transform reho estimator
|
123
|
-
reho_map = reho_estimator.fit_transform(
|
124
|
-
use_afni=self.use_afni,
|
125
|
-
input_data=input,
|
142
|
+
logger.debug("Calculating voxel-wise ReHo")
|
143
|
+
|
144
|
+
# Conditional estimator
|
145
|
+
if self.using == "afni":
|
146
|
+
estimator = AFNIReHo()
|
147
|
+
elif self.using == "junifer":
|
148
|
+
estimator = JuniferReHo()
|
149
|
+
# Compute reho
|
150
|
+
reho_map, reho_map_path = estimator.compute( # type: ignore
|
151
|
+
data=input_data["data"],
|
126
152
|
**reho_params,
|
127
153
|
)
|
128
|
-
|
154
|
+
|
155
|
+
# If the input data space is native already, the original path should
|
156
|
+
# be propagated down as it might be required for transforming
|
157
|
+
# parcellation / coordinates to native space, else the reho map
|
158
|
+
# path should be passed for use later if required.
|
159
|
+
# TODO(synchon): will be taken care in #292
|
160
|
+
if input_data["space"] == "native":
|
161
|
+
return reho_map, input_data["path"]
|
162
|
+
|
163
|
+
return reho_map, reho_map_path
|
@@ -20,15 +20,18 @@ class ReHoParcels(ReHoBase):
|
|
20
20
|
|
21
21
|
Parameters
|
22
22
|
----------
|
23
|
-
parcellation : str
|
24
|
-
The name of the parcellation. Check valid options by calling
|
23
|
+
parcellation : str or list of str
|
24
|
+
The name(s) of the parcellation(s). Check valid options by calling
|
25
25
|
:func:`.list_parcellations`.
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
using : {"junifer", "afni"}
|
27
|
+
Implementation to use for computing ReHo:
|
28
|
+
|
29
|
+
* "junifer" : Use ``junifer``'s own ReHo implementation
|
30
|
+
* "afni" : Use AFNI's ``3dReHo``
|
31
|
+
|
29
32
|
reho_params : dict, optional
|
30
33
|
Extra parameters for computing ReHo map as a dictionary (default None).
|
31
|
-
If ``
|
34
|
+
If ``using="afni"``, then the valid keys are:
|
32
35
|
|
33
36
|
* ``nneigh`` : {7, 19, 27}, optional (default 27)
|
34
37
|
Number of voxels in the neighbourhood, inclusive. Can be:
|
@@ -58,7 +61,7 @@ class ReHoParcels(ReHoBase):
|
|
58
61
|
The number of voxels for +/- z-axis of cuboidal volumes
|
59
62
|
(default None).
|
60
63
|
|
61
|
-
else if ``
|
64
|
+
else if ``using="junifer"``, then the valid keys are:
|
62
65
|
|
63
66
|
* ``nneigh`` : {7, 19, 27, 125}, optional (default 27)
|
64
67
|
Number of voxels in the neighbourhood, inclusive. Can be:
|
@@ -86,20 +89,21 @@ class ReHoParcels(ReHoBase):
|
|
86
89
|
|
87
90
|
def __init__(
|
88
91
|
self,
|
89
|
-
parcellation: str,
|
90
|
-
|
92
|
+
parcellation: Union[str, List[str]],
|
93
|
+
using: str,
|
91
94
|
reho_params: Optional[Dict] = None,
|
92
95
|
agg_method: str = "mean",
|
93
96
|
agg_method_params: Optional[Dict] = None,
|
94
97
|
masks: Union[str, Dict, List[Union[Dict, str]], None] = None,
|
95
98
|
name: Optional[str] = None,
|
96
99
|
) -> None:
|
100
|
+
# Superclass init first to validate `using` parameter
|
101
|
+
super().__init__(using=using, name=name)
|
97
102
|
self.parcellation = parcellation
|
98
103
|
self.reho_params = reho_params
|
99
104
|
self.agg_method = agg_method
|
100
105
|
self.agg_method_params = agg_method_params
|
101
106
|
self.masks = masks
|
102
|
-
super().__init__(use_afni=use_afni, name=name)
|
103
107
|
|
104
108
|
def compute(
|
105
109
|
self,
|
@@ -125,12 +129,19 @@ class ReHoParcels(ReHoBase):
|
|
125
129
|
* ``col_names`` : the column labels for the parcels as a list
|
126
130
|
|
127
131
|
"""
|
128
|
-
logger.info("Calculating ReHo for parcels
|
129
|
-
|
132
|
+
logger.info("Calculating ReHo for parcels")
|
133
|
+
|
134
|
+
# Compute voxelwise reho
|
135
|
+
# If the input data space is "native", then reho_file_path points to
|
136
|
+
# the input data path as it might be required for parcellation
|
137
|
+
# transformation to native space.
|
130
138
|
if self.reho_params is not None:
|
131
|
-
reho_map = self.
|
139
|
+
reho_map, reho_file_path = self._compute(
|
140
|
+
input_data=input, **self.reho_params
|
141
|
+
)
|
132
142
|
else:
|
133
|
-
reho_map = self.
|
143
|
+
reho_map, reho_file_path = self._compute(input_data=input)
|
144
|
+
|
134
145
|
# Initialize parcel aggregation
|
135
146
|
parcel_aggregation = ParcelAggregation(
|
136
147
|
parcellation=self.parcellation,
|
@@ -142,8 +153,7 @@ class ReHoParcels(ReHoBase):
|
|
142
153
|
# Perform aggregation on reho map
|
143
154
|
parcel_aggregation_input = dict(input.items())
|
144
155
|
parcel_aggregation_input["data"] = reho_map
|
145
|
-
parcel_aggregation_input["path"] =
|
146
|
-
|
156
|
+
parcel_aggregation_input["path"] = reho_file_path
|
147
157
|
output = parcel_aggregation.compute(
|
148
158
|
input=parcel_aggregation_input,
|
149
159
|
extra_input=extra_input,
|
@@ -23,6 +23,12 @@ class ReHoSpheres(ReHoBase):
|
|
23
23
|
coords : str
|
24
24
|
The name of the coordinates list to use. See
|
25
25
|
:func:`.list_coordinates` for options.
|
26
|
+
using : {"junifer", "afni"}
|
27
|
+
Implementation to use for computing ReHo:
|
28
|
+
|
29
|
+
* "junifer" : Use ``junifer``'s own ReHo implementation
|
30
|
+
* "afni" : Use AFNI's ``3dReHo``
|
31
|
+
|
26
32
|
radius : float, optional
|
27
33
|
The radius of the sphere in millimeters. If None, the signal will be
|
28
34
|
extracted from a single voxel. See
|
@@ -36,7 +42,7 @@ class ReHoSpheres(ReHoBase):
|
|
36
42
|
if available (default None).
|
37
43
|
reho_params : dict, optional
|
38
44
|
Extra parameters for computing ReHo map as a dictionary (default None).
|
39
|
-
If ``
|
45
|
+
If ``using="afni"``, then the valid keys are:
|
40
46
|
|
41
47
|
* ``nneigh`` : {7, 19, 27}, optional (default 27)
|
42
48
|
Number of voxels in the neighbourhood, inclusive. Can be:
|
@@ -66,7 +72,7 @@ class ReHoSpheres(ReHoBase):
|
|
66
72
|
The number of voxels for +/- z-axis of cuboidal volumes
|
67
73
|
(default None).
|
68
74
|
|
69
|
-
else if ``
|
75
|
+
else if ``using="junifer"``, then the valid keys are:
|
70
76
|
|
71
77
|
* ``nneigh`` : {7, 19, 27, 125}, optional (default 27)
|
72
78
|
Number of voxels in the neighbourhood, inclusive. Can be:
|
@@ -95,15 +101,17 @@ class ReHoSpheres(ReHoBase):
|
|
95
101
|
def __init__(
|
96
102
|
self,
|
97
103
|
coords: str,
|
104
|
+
using: str,
|
98
105
|
radius: Optional[float] = None,
|
99
106
|
allow_overlap: bool = False,
|
100
|
-
use_afni: Optional[bool] = None,
|
101
107
|
reho_params: Optional[Dict] = None,
|
102
108
|
agg_method: str = "mean",
|
103
109
|
agg_method_params: Optional[Dict] = None,
|
104
110
|
masks: Union[str, Dict, List[Union[Dict, str]], None] = None,
|
105
111
|
name: Optional[str] = None,
|
106
112
|
) -> None:
|
113
|
+
# Superclass init first to validate `using` parameter
|
114
|
+
super().__init__(using=using, name=name)
|
107
115
|
self.coords = coords
|
108
116
|
self.radius = radius
|
109
117
|
self.allow_overlap = allow_overlap
|
@@ -111,7 +119,6 @@ class ReHoSpheres(ReHoBase):
|
|
111
119
|
self.agg_method = agg_method
|
112
120
|
self.agg_method_params = agg_method_params
|
113
121
|
self.masks = masks
|
114
|
-
super().__init__(use_afni=use_afni, name=name)
|
115
122
|
|
116
123
|
def compute(
|
117
124
|
self,
|
@@ -137,12 +144,19 @@ class ReHoSpheres(ReHoBase):
|
|
137
144
|
* ``col_names`` : the column labels for the spheres as a list
|
138
145
|
|
139
146
|
"""
|
140
|
-
logger.info("Calculating ReHo for spheres
|
141
|
-
|
147
|
+
logger.info("Calculating ReHo for spheres")
|
148
|
+
|
149
|
+
# Compute voxelwise reho
|
150
|
+
# If the input data space is "native", then reho_file_path points to
|
151
|
+
# the input data path as it might be required for coordinates
|
152
|
+
# transformation to native space.
|
142
153
|
if self.reho_params is not None:
|
143
|
-
reho_map = self.
|
154
|
+
reho_map, reho_file_path = self._compute(
|
155
|
+
input_data=input, **self.reho_params
|
156
|
+
)
|
144
157
|
else:
|
145
|
-
reho_map = self.
|
158
|
+
reho_map, reho_file_path = self._compute(input_data=input)
|
159
|
+
|
146
160
|
# Initialize sphere aggregation
|
147
161
|
sphere_aggregation = SphereAggregation(
|
148
162
|
coords=self.coords,
|
@@ -156,7 +170,7 @@ class ReHoSpheres(ReHoBase):
|
|
156
170
|
# Perform aggregation on reho map
|
157
171
|
sphere_aggregation_input = dict(input.items())
|
158
172
|
sphere_aggregation_input["data"] = reho_map
|
159
|
-
sphere_aggregation_input["path"] =
|
173
|
+
sphere_aggregation_input["path"] = reho_file_path
|
160
174
|
output = sphere_aggregation.compute(
|
161
175
|
input=sphere_aggregation_input, extra_input=extra_input
|
162
176
|
)
|
@@ -1,94 +1,88 @@
|
|
1
|
-
"""Provide tests for
|
1
|
+
"""Provide tests for ReHoParcels."""
|
2
2
|
|
3
3
|
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
4
|
# License: AGPL
|
5
5
|
|
6
|
+
import logging
|
6
7
|
from pathlib import Path
|
7
8
|
|
8
9
|
import pytest
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
from junifer.markers
|
13
|
-
from junifer.pipeline
|
14
|
-
from junifer.
|
15
|
-
from junifer.
|
16
|
-
|
10
|
+
import scipy as sp
|
11
|
+
|
12
|
+
from junifer.datareader import DefaultDataReader
|
13
|
+
from junifer.markers import ReHoParcels
|
14
|
+
from junifer.pipeline import WorkDirManager
|
15
|
+
from junifer.pipeline.utils import _check_afni, _check_ants
|
16
|
+
from junifer.storage import SQLiteFeatureStorage
|
17
|
+
from junifer.testing.datagrabbers import (
|
18
|
+
PartlyCloudyTestingDataGrabber,
|
19
|
+
SPMAuditoryTestingDataGrabber,
|
20
|
+
)
|
17
21
|
|
18
|
-
PARCELLATION = "Schaefer100x7"
|
19
22
|
|
23
|
+
def test_ReHoParcels(caplog: pytest.LogCaptureFixture, tmp_path: Path) -> None:
|
24
|
+
"""Test ReHoParcels.
|
20
25
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
fmri_img = nimg.load_img(subject_data["BOLD"]["path"])
|
28
|
-
# Initialize marker
|
29
|
-
reho_parcels_marker = ReHoParcels(parcellation=PARCELLATION)
|
30
|
-
# Fit transform marker on data
|
31
|
-
reho_parcels_output = reho_parcels_marker.fit_transform(
|
32
|
-
{"BOLD": {"path": "/tmp", "data": fmri_img, "meta": {}}}
|
33
|
-
)
|
34
|
-
# Get BOLD output
|
35
|
-
reho_parcels_output_bold = reho_parcels_output["BOLD"]
|
36
|
-
# Assert BOLD output keys
|
37
|
-
assert "data" in reho_parcels_output_bold
|
38
|
-
assert "col_names" in reho_parcels_output_bold
|
26
|
+
Parameters
|
27
|
+
----------
|
28
|
+
caplog : pytest.LogCaptureFixture
|
29
|
+
The pytest.LogCaptureFixture object.
|
30
|
+
tmp_path : pathlib.Path
|
31
|
+
The path to the test directory.
|
39
32
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
33
|
+
"""
|
34
|
+
with caplog.at_level(logging.DEBUG):
|
35
|
+
with PartlyCloudyTestingDataGrabber() as dg:
|
36
|
+
element_data = DefaultDataReader().fit_transform(dg["sub-01"])
|
37
|
+
# Update workdir to current test's tmp_path
|
38
|
+
WorkDirManager().workdir = tmp_path
|
39
|
+
|
40
|
+
# Initialize marker
|
41
|
+
marker = ReHoParcels(
|
42
|
+
parcellation="TianxS1x3TxMNInonlinear2009cAsym",
|
43
|
+
using="junifer",
|
44
|
+
)
|
45
|
+
# Fit transform marker on data
|
46
|
+
output = marker.fit_transform(element_data)
|
47
|
+
|
48
|
+
assert "Creating cache" in caplog.text
|
49
|
+
|
50
|
+
# Get BOLD output
|
51
|
+
assert "BOLD" in output
|
52
|
+
output_bold = output["BOLD"]
|
53
|
+
# Assert BOLD output keys
|
54
|
+
assert "data" in output_bold
|
55
|
+
assert "col_names" in output_bold
|
56
|
+
|
57
|
+
output_bold_data = output_bold["data"]
|
58
|
+
# Assert BOLD output data dimension
|
59
|
+
assert output_bold_data.ndim == 2
|
60
|
+
# Assert BOLD output data is normalized
|
61
|
+
assert (output_bold_data > 0).all() and (
|
62
|
+
output_bold_data < 1
|
63
|
+
).all()
|
64
|
+
|
65
|
+
# Reset log capture
|
66
|
+
caplog.clear()
|
67
|
+
# Initialize storage
|
68
|
+
storage = SQLiteFeatureStorage(tmp_path / "reho_parcels.sqlite")
|
69
|
+
# Fit transform marker on data with storage
|
70
|
+
marker.fit_transform(
|
71
|
+
input=element_data,
|
72
|
+
storage=storage,
|
73
|
+
)
|
74
|
+
# Cache working correctly
|
75
|
+
assert "Creating cache" not in caplog.text
|
47
76
|
|
48
77
|
|
49
78
|
@pytest.mark.skipif(
|
50
|
-
|
79
|
+
_check_ants() is False, reason="requires ANTs to be in PATH"
|
51
80
|
)
|
52
|
-
|
53
|
-
"
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
# Load image to memory
|
58
|
-
fmri_img = nimg.load_img(subject_data["BOLD"]["path"])
|
59
|
-
|
60
|
-
# Initialize marker with use_afni=False
|
61
|
-
reho_parcels_marker_python = ReHoParcels(
|
62
|
-
parcellation=PARCELLATION, use_afni=False
|
63
|
-
)
|
64
|
-
# Fit transform marker on data
|
65
|
-
reho_parcels_output_python = reho_parcels_marker_python.fit_transform(
|
66
|
-
{"BOLD": {"path": "/tmp", "data": fmri_img, "meta": {}}}
|
67
|
-
)
|
68
|
-
# Get BOLD output
|
69
|
-
reho_parcels_output_bold_python = reho_parcels_output_python["BOLD"]
|
70
|
-
|
71
|
-
# Initialize marker with use_afni=True
|
72
|
-
reho_parcels_marker_afni = ReHoParcels(
|
73
|
-
parcellation=PARCELLATION, use_afni=True
|
74
|
-
)
|
75
|
-
# Fit transform marker on data
|
76
|
-
reho_parcels_output_afni = reho_parcels_marker_afni.fit_transform(
|
77
|
-
{"BOLD": {"path": "/tmp", "data": fmri_img, "meta": {}}}
|
78
|
-
)
|
79
|
-
# Get BOLD output
|
80
|
-
reho_parcels_output_bold_afni = reho_parcels_output_afni["BOLD"]
|
81
|
-
|
82
|
-
# Check for Pearson correlation coefficient
|
83
|
-
r, _ = pearsonr(
|
84
|
-
reho_parcels_output_bold_python["data"].flatten(),
|
85
|
-
reho_parcels_output_bold_afni["data"].flatten(),
|
86
|
-
)
|
87
|
-
assert r >= 0.3 # this is very bad, but they differ...
|
88
|
-
|
89
|
-
|
90
|
-
def test_reho_parcels_storage(tmp_path: Path) -> None:
|
91
|
-
"""Test ReHoParcels storage.
|
81
|
+
@pytest.mark.skipif(
|
82
|
+
_check_afni() is False, reason="requires AFNI to be in PATH"
|
83
|
+
)
|
84
|
+
def test_ReHoParcels_comparison(tmp_path: Path) -> None:
|
85
|
+
"""Test ReHoParcels implementation comparison.
|
92
86
|
|
93
87
|
Parameters
|
94
88
|
----------
|
@@ -97,22 +91,29 @@ def test_reho_parcels_storage(tmp_path: Path) -> None:
|
|
97
91
|
|
98
92
|
"""
|
99
93
|
with SPMAuditoryTestingDataGrabber() as dg:
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
94
|
+
element_data = DefaultDataReader().fit_transform(dg["sub001"])
|
95
|
+
# Update workdir to current test's tmp_path
|
96
|
+
WorkDirManager().workdir = tmp_path
|
97
|
+
|
104
98
|
# Initialize marker
|
105
|
-
|
106
|
-
|
107
|
-
reho_parcels_storage = SQLiteFeatureStorage(
|
108
|
-
tmp_path / "reho_parcels.sqlite"
|
99
|
+
junifer_marker = ReHoParcels(
|
100
|
+
parcellation="Schaefer100x7", using="junifer"
|
109
101
|
)
|
110
|
-
#
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
102
|
+
# Fit transform marker on data
|
103
|
+
junifer_output = junifer_marker.fit_transform(element_data)
|
104
|
+
# Get BOLD output
|
105
|
+
junifer_output_bold = junifer_output["BOLD"]
|
106
|
+
|
107
|
+
# Initialize marker
|
108
|
+
afni_marker = ReHoParcels(parcellation="Schaefer100x7", using="afni")
|
109
|
+
# Fit transform marker on data
|
110
|
+
afni_output = afni_marker.fit_transform(element_data)
|
111
|
+
# Get BOLD output
|
112
|
+
afni_output_bold = afni_output["BOLD"]
|
113
|
+
|
114
|
+
# Check for Pearson correlation coefficient
|
115
|
+
r, _ = sp.stats.pearsonr(
|
116
|
+
junifer_output_bold["data"].flatten(),
|
117
|
+
afni_output_bold["data"].flatten(),
|
118
118
|
)
|
119
|
+
assert r >= 0.2 # this is very bad, but they differ...
|