junifer 0.0.3.dev188__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.dev188.dist-info → junifer-0.0.4.dist-info}/METADATA +59 -28
- junifer-0.0.4.dist-info/RECORD +257 -0
- {junifer-0.0.3.dev188.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.dev188.dist-info/RECORD +0 -199
- {junifer-0.0.3.dev188.dist-info → junifer-0.0.4.dist-info}/AUTHORS.rst +0 -0
- {junifer-0.0.3.dev188.dist-info → junifer-0.0.4.dist-info}/LICENSE.md +0 -0
- {junifer-0.0.3.dev188.dist-info → junifer-0.0.4.dist-info}/entry_points.txt +0 -0
- {junifer-0.0.3.dev188.dist-info → junifer-0.0.4.dist-info}/top_level.txt +0 -0
junifer/datagrabber/pattern.py
CHANGED
@@ -32,36 +32,134 @@ class PatternDataGrabber(BaseDataGrabber):
|
|
32
32
|
types : list of str
|
33
33
|
The types of data to be grabbed.
|
34
34
|
patterns : dict
|
35
|
-
|
36
|
-
|
37
|
-
``
|
35
|
+
Data type patterns as a dictionary. It has the following schema:
|
36
|
+
|
37
|
+
* ``"T1w"`` :
|
38
|
+
|
39
|
+
.. code-block:: none
|
40
|
+
|
41
|
+
{
|
42
|
+
"mandatory": ["pattern", "space"],
|
43
|
+
"optional": []
|
44
|
+
}
|
45
|
+
|
46
|
+
* ``"T2w"`` :
|
47
|
+
|
48
|
+
.. code-block:: none
|
49
|
+
|
50
|
+
{
|
51
|
+
"mandatory": ["pattern", "space"],
|
52
|
+
"optional": []
|
53
|
+
}
|
54
|
+
|
55
|
+
* ``"BOLD"`` :
|
56
|
+
|
57
|
+
.. code-block:: none
|
58
|
+
|
59
|
+
{
|
60
|
+
"mandatory": ["pattern", "space"],
|
61
|
+
"optional": ["mask_item"]
|
62
|
+
}
|
63
|
+
|
64
|
+
* ``"Warp"`` :
|
65
|
+
|
66
|
+
.. code-block:: none
|
67
|
+
|
68
|
+
{
|
69
|
+
"mandatory": ["pattern", "src", "dst"],
|
70
|
+
"optional": []
|
71
|
+
}
|
72
|
+
|
73
|
+
* ``"BOLD_confounds"`` :
|
74
|
+
|
75
|
+
.. code-block:: none
|
76
|
+
|
77
|
+
{
|
78
|
+
"mandatory": ["pattern", "format"],
|
79
|
+
"optional": []
|
80
|
+
}
|
81
|
+
|
82
|
+
* ``"VBM_GM"`` :
|
83
|
+
|
84
|
+
.. code-block:: none
|
85
|
+
|
86
|
+
{
|
87
|
+
"mandatory": ["pattern", "space"],
|
88
|
+
"optional": []
|
89
|
+
}
|
90
|
+
|
91
|
+
* ``"VBM_WM"`` :
|
92
|
+
|
93
|
+
.. code-block:: none
|
94
|
+
|
95
|
+
{
|
96
|
+
"mandatory": ["pattern", "space"],
|
97
|
+
"optional": []
|
98
|
+
}
|
99
|
+
|
100
|
+
Basically, for each data type, one needs to provide ``mandatory`` keys
|
101
|
+
and can choose to also provide ``optional`` keys. The value for each
|
102
|
+
key is a string. So, one needs to provide necessary data types as a
|
103
|
+
dictionary, for example:
|
104
|
+
|
105
|
+
.. code-block:: none
|
106
|
+
|
107
|
+
{
|
108
|
+
"BOLD": {
|
109
|
+
"pattern": "...",
|
110
|
+
"space": "...",
|
111
|
+
},
|
112
|
+
"T1w": {
|
113
|
+
"pattern": "...",
|
114
|
+
"space": "...",
|
115
|
+
},
|
116
|
+
"Warp": {
|
117
|
+
"pattern": "...",
|
118
|
+
"src": "...",
|
119
|
+
"dst": "...",
|
120
|
+
}
|
121
|
+
}
|
122
|
+
|
123
|
+
taken from :class:`.HCP1200`.
|
38
124
|
replacements : str or list of str
|
39
|
-
Replacements in the
|
125
|
+
Replacements in the ``pattern`` key of each data type. The value needs
|
126
|
+
to be a list of all possible replacements.
|
40
127
|
datadir : str or pathlib.Path
|
41
128
|
The directory where the data is / will be stored.
|
42
129
|
confounds_format : {"fmriprep", "adhoc"} or None, optional
|
43
130
|
The format of the confounds for the dataset (default None).
|
44
131
|
|
132
|
+
Raises
|
133
|
+
------
|
134
|
+
ValueError
|
135
|
+
If ``confounds_format`` is invalid.
|
136
|
+
|
45
137
|
"""
|
46
138
|
|
47
139
|
def __init__(
|
48
140
|
self,
|
49
141
|
types: List[str],
|
50
|
-
patterns: Dict[str, str],
|
142
|
+
patterns: Dict[str, Dict[str, str]],
|
51
143
|
replacements: Union[List[str], str],
|
52
144
|
datadir: Union[str, Path],
|
53
145
|
confounds_format: Optional[str] = None,
|
54
146
|
) -> None:
|
55
147
|
# Validate patterns
|
56
148
|
validate_patterns(types=types, patterns=patterns)
|
149
|
+
self.patterns = patterns
|
57
150
|
|
151
|
+
# Convert replacements to list if not already
|
58
152
|
if not isinstance(replacements, list):
|
59
153
|
replacements = [replacements]
|
60
154
|
# Validate replacements
|
61
155
|
validate_replacements(replacements=replacements, patterns=patterns)
|
156
|
+
self.replacements = replacements
|
62
157
|
|
63
158
|
# Validate confounds format
|
64
|
-
if
|
159
|
+
if (
|
160
|
+
confounds_format is not None
|
161
|
+
and confounds_format not in _CONFOUNDS_FORMATS
|
162
|
+
):
|
65
163
|
raise_error(
|
66
164
|
"Invalid value for `confounds_format`, should be one of "
|
67
165
|
f"{_CONFOUNDS_FORMATS}."
|
@@ -72,8 +170,7 @@ class PatternDataGrabber(BaseDataGrabber):
|
|
72
170
|
logger.debug("Initializing PatternDataGrabber")
|
73
171
|
logger.debug(f"\tpatterns = {patterns}")
|
74
172
|
logger.debug(f"\treplacements = {replacements}")
|
75
|
-
|
76
|
-
self.replacements = replacements
|
173
|
+
logger.debug(f"\tconfounds_format = {confounds_format}")
|
77
174
|
|
78
175
|
@property
|
79
176
|
def skip_file_check(self) -> bool:
|
@@ -136,6 +233,11 @@ class PatternDataGrabber(BaseDataGrabber):
|
|
136
233
|
str
|
137
234
|
The pattern with the element replaced.
|
138
235
|
|
236
|
+
Raises
|
237
|
+
------
|
238
|
+
ValueError
|
239
|
+
If element keys do not match with replacements.
|
240
|
+
|
139
241
|
"""
|
140
242
|
if list(element.keys()) != self.replacements:
|
141
243
|
raise_error(
|
@@ -160,7 +262,7 @@ class PatternDataGrabber(BaseDataGrabber):
|
|
160
262
|
return self.replacements
|
161
263
|
|
162
264
|
def get_item(self, **element: str) -> Dict[str, Dict]:
|
163
|
-
"""Implement single element indexing
|
265
|
+
"""Implement single element indexing for the datagrabber.
|
164
266
|
|
165
267
|
This method constructs a real path to the requested item's data, by
|
166
268
|
replacing the ``patterns`` with actual values passed via ``**element``.
|
@@ -177,20 +279,33 @@ class PatternDataGrabber(BaseDataGrabber):
|
|
177
279
|
Dictionary of dictionaries for each type of data required for the
|
178
280
|
specified element.
|
179
281
|
|
282
|
+
Raises
|
283
|
+
------
|
284
|
+
RuntimeError
|
285
|
+
If more than one file matches for a data type's pattern or
|
286
|
+
if no file matches for a data type's pattern or
|
287
|
+
if file cannot be accessed for an element.
|
288
|
+
|
180
289
|
"""
|
181
290
|
out = {}
|
182
291
|
for t_type in self.types:
|
183
292
|
t_pattern = self.patterns[t_type]
|
184
|
-
t_replace = self._replace_patterns_glob(
|
293
|
+
t_replace = self._replace_patterns_glob(
|
294
|
+
element, t_pattern["pattern"]
|
295
|
+
)
|
185
296
|
if "*" in t_replace:
|
186
297
|
t_matches = list(self.datadir.absolute().glob(t_replace))
|
187
298
|
if len(t_matches) > 1:
|
188
299
|
raise_error(
|
189
300
|
f"More than one file matches for {element} / {t_type}:"
|
190
|
-
f" {t_matches}"
|
301
|
+
f" {t_matches}",
|
302
|
+
klass=RuntimeError,
|
191
303
|
)
|
192
304
|
elif len(t_matches) == 0:
|
193
|
-
raise_error(
|
305
|
+
raise_error(
|
306
|
+
f"No file matches for {element} / {t_type}",
|
307
|
+
klass=RuntimeError,
|
308
|
+
)
|
194
309
|
t_out = t_matches[0]
|
195
310
|
else:
|
196
311
|
t_out = self.datadir / t_replace
|
@@ -198,22 +313,13 @@ class PatternDataGrabber(BaseDataGrabber):
|
|
198
313
|
if not t_out.exists() and not t_out.is_symlink():
|
199
314
|
raise_error(
|
200
315
|
f"Cannot access {t_type} for {element}: "
|
201
|
-
f"File {t_out} does not exist"
|
316
|
+
f"File {t_out} does not exist",
|
317
|
+
klass=RuntimeError,
|
202
318
|
)
|
203
319
|
# Update path for the element
|
204
|
-
out[t_type] =
|
205
|
-
#
|
206
|
-
|
207
|
-
if t_type == "BOLD_confounds":
|
208
|
-
if not self.confounds_format:
|
209
|
-
raise_error(
|
210
|
-
"`confounds_format` needs to be one of "
|
211
|
-
f"{_CONFOUNDS_FORMATS}, None provided. "
|
212
|
-
"As the DataGrabber used specifies "
|
213
|
-
"'BOLD_confounds', None is invalid."
|
214
|
-
)
|
215
|
-
# Set the format
|
216
|
-
out[t_type].update({"format": self.confounds_format})
|
320
|
+
out[t_type] = t_pattern.copy() # copy data type dictionary
|
321
|
+
out[t_type].pop("pattern") # remove pattern key
|
322
|
+
out[t_type].update({"path": t_out}) # add path key
|
217
323
|
|
218
324
|
return out
|
219
325
|
|
@@ -252,7 +358,7 @@ class PatternDataGrabber(BaseDataGrabber):
|
|
252
358
|
re_pattern,
|
253
359
|
glob_pattern,
|
254
360
|
t_replacements,
|
255
|
-
) = self._replace_patterns_regex(t_pattern)
|
361
|
+
) = self._replace_patterns_regex(t_pattern["pattern"])
|
256
362
|
for fname in self.datadir.glob(glob_pattern):
|
257
363
|
suffix = fname.relative_to(self.datadir).as_posix()
|
258
364
|
m = re.match(re_pattern, suffix)
|
@@ -5,12 +5,11 @@
|
|
5
5
|
# Synchon Mandal <s.mandal@fz-juelich.de>
|
6
6
|
# License: AGPL
|
7
7
|
|
8
|
-
from typing import Dict, List
|
9
8
|
|
10
9
|
from ..api.decorators import register_datagrabber
|
10
|
+
from ..utils import logger
|
11
11
|
from .datalad_base import DataladDataGrabber
|
12
12
|
from .pattern import PatternDataGrabber
|
13
|
-
from .utils import validate_patterns
|
14
13
|
|
15
14
|
|
16
15
|
@register_datagrabber
|
@@ -25,11 +24,109 @@ class PatternDataladDataGrabber(DataladDataGrabber, PatternDataGrabber):
|
|
25
24
|
types : list of str
|
26
25
|
The types of data to be grabbed.
|
27
26
|
patterns : dict
|
28
|
-
|
29
|
-
|
30
|
-
``
|
31
|
-
|
32
|
-
|
27
|
+
Data type patterns as a dictionary. It has the following schema:
|
28
|
+
|
29
|
+
* ``"T1w"`` :
|
30
|
+
|
31
|
+
.. code-block:: none
|
32
|
+
|
33
|
+
{
|
34
|
+
"mandatory": ["pattern", "space"],
|
35
|
+
"optional": []
|
36
|
+
}
|
37
|
+
|
38
|
+
* ``"T2w"`` :
|
39
|
+
|
40
|
+
.. code-block:: none
|
41
|
+
|
42
|
+
{
|
43
|
+
"mandatory": ["pattern", "space"],
|
44
|
+
"optional": []
|
45
|
+
}
|
46
|
+
|
47
|
+
* ``"BOLD"`` :
|
48
|
+
|
49
|
+
.. code-block:: none
|
50
|
+
|
51
|
+
{
|
52
|
+
"mandatory": ["pattern", "space"],
|
53
|
+
"optional": ["mask_item"]
|
54
|
+
}
|
55
|
+
|
56
|
+
* ``"Warp"`` :
|
57
|
+
|
58
|
+
.. code-block:: none
|
59
|
+
|
60
|
+
{
|
61
|
+
"mandatory": ["pattern", "src", "dst"],
|
62
|
+
"optional": []
|
63
|
+
}
|
64
|
+
|
65
|
+
* ``"BOLD_confounds"`` :
|
66
|
+
|
67
|
+
.. code-block:: none
|
68
|
+
|
69
|
+
{
|
70
|
+
"mandatory": ["pattern", "format"],
|
71
|
+
"optional": []
|
72
|
+
}
|
73
|
+
|
74
|
+
* ``"VBM_GM"`` :
|
75
|
+
|
76
|
+
.. code-block:: none
|
77
|
+
|
78
|
+
{
|
79
|
+
"mandatory": ["pattern", "space"],
|
80
|
+
"optional": []
|
81
|
+
}
|
82
|
+
|
83
|
+
* ``"VBM_WM"`` :
|
84
|
+
|
85
|
+
.. code-block:: none
|
86
|
+
|
87
|
+
{
|
88
|
+
"mandatory": ["pattern", "space"],
|
89
|
+
"optional": []
|
90
|
+
}
|
91
|
+
|
92
|
+
Basically, for each data type, one needs to provide ``mandatory`` keys
|
93
|
+
and can choose to also provide ``optional`` keys. The value for each
|
94
|
+
key is a string. So, one needs to provide necessary data types as a
|
95
|
+
dictionary, for example:
|
96
|
+
|
97
|
+
.. code-block:: none
|
98
|
+
|
99
|
+
{
|
100
|
+
"BOLD": {
|
101
|
+
"pattern": "...",
|
102
|
+
"space": "...",
|
103
|
+
},
|
104
|
+
"T1w": {
|
105
|
+
"pattern": "...",
|
106
|
+
"space": "...",
|
107
|
+
},
|
108
|
+
"Warp": {
|
109
|
+
"pattern": "...",
|
110
|
+
"src": "...",
|
111
|
+
"dst": "...",
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
taken from :class:`.HCP1200`.
|
116
|
+
replacements : str or list of str
|
117
|
+
Replacements in the ``pattern`` key of each data type. The value needs
|
118
|
+
to be a list of all possible replacements.
|
119
|
+
confounds_format : {"fmriprep", "adhoc"} or None, optional
|
120
|
+
The format of the confounds for the dataset (default None).
|
121
|
+
datadir : str or pathlib.Path or None, optional
|
122
|
+
That directory where the datalad dataset will be cloned. If None,
|
123
|
+
the datalad dataset will be cloned into a temporary directory
|
124
|
+
(default None).
|
125
|
+
rootdir : str or pathlib.Path, optional
|
126
|
+
The path within the datalad dataset to the root directory
|
127
|
+
(default ".").
|
128
|
+
uri : str or None, optional
|
129
|
+
URI of the datalad sibling (default None).
|
33
130
|
|
34
131
|
See Also
|
35
132
|
--------
|
@@ -42,12 +139,13 @@ class PatternDataladDataGrabber(DataladDataGrabber, PatternDataGrabber):
|
|
42
139
|
|
43
140
|
def __init__(
|
44
141
|
self,
|
45
|
-
types: List[str],
|
46
|
-
patterns: Dict[str, str],
|
47
142
|
**kwargs,
|
48
143
|
) -> None:
|
49
|
-
#
|
50
|
-
|
144
|
+
# TODO(synchon): needs to be reworked, DataladDataGrabber needs to be
|
145
|
+
# a mixin to avoid multiple inheritance wherever possible.
|
146
|
+
|
147
|
+
logger.debug("Initializing PatternDataladDataGrabber")
|
148
|
+
for key, val in kwargs.items():
|
149
|
+
logger.debug(f"\t{key} = {val}")
|
51
150
|
|
52
|
-
super().__init__(
|
53
|
-
self.patterns = patterns
|
151
|
+
super().__init__(**kwargs)
|
@@ -12,12 +12,6 @@ import pytest
|
|
12
12
|
from junifer.datagrabber import BaseDataGrabber
|
13
13
|
|
14
14
|
|
15
|
-
def test_BaseDataGrabber_abstractness() -> None:
|
16
|
-
"""Test BaseDataGrabber is abstract base class."""
|
17
|
-
with pytest.raises(TypeError, match=r"abstract"):
|
18
|
-
BaseDataGrabber(datadir="/tmp", types=["func"]) # type: ignore
|
19
|
-
|
20
|
-
|
21
15
|
def test_BaseDataGrabber() -> None:
|
22
16
|
"""Test BaseDataGrabber."""
|
23
17
|
|
@@ -67,3 +61,60 @@ def test_BaseDataGrabber() -> None:
|
|
67
61
|
|
68
62
|
with pytest.raises(NotImplementedError):
|
69
63
|
dg.get_item(subject=1) # type: ignore
|
64
|
+
|
65
|
+
|
66
|
+
def test_BaseDataGrabber_filter_single() -> None:
|
67
|
+
"""Test single-keyed element filter for BaseDataGrabber."""
|
68
|
+
|
69
|
+
# Create concrete class
|
70
|
+
class FilterDataGrabber(BaseDataGrabber):
|
71
|
+
def get_item(self, subject):
|
72
|
+
return {"BOLD": {}}
|
73
|
+
|
74
|
+
def get_elements(self):
|
75
|
+
return ["sub01", "sub02", "sub03"]
|
76
|
+
|
77
|
+
def get_element_keys(self):
|
78
|
+
return ["subject"]
|
79
|
+
|
80
|
+
dg = FilterDataGrabber(datadir="/tmp", types=["BOLD"])
|
81
|
+
with dg:
|
82
|
+
assert "sub01" in list(dg.filter(["sub01"]))
|
83
|
+
assert "sub02" not in list(dg.filter(["sub01"]))
|
84
|
+
|
85
|
+
|
86
|
+
def test_BaseDataGrabber_filter_multi() -> None:
|
87
|
+
"""Test multi-keyed element filter for BaseDataGrabber."""
|
88
|
+
|
89
|
+
# Create concrete class
|
90
|
+
class FilterDataGrabber(BaseDataGrabber):
|
91
|
+
def get_item(self, subject):
|
92
|
+
return {"BOLD": {}}
|
93
|
+
|
94
|
+
def get_elements(self):
|
95
|
+
return [
|
96
|
+
("sub01", "rest"),
|
97
|
+
("sub01", "movie"),
|
98
|
+
("sub02", "rest"),
|
99
|
+
("sub02", "movie"),
|
100
|
+
("sub03", "rest"),
|
101
|
+
("sub03", "movie"),
|
102
|
+
]
|
103
|
+
|
104
|
+
def get_element_keys(self):
|
105
|
+
return ["subject", "task"]
|
106
|
+
|
107
|
+
dg = FilterDataGrabber(datadir="/tmp", types=["BOLD"])
|
108
|
+
with dg:
|
109
|
+
assert ("sub01", "rest") in list(
|
110
|
+
dg.filter([("sub01", "rest")]) # type: ignore
|
111
|
+
)
|
112
|
+
assert ("sub01", "movie") not in list(
|
113
|
+
dg.filter([("sub01", "rest")]) # type: ignore
|
114
|
+
)
|
115
|
+
assert ("sub02", "rest") not in list(
|
116
|
+
dg.filter([("sub01", "rest")]) # type: ignore
|
117
|
+
)
|
118
|
+
assert ("sub02", "movie") not in list(
|
119
|
+
dg.filter([("sub01", "rest")]) # type: ignore
|
120
|
+
)
|