junifer 0.0.5.dev240__py3-none-any.whl → 0.0.6__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/__init__.py +2 -31
- junifer/__init__.pyi +37 -0
- junifer/_version.py +9 -4
- junifer/api/__init__.py +3 -5
- junifer/api/__init__.pyi +4 -0
- junifer/api/decorators.py +14 -19
- junifer/api/functions.py +165 -109
- junifer/api/py.typed +0 -0
- junifer/api/queue_context/__init__.py +2 -4
- junifer/api/queue_context/__init__.pyi +5 -0
- junifer/api/queue_context/gnu_parallel_local_adapter.py +22 -6
- junifer/api/queue_context/htcondor_adapter.py +23 -6
- junifer/api/queue_context/py.typed +0 -0
- junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +3 -3
- junifer/api/queue_context/tests/test_htcondor_adapter.py +3 -3
- junifer/api/tests/test_functions.py +168 -74
- junifer/cli/__init__.py +24 -0
- junifer/cli/__init__.pyi +3 -0
- junifer/{api → cli}/cli.py +141 -125
- junifer/cli/parser.py +235 -0
- junifer/cli/py.typed +0 -0
- junifer/{api → cli}/tests/test_cli.py +8 -8
- junifer/{api/tests/test_api_utils.py → cli/tests/test_cli_utils.py} +5 -4
- junifer/{api → cli}/tests/test_parser.py +2 -2
- junifer/{api → cli}/utils.py +6 -16
- junifer/configs/juseless/__init__.py +2 -2
- junifer/configs/juseless/__init__.pyi +3 -0
- junifer/configs/juseless/datagrabbers/__init__.py +2 -12
- junifer/configs/juseless/datagrabbers/__init__.pyi +13 -0
- junifer/configs/juseless/datagrabbers/ixi_vbm.py +2 -2
- junifer/configs/juseless/datagrabbers/py.typed +0 -0
- junifer/configs/juseless/datagrabbers/tests/test_ucla.py +2 -2
- junifer/configs/juseless/datagrabbers/ucla.py +4 -4
- junifer/configs/juseless/py.typed +0 -0
- junifer/conftest.py +25 -0
- junifer/data/__init__.py +2 -42
- junifer/data/__init__.pyi +29 -0
- junifer/data/_dispatch.py +248 -0
- junifer/data/coordinates/__init__.py +9 -0
- junifer/data/coordinates/__init__.pyi +5 -0
- junifer/data/coordinates/_ants_coordinates_warper.py +104 -0
- junifer/data/coordinates/_coordinates.py +385 -0
- junifer/data/coordinates/_fsl_coordinates_warper.py +81 -0
- junifer/data/{tests → coordinates/tests}/test_coordinates.py +26 -33
- junifer/data/masks/__init__.py +9 -0
- junifer/data/masks/__init__.pyi +6 -0
- junifer/data/masks/_ants_mask_warper.py +177 -0
- junifer/data/masks/_fsl_mask_warper.py +106 -0
- junifer/data/masks/_masks.py +802 -0
- junifer/data/{tests → masks/tests}/test_masks.py +67 -63
- junifer/data/parcellations/__init__.py +9 -0
- junifer/data/parcellations/__init__.pyi +6 -0
- junifer/data/parcellations/_ants_parcellation_warper.py +166 -0
- junifer/data/parcellations/_fsl_parcellation_warper.py +89 -0
- junifer/data/parcellations/_parcellations.py +1388 -0
- junifer/data/{tests → parcellations/tests}/test_parcellations.py +165 -295
- junifer/data/pipeline_data_registry_base.py +76 -0
- junifer/data/py.typed +0 -0
- junifer/data/template_spaces.py +44 -79
- junifer/data/tests/test_data_utils.py +1 -2
- junifer/data/tests/test_template_spaces.py +8 -4
- junifer/data/utils.py +109 -4
- junifer/datagrabber/__init__.py +2 -26
- junifer/datagrabber/__init__.pyi +27 -0
- junifer/datagrabber/aomic/__init__.py +2 -4
- junifer/datagrabber/aomic/__init__.pyi +5 -0
- junifer/datagrabber/aomic/id1000.py +81 -52
- junifer/datagrabber/aomic/piop1.py +83 -55
- junifer/datagrabber/aomic/piop2.py +85 -56
- junifer/datagrabber/aomic/py.typed +0 -0
- junifer/datagrabber/aomic/tests/test_id1000.py +19 -12
- junifer/datagrabber/aomic/tests/test_piop1.py +52 -18
- junifer/datagrabber/aomic/tests/test_piop2.py +50 -17
- junifer/datagrabber/base.py +22 -18
- junifer/datagrabber/datalad_base.py +71 -34
- junifer/datagrabber/dmcc13_benchmark.py +31 -18
- junifer/datagrabber/hcp1200/__init__.py +2 -3
- junifer/datagrabber/hcp1200/__init__.pyi +4 -0
- junifer/datagrabber/hcp1200/datalad_hcp1200.py +3 -3
- junifer/datagrabber/hcp1200/hcp1200.py +26 -15
- junifer/datagrabber/hcp1200/py.typed +0 -0
- junifer/datagrabber/hcp1200/tests/test_hcp1200.py +8 -2
- junifer/datagrabber/multiple.py +14 -9
- junifer/datagrabber/pattern.py +132 -96
- junifer/datagrabber/pattern_validation_mixin.py +206 -94
- junifer/datagrabber/py.typed +0 -0
- junifer/datagrabber/tests/test_datalad_base.py +27 -12
- junifer/datagrabber/tests/test_dmcc13_benchmark.py +28 -11
- junifer/datagrabber/tests/test_multiple.py +48 -2
- junifer/datagrabber/tests/test_pattern_datalad.py +1 -1
- junifer/datagrabber/tests/test_pattern_validation_mixin.py +6 -6
- junifer/datareader/__init__.py +2 -2
- junifer/datareader/__init__.pyi +3 -0
- junifer/datareader/default.py +6 -6
- junifer/datareader/py.typed +0 -0
- junifer/external/nilearn/__init__.py +2 -3
- junifer/external/nilearn/__init__.pyi +4 -0
- junifer/external/nilearn/junifer_connectivity_measure.py +25 -17
- junifer/external/nilearn/junifer_nifti_spheres_masker.py +4 -4
- junifer/external/nilearn/py.typed +0 -0
- junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +17 -16
- junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +2 -3
- junifer/markers/__init__.py +2 -38
- junifer/markers/__init__.pyi +37 -0
- junifer/markers/base.py +11 -14
- junifer/markers/brainprint.py +12 -14
- junifer/markers/complexity/__init__.py +2 -18
- junifer/markers/complexity/__init__.pyi +17 -0
- junifer/markers/complexity/complexity_base.py +9 -11
- junifer/markers/complexity/hurst_exponent.py +7 -7
- junifer/markers/complexity/multiscale_entropy_auc.py +7 -7
- junifer/markers/complexity/perm_entropy.py +7 -7
- junifer/markers/complexity/py.typed +0 -0
- junifer/markers/complexity/range_entropy.py +7 -7
- junifer/markers/complexity/range_entropy_auc.py +7 -7
- junifer/markers/complexity/sample_entropy.py +7 -7
- junifer/markers/complexity/tests/test_complexity_base.py +1 -1
- junifer/markers/complexity/tests/test_hurst_exponent.py +5 -5
- junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +5 -5
- junifer/markers/complexity/tests/test_perm_entropy.py +5 -5
- junifer/markers/complexity/tests/test_range_entropy.py +5 -5
- junifer/markers/complexity/tests/test_range_entropy_auc.py +5 -5
- junifer/markers/complexity/tests/test_sample_entropy.py +5 -5
- junifer/markers/complexity/tests/test_weighted_perm_entropy.py +5 -5
- junifer/markers/complexity/weighted_perm_entropy.py +7 -7
- junifer/markers/ets_rss.py +12 -11
- junifer/markers/falff/__init__.py +2 -3
- junifer/markers/falff/__init__.pyi +4 -0
- junifer/markers/falff/_afni_falff.py +38 -45
- junifer/markers/falff/_junifer_falff.py +16 -19
- junifer/markers/falff/falff_base.py +7 -11
- junifer/markers/falff/falff_parcels.py +9 -9
- junifer/markers/falff/falff_spheres.py +8 -8
- junifer/markers/falff/py.typed +0 -0
- junifer/markers/falff/tests/test_falff_spheres.py +3 -1
- junifer/markers/functional_connectivity/__init__.py +2 -12
- junifer/markers/functional_connectivity/__init__.pyi +13 -0
- junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +9 -8
- junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +8 -8
- junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +7 -7
- junifer/markers/functional_connectivity/functional_connectivity_base.py +13 -12
- junifer/markers/functional_connectivity/functional_connectivity_parcels.py +8 -8
- junifer/markers/functional_connectivity/functional_connectivity_spheres.py +7 -7
- junifer/markers/functional_connectivity/py.typed +0 -0
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +1 -2
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +1 -2
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +6 -6
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +5 -5
- junifer/markers/parcel_aggregation.py +22 -17
- junifer/markers/py.typed +0 -0
- junifer/markers/reho/__init__.py +2 -3
- junifer/markers/reho/__init__.pyi +4 -0
- junifer/markers/reho/_afni_reho.py +29 -35
- junifer/markers/reho/_junifer_reho.py +13 -14
- junifer/markers/reho/py.typed +0 -0
- junifer/markers/reho/reho_base.py +7 -11
- junifer/markers/reho/reho_parcels.py +10 -10
- junifer/markers/reho/reho_spheres.py +9 -9
- junifer/markers/sphere_aggregation.py +22 -17
- junifer/markers/temporal_snr/__init__.py +2 -3
- junifer/markers/temporal_snr/__init__.pyi +4 -0
- junifer/markers/temporal_snr/py.typed +0 -0
- junifer/markers/temporal_snr/temporal_snr_base.py +11 -10
- junifer/markers/temporal_snr/temporal_snr_parcels.py +8 -8
- junifer/markers/temporal_snr/temporal_snr_spheres.py +7 -7
- junifer/markers/tests/test_ets_rss.py +3 -3
- junifer/markers/tests/test_parcel_aggregation.py +24 -24
- junifer/markers/tests/test_sphere_aggregation.py +6 -6
- junifer/markers/utils.py +3 -3
- junifer/onthefly/__init__.py +2 -1
- junifer/onthefly/_brainprint.py +138 -0
- junifer/onthefly/read_transform.py +5 -8
- junifer/pipeline/__init__.py +2 -10
- junifer/pipeline/__init__.pyi +13 -0
- junifer/{markers/collection.py → pipeline/marker_collection.py} +8 -14
- junifer/pipeline/pipeline_component_registry.py +294 -0
- junifer/pipeline/pipeline_step_mixin.py +15 -11
- junifer/pipeline/py.typed +0 -0
- junifer/{markers/tests/test_collection.py → pipeline/tests/test_marker_collection.py} +2 -3
- junifer/pipeline/tests/test_pipeline_component_registry.py +200 -0
- junifer/pipeline/tests/test_pipeline_step_mixin.py +36 -37
- junifer/pipeline/tests/test_update_meta_mixin.py +4 -4
- junifer/pipeline/tests/test_workdir_manager.py +43 -0
- junifer/pipeline/update_meta_mixin.py +21 -17
- junifer/pipeline/utils.py +6 -6
- junifer/pipeline/workdir_manager.py +19 -5
- junifer/preprocess/__init__.py +2 -10
- junifer/preprocess/__init__.pyi +11 -0
- junifer/preprocess/base.py +10 -10
- junifer/preprocess/confounds/__init__.py +2 -2
- junifer/preprocess/confounds/__init__.pyi +3 -0
- junifer/preprocess/confounds/fmriprep_confound_remover.py +243 -64
- junifer/preprocess/confounds/py.typed +0 -0
- junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +121 -14
- junifer/preprocess/py.typed +0 -0
- junifer/preprocess/smoothing/__init__.py +2 -2
- junifer/preprocess/smoothing/__init__.pyi +3 -0
- junifer/preprocess/smoothing/_afni_smoothing.py +40 -40
- junifer/preprocess/smoothing/_fsl_smoothing.py +22 -32
- junifer/preprocess/smoothing/_nilearn_smoothing.py +35 -14
- junifer/preprocess/smoothing/py.typed +0 -0
- junifer/preprocess/smoothing/smoothing.py +11 -13
- junifer/preprocess/warping/__init__.py +2 -2
- junifer/preprocess/warping/__init__.pyi +3 -0
- junifer/preprocess/warping/_ants_warper.py +136 -32
- junifer/preprocess/warping/_fsl_warper.py +73 -22
- junifer/preprocess/warping/py.typed +0 -0
- junifer/preprocess/warping/space_warper.py +39 -11
- junifer/preprocess/warping/tests/test_space_warper.py +5 -9
- junifer/py.typed +0 -0
- junifer/stats.py +5 -5
- junifer/storage/__init__.py +2 -10
- junifer/storage/__init__.pyi +11 -0
- junifer/storage/base.py +47 -13
- junifer/storage/hdf5.py +95 -33
- junifer/storage/pandas_base.py +12 -11
- junifer/storage/py.typed +0 -0
- junifer/storage/sqlite.py +11 -11
- junifer/storage/tests/test_hdf5.py +86 -4
- junifer/storage/tests/test_sqlite.py +2 -2
- junifer/storage/tests/test_storage_base.py +5 -2
- junifer/storage/tests/test_utils.py +33 -7
- junifer/storage/utils.py +95 -9
- junifer/testing/__init__.py +2 -3
- junifer/testing/__init__.pyi +4 -0
- junifer/testing/datagrabbers.py +10 -11
- junifer/testing/py.typed +0 -0
- junifer/testing/registry.py +4 -7
- junifer/testing/tests/test_testing_registry.py +9 -17
- junifer/tests/test_stats.py +2 -2
- junifer/typing/__init__.py +9 -0
- junifer/typing/__init__.pyi +31 -0
- junifer/typing/_typing.py +68 -0
- junifer/utils/__init__.py +2 -12
- junifer/utils/__init__.pyi +18 -0
- junifer/utils/_config.py +110 -0
- junifer/utils/_yaml.py +16 -0
- junifer/utils/helpers.py +6 -6
- junifer/utils/logging.py +117 -8
- junifer/utils/py.typed +0 -0
- junifer/{pipeline → utils}/singleton.py +19 -14
- junifer/utils/tests/test_config.py +59 -0
- {junifer-0.0.5.dev240.dist-info → junifer-0.0.6.dist-info}/METADATA +43 -38
- junifer-0.0.6.dist-info/RECORD +350 -0
- {junifer-0.0.5.dev240.dist-info → junifer-0.0.6.dist-info}/WHEEL +1 -1
- junifer-0.0.6.dist-info/entry_points.txt +2 -0
- junifer/api/parser.py +0 -118
- junifer/data/coordinates.py +0 -408
- junifer/data/masks.py +0 -670
- junifer/data/parcellations.py +0 -1828
- junifer/pipeline/registry.py +0 -177
- junifer/pipeline/tests/test_registry.py +0 -150
- junifer-0.0.5.dev240.dist-info/RECORD +0 -275
- junifer-0.0.5.dev240.dist-info/entry_points.txt +0 -2
- /junifer/{api → cli}/tests/data/gmd_mean.yaml +0 -0
- /junifer/{api → cli}/tests/data/gmd_mean_htcondor.yaml +0 -0
- /junifer/{api → cli}/tests/data/partly_cloudy_agg_mean_tian.yml +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/AutobiographicalMemory_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/CogAC_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/CogAR_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/DMNBuckner_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Dosenbach2010_MNI_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Empathy_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Motor_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/MultiTask_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/PhysioStress_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Power2011_MNI_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Power2013_MNI_VOIs.tsv +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Rew_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Somatosensory_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/ToM_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/VigAtt_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/WM_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/eMDN_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/eSAD_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/extDMN_VOIs.txt +0 -0
- {junifer-0.0.5.dev240.dist-info → junifer-0.0.6.dist-info/licenses}/AUTHORS.rst +0 -0
- {junifer-0.0.5.dev240.dist-info → junifer-0.0.6.dist-info/licenses}/LICENSE.md +0 -0
- {junifer-0.0.5.dev240.dist-info → junifer-0.0.6.dist-info}/top_level.txt +0 -0
@@ -5,12 +5,12 @@
|
|
5
5
|
# Synchon Mandal <s.mandal@fz-juelich.de>
|
6
6
|
# License: AGPL
|
7
7
|
|
8
|
-
from typing import List
|
9
8
|
|
10
9
|
import numpy as np
|
11
10
|
import pandas as pd
|
12
11
|
import pytest
|
13
12
|
from nilearn._utils.exceptions import DimensionError
|
13
|
+
from nilearn.interfaces.fmriprep.load_confounds_utils import prepare_output
|
14
14
|
from numpy.testing import assert_array_equal, assert_raises
|
15
15
|
from pandas.testing import assert_frame_equal
|
16
16
|
|
@@ -47,7 +47,7 @@ def test_fMRIPrepConfoundRemover_init() -> None:
|
|
47
47
|
["T1w", "BOLD"],
|
48
48
|
],
|
49
49
|
)
|
50
|
-
def test_fMRIPrepConfoundRemover_validate_input(input_:
|
50
|
+
def test_fMRIPrepConfoundRemover_validate_input(input_: list[str]) -> None:
|
51
51
|
"""Test fMRIPrepConfoundRemover validate_input.
|
52
52
|
|
53
53
|
Parameters
|
@@ -212,7 +212,7 @@ def test_fMRIPrepConfoundRemover__process_fmriprep_spec() -> None:
|
|
212
212
|
)
|
213
213
|
|
214
214
|
msg = r"Missing basic confounds: \['white_matter'\]"
|
215
|
-
with pytest.raises(
|
215
|
+
with pytest.raises(RuntimeError, match=msg):
|
216
216
|
confound_remover._process_fmriprep_spec({"data": confounds_df})
|
217
217
|
|
218
218
|
var_names = ["csf", "white_matter"]
|
@@ -221,7 +221,7 @@ def test_fMRIPrepConfoundRemover__process_fmriprep_spec() -> None:
|
|
221
221
|
)
|
222
222
|
|
223
223
|
msg = r"Missing framewise_displacement"
|
224
|
-
with pytest.raises(
|
224
|
+
with pytest.raises(RuntimeError, match=msg):
|
225
225
|
confound_remover._process_fmriprep_spec({"data": confounds_df})
|
226
226
|
|
227
227
|
|
@@ -321,6 +321,32 @@ def test_fMRIPRepConfoundRemover__pick_confounds_fmriprep_compute() -> None:
|
|
321
321
|
assert_frame_equal(out_junifer, out_fmriprep)
|
322
322
|
|
323
323
|
|
324
|
+
@pytest.mark.parametrize(
|
325
|
+
"preprocessor",
|
326
|
+
[
|
327
|
+
fMRIPrepConfoundRemover(
|
328
|
+
std_dvars_threshold=1.5,
|
329
|
+
),
|
330
|
+
fMRIPrepConfoundRemover(
|
331
|
+
fd_threshold=0.5,
|
332
|
+
),
|
333
|
+
],
|
334
|
+
)
|
335
|
+
def test_fMRIPrepConfoundRemover__get_scrub_regressors_errors(
|
336
|
+
preprocessor: type,
|
337
|
+
) -> None:
|
338
|
+
"""Test fMRIPrepConfoundRemover scrub regressors errors.
|
339
|
+
|
340
|
+
Parameters
|
341
|
+
----------
|
342
|
+
preprocessor : object
|
343
|
+
The parametrized preprocessor.
|
344
|
+
|
345
|
+
"""
|
346
|
+
with pytest.raises(RuntimeError, match="Invalid confounds file."):
|
347
|
+
preprocessor._get_scrub_regressors(pd.DataFrame({"a": [1, 2]}))
|
348
|
+
|
349
|
+
|
324
350
|
def test_fMRIPrepConfoundRemover__validate_data() -> None:
|
325
351
|
"""Test fMRIPrepConfoundRemover validate data."""
|
326
352
|
confound_remover = fMRIPrepConfoundRemover(strategy={"wm_csf": "full"})
|
@@ -461,22 +487,32 @@ def test_fMRIPrepConfoundRemover_fit_transform() -> None:
|
|
461
487
|
|
462
488
|
with PartlyCloudyTestingDataGrabber(reduce_confounds=False) as dg:
|
463
489
|
element_data = DefaultDataReader().fit_transform(dg["sub-01"])
|
464
|
-
|
490
|
+
# Get original data
|
491
|
+
input_img = element_data["BOLD"]["data"]
|
492
|
+
input_bold = input_img.get_fdata().copy()
|
493
|
+
input_tr = input_img.header.get_zooms()[3]
|
494
|
+
# Fit-transform
|
465
495
|
output = confound_remover.fit_transform(element_data)
|
466
|
-
|
496
|
+
output_img = output["BOLD"]["data"]
|
497
|
+
output_bold = output_img.get_fdata()
|
498
|
+
output_tr = output_img.header.get_zooms()[3]
|
499
|
+
|
467
500
|
# Transformation is in place
|
468
501
|
assert_array_equal(
|
469
|
-
|
502
|
+
output_bold, element_data["BOLD"]["data"].get_fdata()
|
470
503
|
)
|
471
504
|
|
472
505
|
# Data should have the same shape
|
473
|
-
assert
|
506
|
+
assert input_bold.shape == output_bold.shape
|
474
507
|
|
475
508
|
# but be different
|
476
509
|
assert_raises(
|
477
|
-
AssertionError, assert_array_equal,
|
510
|
+
AssertionError, assert_array_equal, input_bold, output_bold
|
478
511
|
)
|
479
512
|
|
513
|
+
# Check t_r
|
514
|
+
assert input_tr == output_tr
|
515
|
+
|
480
516
|
assert "meta" in output["BOLD"]
|
481
517
|
assert "preprocess" in output["BOLD"]["meta"]
|
482
518
|
t_meta = output["BOLD"]["meta"]["preprocess"]
|
@@ -507,22 +543,32 @@ def test_fMRIPrepConfoundRemover_fit_transform_masks() -> None:
|
|
507
543
|
|
508
544
|
with PartlyCloudyTestingDataGrabber(reduce_confounds=False) as dg:
|
509
545
|
element_data = DefaultDataReader().fit_transform(dg["sub-01"])
|
510
|
-
|
546
|
+
# Get original data
|
547
|
+
input_img = element_data["BOLD"]["data"]
|
548
|
+
input_bold = input_img.get_fdata().copy()
|
549
|
+
input_tr = input_img.header.get_zooms()[3]
|
550
|
+
# Fit-transform
|
511
551
|
output = confound_remover.fit_transform(element_data)
|
512
|
-
|
552
|
+
output_img = output["BOLD"]["data"]
|
553
|
+
output_bold = output_img.get_fdata()
|
554
|
+
output_tr = output_img.header.get_zooms()[3]
|
555
|
+
|
513
556
|
# Transformation is in place
|
514
557
|
assert_array_equal(
|
515
|
-
|
558
|
+
output_bold, element_data["BOLD"]["data"].get_fdata()
|
516
559
|
)
|
517
560
|
|
518
561
|
# Data should have the same shape
|
519
|
-
assert
|
562
|
+
assert input_bold.shape == output_bold.shape
|
520
563
|
|
521
564
|
# but be different
|
522
565
|
assert_raises(
|
523
|
-
AssertionError, assert_array_equal,
|
566
|
+
AssertionError, assert_array_equal, input_bold, output_bold
|
524
567
|
)
|
525
568
|
|
569
|
+
# Check t_r
|
570
|
+
assert input_tr == output_tr
|
571
|
+
|
526
572
|
assert "meta" in output["BOLD"]
|
527
573
|
assert "preprocess" in output["BOLD"]["meta"]
|
528
574
|
t_meta = output["BOLD"]["meta"]["preprocess"]
|
@@ -548,3 +594,64 @@ def test_fMRIPrepConfoundRemover_fit_transform_masks() -> None:
|
|
548
594
|
assert "dependencies" in output["BOLD"]["meta"]
|
549
595
|
dependencies = output["BOLD"]["meta"]["dependencies"]
|
550
596
|
assert dependencies == {"numpy", "nilearn"}
|
597
|
+
|
598
|
+
|
599
|
+
def test_fMRIPrepConfoundRemover_scrubbing() -> None:
|
600
|
+
"""Test fMRIPrepConfoundRemover with scrubbing."""
|
601
|
+
confound_remover = fMRIPrepConfoundRemover(
|
602
|
+
strategy={
|
603
|
+
"motion": "full",
|
604
|
+
"wm_csf": "full",
|
605
|
+
"global_signal": "full",
|
606
|
+
"scrubbing": True,
|
607
|
+
},
|
608
|
+
)
|
609
|
+
|
610
|
+
with PartlyCloudyTestingDataGrabber(reduce_confounds=False) as dg:
|
611
|
+
element_data = DefaultDataReader().fit_transform(dg["sub-01"])
|
612
|
+
orig_bold = element_data["BOLD"]["data"].get_fdata().copy()
|
613
|
+
orig_confounds = element_data["BOLD"]["confounds"].copy()
|
614
|
+
pre_input = element_data["BOLD"]
|
615
|
+
pre_extra_input = {
|
616
|
+
"BOLD": {"confounds": element_data["BOLD"]["confounds"]}
|
617
|
+
}
|
618
|
+
output, _ = confound_remover.preprocess(pre_input, pre_extra_input)
|
619
|
+
trans_bold = output["data"].get_fdata()
|
620
|
+
# Transformation is in place
|
621
|
+
assert_array_equal(
|
622
|
+
trans_bold, element_data["BOLD"]["data"].get_fdata()
|
623
|
+
)
|
624
|
+
|
625
|
+
# Data should have different shape
|
626
|
+
assert_raises(
|
627
|
+
AssertionError,
|
628
|
+
assert_array_equal,
|
629
|
+
orig_bold.shape,
|
630
|
+
trans_bold.shape,
|
631
|
+
)
|
632
|
+
# and be different
|
633
|
+
assert_raises(
|
634
|
+
AssertionError, assert_array_equal, orig_bold, trans_bold
|
635
|
+
)
|
636
|
+
|
637
|
+
# Check scrubbing process
|
638
|
+
# Should be at the start
|
639
|
+
confounds_df = confound_remover._pick_confounds(orig_confounds)
|
640
|
+
assert confounds_df.shape == (168, 36)
|
641
|
+
# Should have 4 motion outliers based on threshold
|
642
|
+
motion_outline_regressors = confound_remover._get_scrub_regressors(
|
643
|
+
orig_confounds["data"]
|
644
|
+
)
|
645
|
+
assert motion_outline_regressors.shape == (168, 4)
|
646
|
+
# Add regressors to confounds
|
647
|
+
concat_confounds_df = pd.concat(
|
648
|
+
[confounds_df, motion_outline_regressors], axis=1
|
649
|
+
)
|
650
|
+
assert concat_confounds_df.shape == (168, 40)
|
651
|
+
# Get sample mask and correct confounds
|
652
|
+
sample_mask, final_confounds_df = prepare_output(
|
653
|
+
confounds=concat_confounds_df, demean=False
|
654
|
+
)
|
655
|
+
assert not confounds_df.equals(final_confounds_df)
|
656
|
+
assert sample_mask.shape == (164,)
|
657
|
+
assert not (np.isin([91, 92, 93, 113], sample_mask)).all()
|
File without changes
|
@@ -4,24 +4,18 @@
|
|
4
4
|
# License: AGPL
|
5
5
|
|
6
6
|
from typing import (
|
7
|
-
|
7
|
+
Any,
|
8
8
|
ClassVar,
|
9
|
-
Dict,
|
10
|
-
List,
|
11
|
-
Set,
|
12
9
|
Union,
|
13
10
|
)
|
14
11
|
|
15
12
|
import nibabel as nib
|
16
13
|
|
17
14
|
from ...pipeline import WorkDirManager
|
15
|
+
from ...typing import Dependencies, ExternalDependencies
|
18
16
|
from ...utils import logger, run_ext_cmd
|
19
17
|
|
20
18
|
|
21
|
-
if TYPE_CHECKING:
|
22
|
-
from nibabel import Nifti1Image
|
23
|
-
|
24
|
-
|
25
19
|
__all__ = ["AFNISmoothing"]
|
26
20
|
|
27
21
|
|
@@ -32,34 +26,34 @@ class AFNISmoothing:
|
|
32
26
|
|
33
27
|
"""
|
34
28
|
|
35
|
-
_EXT_DEPENDENCIES: ClassVar[
|
29
|
+
_EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [
|
36
30
|
{
|
37
31
|
"name": "afni",
|
38
32
|
"commands": ["3dBlurToFWHM"],
|
39
33
|
},
|
40
34
|
]
|
41
35
|
|
42
|
-
_DEPENDENCIES: ClassVar[
|
36
|
+
_DEPENDENCIES: ClassVar[Dependencies] = {"nibabel"}
|
43
37
|
|
44
38
|
def preprocess(
|
45
39
|
self,
|
46
|
-
|
40
|
+
input: dict[str, Any],
|
47
41
|
fwhm: Union[int, float],
|
48
|
-
) ->
|
42
|
+
) -> dict[str, Any]:
|
49
43
|
"""Preprocess using AFNI.
|
50
44
|
|
51
45
|
Parameters
|
52
46
|
----------
|
53
|
-
|
54
|
-
|
47
|
+
input : dict
|
48
|
+
A single input from the Junifer Data object in which to preprocess.
|
55
49
|
fwhm : int or float
|
56
50
|
Smooth until the value. AFNI estimates the smoothing and then
|
57
51
|
applies smoothing to reach ``fwhm``.
|
58
52
|
|
59
53
|
Returns
|
60
54
|
-------
|
61
|
-
|
62
|
-
The
|
55
|
+
dict
|
56
|
+
The ``input`` dictionary with updated values.
|
63
57
|
|
64
58
|
Notes
|
65
59
|
-----
|
@@ -73,18 +67,18 @@ class AFNISmoothing:
|
|
73
67
|
"""
|
74
68
|
logger.info("Smoothing using AFNI")
|
75
69
|
|
76
|
-
# Create
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
70
|
+
# Create element-scoped tempdir so that the output is
|
71
|
+
# available later as nibabel stores file path reference for
|
72
|
+
# loading on computation
|
73
|
+
element_tempdir = WorkDirManager().get_element_tempdir(
|
74
|
+
prefix="afni_smoothing"
|
75
|
+
)
|
82
76
|
|
83
77
|
# Set 3dBlurToFWHM command
|
84
|
-
blur_out_path_prefix =
|
78
|
+
blur_out_path_prefix = element_tempdir / "blur"
|
85
79
|
blur_cmd = [
|
86
80
|
"3dBlurToFWHM",
|
87
|
-
f"-input {
|
81
|
+
f"-input {input['path'].resolve()}",
|
88
82
|
f"-prefix {blur_out_path_prefix.resolve()}",
|
89
83
|
"-automask",
|
90
84
|
f"-FWHM {fwhm}",
|
@@ -92,28 +86,34 @@ class AFNISmoothing:
|
|
92
86
|
# Call 3dBlurToFWHM
|
93
87
|
run_ext_cmd(name="3dBlurToFWHM", cmd=blur_cmd)
|
94
88
|
|
95
|
-
#
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
89
|
+
# Read header to get output suffix
|
90
|
+
header = input["data"].header
|
91
|
+
sform_code = header.get_sform(coded=True)[1]
|
92
|
+
if sform_code == 4:
|
93
|
+
output_suffix = "tlrc"
|
94
|
+
else:
|
95
|
+
output_suffix = "orig"
|
96
|
+
|
101
97
|
# Convert afni to nifti
|
102
|
-
|
103
|
-
element_tempdir / "
|
98
|
+
blur_nifti_out_path = (
|
99
|
+
element_tempdir / "smoothed_data.nii" # needs to be .nii
|
104
100
|
)
|
105
101
|
convert_cmd = [
|
106
102
|
"3dAFNItoNIFTI",
|
107
|
-
f"-prefix {
|
108
|
-
f"{blur_out_path_prefix}+
|
103
|
+
f"-prefix {blur_nifti_out_path.resolve()}",
|
104
|
+
f"{blur_out_path_prefix}+{output_suffix}.BRIK",
|
109
105
|
]
|
110
106
|
# Call 3dAFNItoNIFTI
|
111
107
|
run_ext_cmd(name="3dAFNItoNIFTI", cmd=convert_cmd)
|
112
108
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
109
|
+
logger.debug("Updating smoothed data")
|
110
|
+
input.update(
|
111
|
+
{
|
112
|
+
# Update path to sync with "data"
|
113
|
+
"path": blur_nifti_out_path,
|
114
|
+
# Load nifti
|
115
|
+
"data": nib.load(blur_nifti_out_path),
|
116
|
+
}
|
117
|
+
)
|
118
118
|
|
119
|
-
return
|
119
|
+
return input
|
@@ -4,24 +4,17 @@
|
|
4
4
|
# License: AGPL
|
5
5
|
|
6
6
|
from typing import (
|
7
|
-
|
7
|
+
Any,
|
8
8
|
ClassVar,
|
9
|
-
Dict,
|
10
|
-
List,
|
11
|
-
Set,
|
12
|
-
Union,
|
13
9
|
)
|
14
10
|
|
15
11
|
import nibabel as nib
|
16
12
|
|
17
13
|
from ...pipeline import WorkDirManager
|
14
|
+
from ...typing import Dependencies, ExternalDependencies
|
18
15
|
from ...utils import logger, run_ext_cmd
|
19
16
|
|
20
17
|
|
21
|
-
if TYPE_CHECKING:
|
22
|
-
from nibabel import Nifti1Image
|
23
|
-
|
24
|
-
|
25
18
|
__all__ = ["FSLSmoothing"]
|
26
19
|
|
27
20
|
|
@@ -32,27 +25,27 @@ class FSLSmoothing:
|
|
32
25
|
|
33
26
|
"""
|
34
27
|
|
35
|
-
_EXT_DEPENDENCIES: ClassVar[
|
28
|
+
_EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [
|
36
29
|
{
|
37
30
|
"name": "fsl",
|
38
31
|
"commands": ["susan"],
|
39
32
|
},
|
40
33
|
]
|
41
34
|
|
42
|
-
_DEPENDENCIES: ClassVar[
|
35
|
+
_DEPENDENCIES: ClassVar[Dependencies] = {"nibabel"}
|
43
36
|
|
44
37
|
def preprocess(
|
45
38
|
self,
|
46
|
-
|
39
|
+
input: dict[str, Any],
|
47
40
|
brightness_threshold: float,
|
48
41
|
fwhm: float,
|
49
|
-
) ->
|
42
|
+
) -> dict[str, Any]:
|
50
43
|
"""Preprocess using FSL.
|
51
44
|
|
52
45
|
Parameters
|
53
46
|
----------
|
54
|
-
|
55
|
-
|
47
|
+
input : dict
|
48
|
+
A single input from the Junifer Data object in which to preprocess.
|
56
49
|
brightness_threshold : float
|
57
50
|
Threshold to discriminate between noise and the underlying image.
|
58
51
|
The value should be set greater than the noise level and less than
|
@@ -62,8 +55,8 @@ class FSLSmoothing:
|
|
62
55
|
|
63
56
|
Returns
|
64
57
|
-------
|
65
|
-
|
66
|
-
The
|
58
|
+
dict
|
59
|
+
The ``input`` dictionary with updated values.
|
67
60
|
|
68
61
|
Notes
|
69
62
|
-----
|
@@ -79,24 +72,17 @@ class FSLSmoothing:
|
|
79
72
|
"""
|
80
73
|
logger.info("Smoothing using FSL")
|
81
74
|
|
82
|
-
# Create component-scoped tempdir
|
83
|
-
tempdir = WorkDirManager().get_tempdir(prefix="fsl_smoothing")
|
84
|
-
|
85
|
-
# Save target data to a component-scoped tempfile
|
86
|
-
nifti_in_file_path = tempdir / "input.nii.gz"
|
87
|
-
nib.save(data, nifti_in_file_path)
|
88
|
-
|
89
75
|
# Create element-scoped tempdir so that the output is
|
90
76
|
# available later as nibabel stores file path reference for
|
91
77
|
# loading on computation
|
92
78
|
element_tempdir = WorkDirManager().get_element_tempdir(
|
93
79
|
prefix="fsl_susan"
|
94
80
|
)
|
95
|
-
susan_out_path = element_tempdir / "
|
81
|
+
susan_out_path = element_tempdir / "smoothed_data.nii.gz"
|
96
82
|
# Set susan command
|
97
83
|
susan_cmd = [
|
98
84
|
"susan",
|
99
|
-
f"{
|
85
|
+
f"{input['path'].resolve()}",
|
100
86
|
f"{brightness_threshold}",
|
101
87
|
f"{fwhm}",
|
102
88
|
"3", # dimension
|
@@ -107,10 +93,14 @@ class FSLSmoothing:
|
|
107
93
|
# Call susan
|
108
94
|
run_ext_cmd(name="susan", cmd=susan_cmd)
|
109
95
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
96
|
+
logger.debug("Updating smoothed data")
|
97
|
+
input.update(
|
98
|
+
{
|
99
|
+
# Update path to sync with "data"
|
100
|
+
"path": susan_out_path,
|
101
|
+
# Load nifti
|
102
|
+
"data": nib.load(susan_out_path),
|
103
|
+
}
|
104
|
+
)
|
115
105
|
|
116
|
-
return
|
106
|
+
return input
|
@@ -4,23 +4,21 @@
|
|
4
4
|
# License: AGPL
|
5
5
|
|
6
6
|
from typing import (
|
7
|
-
|
7
|
+
Any,
|
8
8
|
ClassVar,
|
9
9
|
Literal,
|
10
|
-
Set,
|
11
10
|
Union,
|
12
11
|
)
|
13
12
|
|
13
|
+
import nibabel as nib
|
14
14
|
from nilearn import image as nimg
|
15
15
|
from numpy.typing import ArrayLike
|
16
16
|
|
17
|
+
from ...pipeline import WorkDirManager
|
18
|
+
from ...typing import Dependencies
|
17
19
|
from ...utils import logger
|
18
20
|
|
19
21
|
|
20
|
-
if TYPE_CHECKING:
|
21
|
-
from nibabel import Nifti1Image
|
22
|
-
|
23
|
-
|
24
22
|
__all__ = ["NilearnSmoothing"]
|
25
23
|
|
26
24
|
|
@@ -31,19 +29,19 @@ class NilearnSmoothing:
|
|
31
29
|
|
32
30
|
"""
|
33
31
|
|
34
|
-
_DEPENDENCIES: ClassVar[
|
32
|
+
_DEPENDENCIES: ClassVar[Dependencies] = {"nilearn"}
|
35
33
|
|
36
34
|
def preprocess(
|
37
35
|
self,
|
38
|
-
|
36
|
+
input: dict[str, Any],
|
39
37
|
fwhm: Union[int, float, ArrayLike, Literal["fast"], None],
|
40
|
-
) ->
|
38
|
+
) -> dict[str, Any]:
|
41
39
|
"""Preprocess using nilearn.
|
42
40
|
|
43
41
|
Parameters
|
44
42
|
----------
|
45
|
-
|
46
|
-
|
43
|
+
input : dict
|
44
|
+
A single input from the Junifer Data object in which to preprocess.
|
47
45
|
fwhm : scalar, ``numpy.ndarray``, tuple or list of scalar, "fast" or \
|
48
46
|
None
|
49
47
|
Smoothing strength, as a full-width at half maximum, in
|
@@ -61,9 +59,32 @@ class NilearnSmoothing:
|
|
61
59
|
|
62
60
|
Returns
|
63
61
|
-------
|
64
|
-
|
65
|
-
The
|
62
|
+
dict
|
63
|
+
The ``input`` dictionary with updated values.
|
66
64
|
|
67
65
|
"""
|
68
66
|
logger.info("Smoothing using nilearn")
|
69
|
-
|
67
|
+
|
68
|
+
# Create element-scoped tempdir so that the output is
|
69
|
+
# available later as nibabel stores file path reference for
|
70
|
+
# loading on computation
|
71
|
+
element_tempdir = WorkDirManager().get_element_tempdir(
|
72
|
+
prefix="nilearn_smoothing"
|
73
|
+
)
|
74
|
+
|
75
|
+
smoothed_img = nimg.smooth_img(imgs=input["data"], fwhm=fwhm)
|
76
|
+
|
77
|
+
# Save smoothed output
|
78
|
+
smoothed_img_path = element_tempdir / "smoothed_data.nii.gz"
|
79
|
+
nib.save(smoothed_img, smoothed_img_path)
|
80
|
+
|
81
|
+
logger.debug("Updating smoothed data")
|
82
|
+
input.update(
|
83
|
+
{
|
84
|
+
# Update path to sync with "data"
|
85
|
+
"path": smoothed_img_path,
|
86
|
+
"data": smoothed_img,
|
87
|
+
}
|
88
|
+
)
|
89
|
+
|
90
|
+
return input
|
File without changes
|
@@ -3,9 +3,10 @@
|
|
3
3
|
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
4
|
# License: AGPL
|
5
5
|
|
6
|
-
from typing import Any, ClassVar,
|
6
|
+
from typing import Any, ClassVar, Optional, Union
|
7
7
|
|
8
8
|
from ...api.decorators import register_preprocessor
|
9
|
+
from ...typing import ConditionalDependencies
|
9
10
|
from ...utils import logger, raise_error
|
10
11
|
from ..base import BasePreprocessor
|
11
12
|
from ._afni_smoothing import AFNISmoothing
|
@@ -67,7 +68,7 @@ class Smoothing(BasePreprocessor):
|
|
67
68
|
|
68
69
|
"""
|
69
70
|
|
70
|
-
_CONDITIONAL_DEPENDENCIES: ClassVar[
|
71
|
+
_CONDITIONAL_DEPENDENCIES: ClassVar[ConditionalDependencies] = [
|
71
72
|
{
|
72
73
|
"using": "nilearn",
|
73
74
|
"depends_on": NilearnSmoothing,
|
@@ -85,8 +86,8 @@ class Smoothing(BasePreprocessor):
|
|
85
86
|
def __init__(
|
86
87
|
self,
|
87
88
|
using: str,
|
88
|
-
on: Union[
|
89
|
-
smoothing_params: Optional[
|
89
|
+
on: Union[list[str], str],
|
90
|
+
smoothing_params: Optional[dict] = None,
|
90
91
|
) -> None:
|
91
92
|
"""Initialize the class."""
|
92
93
|
# Validate `using` parameter
|
@@ -101,7 +102,7 @@ class Smoothing(BasePreprocessor):
|
|
101
102
|
)
|
102
103
|
super().__init__(on=on)
|
103
104
|
|
104
|
-
def get_valid_inputs(self) ->
|
105
|
+
def get_valid_inputs(self) -> list[str]:
|
105
106
|
"""Get valid data types for input.
|
106
107
|
|
107
108
|
Returns
|
@@ -132,9 +133,9 @@ class Smoothing(BasePreprocessor):
|
|
132
133
|
|
133
134
|
def preprocess(
|
134
135
|
self,
|
135
|
-
input:
|
136
|
-
extra_input: Optional[
|
137
|
-
) ->
|
136
|
+
input: dict[str, Any],
|
137
|
+
extra_input: Optional[dict[str, Any]] = None,
|
138
|
+
) -> tuple[dict[str, Any], Optional[dict[str, dict[str, Any]]]]:
|
138
139
|
"""Preprocess.
|
139
140
|
|
140
141
|
Parameters
|
@@ -163,12 +164,9 @@ class Smoothing(BasePreprocessor):
|
|
163
164
|
elif self.using == "fsl":
|
164
165
|
preprocessor = FSLSmoothing()
|
165
166
|
# Smooth
|
166
|
-
|
167
|
-
|
167
|
+
input = preprocessor.preprocess(
|
168
|
+
input=input,
|
168
169
|
**self.smoothing_params,
|
169
170
|
)
|
170
171
|
|
171
|
-
# Modify target data
|
172
|
-
input["data"] = output
|
173
|
-
|
174
172
|
return input, None
|