junifer 0.0.7.dev332__py3-none-any.whl → 0.0.8__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 +9 -19
- junifer/api/__init__.pyi +17 -2
- junifer/api/functions.py +222 -39
- junifer/api/queue_context/__init__.pyi +11 -3
- junifer/api/queue_context/gnu_parallel_local_adapter.py +81 -120
- junifer/api/queue_context/htcondor_adapter.py +118 -181
- junifer/api/queue_context/queue_context_adapter.py +51 -7
- junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +10 -35
- junifer/api/queue_context/tests/test_htcondor_adapter.py +13 -50
- junifer/api/res/fsl/run_fsl_docker.sh +4 -0
- junifer/api/tests/test_functions.py +863 -36
- junifer/cli/__init__.py +1 -7
- junifer/cli/cli.py +41 -22
- junifer/cli/parser.py +23 -147
- junifer/cli/tests/data/gmd_mean.yaml +6 -6
- junifer/cli/tests/data/gmd_mean_htcondor.yaml +6 -5
- junifer/cli/tests/data/partly_cloudy_agg_mean_tian.yml +1 -0
- junifer/cli/tests/test_cli.py +120 -4
- junifer/cli/tests/test_cli_utils.py +23 -6
- junifer/cli/utils.py +14 -9
- junifer/configs/__init__.py +5 -0
- junifer/configs/__init__.pyi +0 -0
- junifer/configs/juseless/datagrabbers/__init__.pyi +4 -2
- junifer/configs/juseless/datagrabbers/aomic_id1000_vbm.py +18 -24
- junifer/configs/juseless/datagrabbers/camcan_vbm.py +20 -27
- junifer/configs/juseless/datagrabbers/ixi_vbm.py +44 -52
- junifer/configs/juseless/datagrabbers/tests/test_ixi_vbm.py +0 -7
- junifer/configs/juseless/datagrabbers/tests/test_ucla.py +2 -19
- junifer/configs/juseless/datagrabbers/ucla.py +111 -104
- junifer/configs/juseless/datagrabbers/ukb_vbm.py +19 -25
- junifer/configs/py.typed +0 -0
- junifer/conftest.py +63 -24
- junifer/data/_dispatch.py +9 -19
- junifer/data/coordinates/_ants_coordinates_warper.py +4 -1
- junifer/data/coordinates/_coordinates.py +51 -6
- junifer/data/coordinates/_fsl_coordinates_warper.py +4 -1
- junifer/data/coordinates/tests/test_coordinates.py +15 -3
- junifer/data/coordinates/tests/test_coordinates_names.py +37 -0
- junifer/data/maps/_ants_maps_warper.py +18 -12
- junifer/data/maps/_fsl_maps_warper.py +7 -3
- junifer/data/maps/_maps.py +12 -8
- junifer/data/maps/tests/test_maps.py +13 -21
- junifer/data/masks/_ants_mask_warper.py +18 -12
- junifer/data/masks/_fsl_mask_warper.py +7 -3
- junifer/data/masks/_masks.py +15 -12
- junifer/data/masks/tests/test_masks.py +20 -17
- junifer/data/parcellations/_ants_parcellation_warper.py +18 -12
- junifer/data/parcellations/_fsl_parcellation_warper.py +7 -5
- junifer/data/parcellations/_parcellations.py +125 -91
- junifer/data/parcellations/tests/test_parcellations.py +122 -1
- junifer/data/template_spaces.py +117 -50
- junifer/data/tests/test_template_spaces.py +10 -7
- junifer/data/utils.py +10 -8
- junifer/datagrabber/__init__.pyi +38 -5
- junifer/datagrabber/aomic/__init__.pyi +8 -1
- junifer/datagrabber/aomic/_types.py +22 -0
- junifer/datagrabber/aomic/id1000.py +193 -183
- junifer/datagrabber/aomic/piop1.py +215 -259
- junifer/datagrabber/aomic/piop2.py +211 -244
- junifer/datagrabber/aomic/tests/test_id1000.py +70 -53
- junifer/datagrabber/aomic/tests/test_piop1.py +98 -102
- junifer/datagrabber/aomic/tests/test_piop2.py +88 -85
- junifer/datagrabber/base.py +253 -79
- junifer/datagrabber/datalad_base.py +127 -76
- junifer/datagrabber/dmcc13_benchmark.py +204 -289
- junifer/datagrabber/hcp1200/__init__.pyi +7 -2
- junifer/datagrabber/hcp1200/datalad_hcp1200.py +61 -40
- junifer/datagrabber/hcp1200/hcp1200.py +151 -164
- junifer/datagrabber/hcp1200/tests/test_hcp1200.py +116 -128
- junifer/datagrabber/multiple.py +183 -63
- junifer/datagrabber/pattern.py +358 -227
- junifer/datagrabber/pattern_datalad.py +84 -124
- junifer/datagrabber/pattern_validation_mixin.py +22 -50
- junifer/datagrabber/tests/test_base.py +17 -4
- junifer/datagrabber/tests/test_datalad_base.py +20 -27
- junifer/datagrabber/tests/test_dmcc13_benchmark.py +110 -122
- junifer/datagrabber/tests/test_multiple.py +293 -31
- junifer/datagrabber/tests/test_pattern.py +577 -18
- junifer/datagrabber/tests/test_pattern_datalad.py +177 -107
- junifer/datagrabber/tests/test_pattern_validation_mixin.py +9 -51
- junifer/datareader/default.py +8 -5
- junifer/datareader/tests/test_default_reader.py +1 -1
- junifer/external/BrainPrint/.codecov.yml +2 -0
- junifer/external/BrainPrint/.codespellignore +2 -0
- junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/bug-report.md +45 -0
- junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/documentation.md +12 -0
- junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/feature-request.md +24 -0
- junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/questions-help-support.md +28 -0
- junifer/external/BrainPrint/.github/dependabot.yml +6 -0
- junifer/external/BrainPrint/.github/workflows/build.yml +53 -0
- junifer/external/BrainPrint/.github/workflows/code-style.yml +44 -0
- junifer/external/BrainPrint/.github/workflows/doc.yml +65 -0
- junifer/external/BrainPrint/.github/workflows/publish.yml +31 -0
- junifer/external/BrainPrint/.github/workflows/pytest.yml +54 -0
- junifer/external/BrainPrint/.gitignore +123 -0
- junifer/external/BrainPrint/LICENSE +21 -0
- junifer/external/BrainPrint/README.md +108 -0
- junifer/external/BrainPrint/brainprint/cli/__init__.py +11 -0
- junifer/external/BrainPrint/brainprint/cli/help_text.py +169 -0
- junifer/external/BrainPrint/brainprint/cli/parser.py +150 -0
- junifer/external/BrainPrint/brainprint/cli/utils.py +14 -0
- junifer/external/BrainPrint/brainprint/commands/__init__.py +0 -0
- junifer/external/BrainPrint/brainprint/commands/sys_info.py +18 -0
- junifer/external/BrainPrint/brainprint/utils/tests/__init__.py +0 -0
- junifer/external/BrainPrint/brainprint/utils/tests/test_config.py +33 -0
- junifer/external/BrainPrint/doc/Makefile +20 -0
- junifer/external/BrainPrint/doc/_static/.gitkeep +0 -0
- junifer/external/BrainPrint/doc/_templates/autosummary/class.rst +10 -0
- junifer/external/BrainPrint/doc/_templates/autosummary/function.rst +8 -0
- junifer/external/BrainPrint/doc/_templates/autosummary/module.rst +6 -0
- junifer/external/BrainPrint/doc/api/index.rst +11 -0
- junifer/external/BrainPrint/doc/conf.py +272 -0
- junifer/external/BrainPrint/doc/index.rst +140 -0
- junifer/external/BrainPrint/doc/links.inc +36 -0
- junifer/external/BrainPrint/doc/make.bat +35 -0
- junifer/external/BrainPrint/doc/references.bib +23 -0
- junifer/external/BrainPrint/pyproject.toml +170 -0
- junifer/external/BrainPrint/setup.py +3 -0
- junifer/external/__init__.py +5 -0
- junifer/external/__init__.pyi +0 -0
- junifer/external/nilearn/junifer_connectivity_measure.py +95 -39
- junifer/external/nilearn/junifer_nifti_spheres_masker.py +226 -67
- junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +39 -27
- junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +231 -21
- junifer/external/py.typed +0 -0
- junifer/markers/__init__.pyi +6 -3
- junifer/markers/base.py +126 -76
- junifer/markers/brainprint.py +30 -39
- junifer/markers/complexity/__init__.py +20 -3
- junifer/markers/complexity/complexity_base.py +40 -41
- junifer/markers/complexity/hurst_exponent.py +22 -35
- junifer/markers/complexity/multiscale_entropy_auc.py +53 -41
- junifer/markers/complexity/perm_entropy.py +22 -36
- junifer/markers/complexity/range_entropy.py +22 -35
- junifer/markers/complexity/range_entropy_auc.py +27 -36
- junifer/markers/complexity/sample_entropy.py +22 -36
- junifer/markers/complexity/tests/test_complexity_registry.py +48 -0
- junifer/markers/complexity/tests/test_hurst_exponent.py +47 -36
- junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +50 -36
- junifer/markers/complexity/tests/test_perm_entropy.py +48 -36
- junifer/markers/complexity/tests/test_range_entropy.py +47 -36
- junifer/markers/complexity/tests/test_range_entropy_auc.py +47 -36
- junifer/markers/complexity/tests/test_sample_entropy.py +48 -36
- junifer/markers/complexity/tests/test_weighted_perm_entropy.py +50 -36
- junifer/markers/complexity/weighted_perm_entropy.py +22 -36
- junifer/markers/ets_rss.py +35 -31
- junifer/markers/falff/__init__.pyi +7 -1
- junifer/markers/falff/_afni_falff.py +22 -9
- junifer/markers/falff/_junifer_falff.py +47 -31
- junifer/markers/falff/falff_base.py +80 -60
- junifer/markers/falff/falff_maps.py +17 -41
- junifer/markers/falff/falff_parcels.py +26 -51
- junifer/markers/falff/falff_spheres.py +34 -61
- junifer/markers/falff/tests/test_falff_maps.py +20 -23
- junifer/markers/falff/tests/test_falff_mask.py +99 -0
- junifer/markers/falff/tests/test_falff_parcels.py +14 -10
- junifer/markers/falff/tests/test_falff_spheres.py +14 -10
- junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +32 -34
- junifer/markers/functional_connectivity/edge_functional_connectivity_maps.py +12 -25
- junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +19 -34
- junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +24 -44
- junifer/markers/functional_connectivity/functional_connectivity_base.py +50 -40
- junifer/markers/functional_connectivity/functional_connectivity_maps.py +12 -25
- junifer/markers/functional_connectivity/functional_connectivity_parcels.py +19 -34
- junifer/markers/functional_connectivity/functional_connectivity_spheres.py +24 -45
- junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +21 -22
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_maps.py +8 -7
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +8 -4
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +8 -4
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_maps.py +8 -7
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +9 -5
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +8 -12
- junifer/markers/maps_aggregation.py +77 -55
- junifer/markers/parcel_aggregation.py +91 -70
- junifer/markers/reho/__init__.pyi +7 -1
- junifer/markers/reho/_afni_reho.py +23 -14
- junifer/markers/reho/_junifer_reho.py +112 -123
- junifer/markers/reho/reho_base.py +115 -37
- junifer/markers/reho/reho_maps.py +18 -32
- junifer/markers/reho/reho_parcels.py +26 -41
- junifer/markers/reho/reho_spheres.py +33 -54
- junifer/markers/reho/tests/test_junifer_reho.py +178 -0
- junifer/markers/reho/tests/test_reho_maps.py +27 -25
- junifer/markers/reho/tests/test_reho_parcels.py +28 -22
- junifer/markers/reho/tests/test_reho_spheres.py +16 -12
- junifer/markers/sphere_aggregation.py +88 -72
- junifer/markers/temporal_snr/temporal_snr_base.py +32 -30
- junifer/markers/temporal_snr/temporal_snr_maps.py +9 -18
- junifer/markers/temporal_snr/temporal_snr_parcels.py +19 -27
- junifer/markers/temporal_snr/temporal_snr_spheres.py +27 -41
- junifer/markers/temporal_snr/tests/test_temporal_snr_base.py +2 -2
- junifer/markers/temporal_snr/tests/test_temporal_snr_maps.py +17 -22
- junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +11 -3
- junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +9 -9
- junifer/markers/tests/test_brainprint.py +10 -9
- junifer/markers/tests/test_ets_rss.py +7 -3
- junifer/markers/tests/test_lost_regions.py +279 -0
- junifer/markers/tests/test_maps_aggregation.py +67 -114
- junifer/markers/tests/test_marker_utils.py +40 -1
- junifer/markers/tests/test_markers_base.py +275 -6
- junifer/markers/tests/test_parcel_aggregation.py +91 -53
- junifer/markers/tests/test_sphere_aggregation.py +53 -47
- junifer/markers/utils.py +267 -5
- junifer/onthefly/__init__.py +2 -3
- junifer/onthefly/__init__.pyi +4 -0
- junifer/onthefly/_brainprint.py +3 -5
- junifer/onthefly/py.typed +0 -0
- junifer/onthefly/read_transform.py +11 -9
- junifer/onthefly/tests/test_read_transform.py +7 -7
- junifer/pipeline/__init__.pyi +4 -2
- junifer/pipeline/marker_collection.py +14 -10
- junifer/pipeline/pipeline_component_registry.py +25 -6
- junifer/pipeline/pipeline_step_mixin.py +5 -12
- junifer/pipeline/tests/test_data_object_dumper.py +10 -10
- junifer/pipeline/tests/test_marker_collection.py +145 -168
- junifer/pipeline/tests/test_pipeline_component_registry.py +52 -8
- junifer/pipeline/tests/test_pipeline_step_mixin.py +12 -26
- junifer/pipeline/tests/test_update_meta_mixin.py +4 -5
- junifer/pipeline/tests/test_workdir_manager.py +39 -0
- junifer/pipeline/update_meta_mixin.py +13 -10
- junifer/pipeline/utils.py +22 -17
- junifer/pipeline/workdir_manager.py +41 -32
- junifer/preprocess/__init__.pyi +9 -4
- junifer/preprocess/_temporal_filter.py +34 -33
- junifer/preprocess/_temporal_slicer.py +17 -30
- junifer/preprocess/base.py +99 -55
- junifer/preprocess/confounds/__init__.pyi +10 -2
- junifer/preprocess/confounds/fmriprep_confound_remover.py +87 -109
- junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +64 -45
- junifer/preprocess/smoothing/__init__.pyi +2 -2
- junifer/preprocess/smoothing/_afni_smoothing.py +8 -7
- junifer/preprocess/smoothing/_fsl_smoothing.py +6 -4
- junifer/preprocess/smoothing/_nilearn_smoothing.py +7 -5
- junifer/preprocess/smoothing/smoothing.py +59 -40
- junifer/preprocess/smoothing/tests/test_smoothing.py +28 -8
- junifer/preprocess/tests/test_preprocess_base.py +17 -9
- junifer/preprocess/tests/test_temporal_filter.py +37 -16
- junifer/preprocess/tests/test_temporal_slicer.py +12 -12
- junifer/preprocess/warping/__init__.pyi +2 -2
- junifer/preprocess/warping/_ants_warper.py +56 -40
- junifer/preprocess/warping/_fsl_warper.py +49 -36
- junifer/preprocess/warping/_utils.py +106 -0
- junifer/preprocess/warping/space_warper.py +99 -98
- junifer/preprocess/warping/tests/test_space_warper.py +46 -41
- junifer/preprocess/warping/tests/test_warping_utils.py +163 -0
- junifer/stats.py +46 -34
- junifer/storage/__init__.pyi +8 -4
- junifer/storage/base.py +129 -64
- junifer/storage/hdf5.py +307 -199
- junifer/storage/pandas_base.py +46 -24
- junifer/storage/sqlite.py +99 -62
- junifer/storage/tests/data/collected_h5io_fork.hdf5 +0 -0
- junifer/storage/tests/test_hdf5.py +147 -12
- junifer/storage/tests/test_repeated_storage.py +293 -0
- junifer/storage/tests/test_sqlite.py +9 -20
- junifer/storage/tests/test_storage_base.py +18 -21
- junifer/storage/tests/test_utils.py +83 -22
- junifer/storage/utils.py +58 -38
- junifer/testing/__init__.pyi +2 -2
- junifer/testing/datagrabbers.py +480 -44
- junifer/testing/registry.py +12 -0
- junifer/testing/tests/test_adhdtesting_datagrabber.py +24 -0
- junifer/testing/tests/test_oasisvmbtesting_datagrabber.py +5 -0
- junifer/testing/tests/test_partlycloudytesting_datagrabber.py +52 -0
- junifer/testing/tests/test_spmauditory_datagrabber.py +16 -0
- junifer/testing/tests/test_testing_registry.py +31 -0
- junifer/testing/tests/test_testing_utils.py +35 -0
- junifer/testing/tests/test_uclacnpvbmtesting_datagrabber.py +81 -0
- junifer/testing/utils.py +33 -1
- junifer/tests/test_stats.py +1 -5
- junifer/typing/__init__.pyi +2 -0
- junifer/typing/_typing.py +34 -19
- junifer/typing/py.typed +0 -0
- junifer/utils/__init__.pyi +10 -1
- junifer/utils/_config.py +1 -2
- junifer/utils/helpers.py +68 -2
- junifer/utils/logging.py +31 -7
- junifer/utils/tests/test_helpers.py +36 -1
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/METADATA +43 -35
- junifer-0.0.8.dist-info/RECORD +402 -0
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/WHEEL +1 -1
- junifer/cli/tests/test_parser.py +0 -280
- junifer/external/h5io/h5io/__init__.py +0 -15
- junifer/external/h5io/h5io/_h5io.py +0 -767
- junifer/external/h5io/h5io/_version.py +0 -1
- junifer/external/h5io/h5io/chunked_array.py +0 -94
- junifer/external/h5io/h5io/chunked_list.py +0 -65
- junifer/markers/complexity/__init__.pyi +0 -17
- junifer-0.0.7.dev332.dist-info/RECORD +0 -353
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/entry_points.txt +0 -0
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/licenses/AUTHORS.rst +0 -0
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/licenses/LICENSE.md +0 -0
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/top_level.txt +0 -0
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
|
4
4
|
# License: AGPL
|
|
5
5
|
|
|
6
|
-
from typing import
|
|
6
|
+
from typing import Annotated, Any
|
|
7
7
|
|
|
8
8
|
import numpy as np
|
|
9
|
+
from pydantic import BeforeValidator
|
|
9
10
|
|
|
10
11
|
from ...api.decorators import register_marker
|
|
11
|
-
from ...
|
|
12
|
+
from ...datagrabber import DataType
|
|
13
|
+
from ...utils import ensure_list
|
|
14
|
+
from ..base import logger
|
|
12
15
|
from ..parcel_aggregation import ParcelAggregation
|
|
13
16
|
from .reho_base import ReHoBase
|
|
14
17
|
|
|
@@ -25,15 +28,10 @@ class ReHoParcels(ReHoBase):
|
|
|
25
28
|
parcellation : str or list of str
|
|
26
29
|
The name(s) of the parcellation(s) to use.
|
|
27
30
|
See :func:`.list_data` for options.
|
|
28
|
-
using :
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
* "junifer" : Use ``junifer``'s own ReHo implementation
|
|
32
|
-
* "afni" : Use AFNI's ``3dReHo``
|
|
33
|
-
|
|
34
|
-
reho_params : dict, optional
|
|
31
|
+
using : :enum:`.ReHoImpl`
|
|
32
|
+
reho_params : dict or None, optional
|
|
35
33
|
Extra parameters for computing ReHo map as a dictionary (default None).
|
|
36
|
-
If ``using=
|
|
34
|
+
If ``using=ReHoImpl.afni``, then the valid keys are:
|
|
37
35
|
|
|
38
36
|
* ``nneigh`` : {7, 19, 27}, optional (default 27)
|
|
39
37
|
Number of voxels in the neighbourhood, inclusive. Can be:
|
|
@@ -63,7 +61,7 @@ class ReHoParcels(ReHoBase):
|
|
|
63
61
|
The number of voxels for +/- z-axis of cuboidal volumes
|
|
64
62
|
(default None).
|
|
65
63
|
|
|
66
|
-
else if ``using=
|
|
64
|
+
else if ``using=ReHoImpl.junifer``, then the valid keys are:
|
|
67
65
|
|
|
68
66
|
* ``nneigh`` : {7, 19, 27, 125}, optional (default 27)
|
|
69
67
|
Number of voxels in the neighbourhood, inclusive. Can be:
|
|
@@ -74,43 +72,28 @@ class ReHoParcels(ReHoBase):
|
|
|
74
72
|
* 125 : for 5x5 cuboidal volume
|
|
75
73
|
|
|
76
74
|
agg_method : str, optional
|
|
77
|
-
The
|
|
78
|
-
:func:`.get_aggfunc_by_name`
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
75
|
+
The aggregation function to use.
|
|
76
|
+
See :func:`.get_aggfunc_by_name` for options
|
|
77
|
+
(default "mean").
|
|
78
|
+
agg_method_params : dict or None, optional
|
|
79
|
+
The parameters to pass to the aggregation function.
|
|
80
|
+
See :func:`.get_aggfunc_by_name` for options (default None).
|
|
81
|
+
masks : str, dict, list of them or None, optional
|
|
83
82
|
The specification of the masks to apply to regions before extracting
|
|
84
83
|
signals. Check :ref:`Using Masks <using_masks>` for more details.
|
|
85
84
|
If None, will not apply any mask (default None).
|
|
86
|
-
name : str, optional
|
|
87
|
-
The name of the marker.
|
|
88
|
-
(default None).
|
|
85
|
+
name : str or None, optional
|
|
86
|
+
The name of the marker.
|
|
87
|
+
If None, it will use the class name (default None).
|
|
89
88
|
|
|
90
89
|
"""
|
|
91
90
|
|
|
92
|
-
|
|
93
|
-
self,
|
|
94
|
-
parcellation: Union[str, list[str]],
|
|
95
|
-
using: str,
|
|
96
|
-
reho_params: Optional[dict] = None,
|
|
97
|
-
agg_method: str = "mean",
|
|
98
|
-
agg_method_params: Optional[dict] = None,
|
|
99
|
-
masks: Union[str, dict, list[Union[dict, str]], None] = None,
|
|
100
|
-
name: Optional[str] = None,
|
|
101
|
-
) -> None:
|
|
102
|
-
# Superclass init first to validate `using` parameter
|
|
103
|
-
super().__init__(using=using, name=name)
|
|
104
|
-
self.parcellation = parcellation
|
|
105
|
-
self.reho_params = reho_params
|
|
106
|
-
self.agg_method = agg_method
|
|
107
|
-
self.agg_method_params = agg_method_params
|
|
108
|
-
self.masks = masks
|
|
91
|
+
parcellation: Annotated[str | list[str], BeforeValidator(ensure_list)]
|
|
109
92
|
|
|
110
93
|
def compute(
|
|
111
94
|
self,
|
|
112
95
|
input: dict[str, Any],
|
|
113
|
-
extra_input:
|
|
96
|
+
extra_input: dict[str, Any] | None = None,
|
|
114
97
|
) -> dict[str, Any]:
|
|
115
98
|
"""Compute.
|
|
116
99
|
|
|
@@ -142,10 +125,12 @@ class ReHoParcels(ReHoBase):
|
|
|
142
125
|
# transformation to native space.
|
|
143
126
|
if self.reho_params is not None:
|
|
144
127
|
reho_map, reho_file_path = self._compute(
|
|
145
|
-
input_data=input, **self.reho_params
|
|
128
|
+
input_data=input, extra_input=extra_input, **self.reho_params
|
|
146
129
|
)
|
|
147
130
|
else:
|
|
148
|
-
reho_map, reho_file_path = self._compute(
|
|
131
|
+
reho_map, reho_file_path = self._compute(
|
|
132
|
+
input_data=input, extra_input=extra_input
|
|
133
|
+
)
|
|
149
134
|
|
|
150
135
|
# Perform aggregation on reho map
|
|
151
136
|
aggregation_input = dict(input.items())
|
|
@@ -156,7 +141,7 @@ class ReHoParcels(ReHoBase):
|
|
|
156
141
|
method=self.agg_method,
|
|
157
142
|
method_params=self.agg_method_params,
|
|
158
143
|
masks=self.masks,
|
|
159
|
-
on=
|
|
144
|
+
on=DataType.BOLD,
|
|
160
145
|
).compute(
|
|
161
146
|
input=aggregation_input,
|
|
162
147
|
extra_input=extra_input,
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
|
4
4
|
# License: AGPL
|
|
5
5
|
|
|
6
|
-
from typing import Any,
|
|
6
|
+
from typing import Any, Literal
|
|
7
7
|
|
|
8
8
|
import numpy as np
|
|
9
|
+
from pydantic import PositiveFloat
|
|
9
10
|
|
|
10
11
|
from ...api.decorators import register_marker
|
|
11
|
-
from ...
|
|
12
|
+
from ...datagrabber import DataType
|
|
13
|
+
from ..base import logger
|
|
12
14
|
from ..sphere_aggregation import SphereAggregation
|
|
13
15
|
from .reho_base import ReHoBase
|
|
14
16
|
|
|
@@ -25,26 +27,18 @@ class ReHoSpheres(ReHoBase):
|
|
|
25
27
|
coords : str
|
|
26
28
|
The name of the coordinates list to use.
|
|
27
29
|
See :func:`.list_data` for options.
|
|
28
|
-
using :
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
radius : float, optional
|
|
35
|
-
The radius of the sphere in millimeters. If None, the signal will be
|
|
36
|
-
extracted from a single voxel. See
|
|
37
|
-
:class:`nilearn.maskers.NiftiSpheresMasker` for more information
|
|
30
|
+
using : :enum:`.ReHoImpl`
|
|
31
|
+
radius : ``zero`` or positive float or None, optional
|
|
32
|
+
The radius of the sphere in millimetres.
|
|
33
|
+
If None, the signal will be extracted from a single voxel.
|
|
34
|
+
See :class:`.JuniferNiftiSpheresMasker` for more information
|
|
38
35
|
(default None).
|
|
39
36
|
allow_overlap : bool, optional
|
|
40
|
-
Whether to allow overlapping spheres.
|
|
41
|
-
the spheres overlap (default
|
|
42
|
-
|
|
43
|
-
Whether to use AFNI for computing. If None, will use AFNI only
|
|
44
|
-
if available (default None).
|
|
45
|
-
reho_params : dict, optional
|
|
37
|
+
Whether to allow overlapping spheres.
|
|
38
|
+
If False, an error is raised if the spheres overlap (default False).
|
|
39
|
+
reho_params : dict or None, optional
|
|
46
40
|
Extra parameters for computing ReHo map as a dictionary (default None).
|
|
47
|
-
If ``using=
|
|
41
|
+
If ``using=ReHoImpl.afni``, then the valid keys are:
|
|
48
42
|
|
|
49
43
|
* ``nneigh`` : {7, 19, 27}, optional (default 27)
|
|
50
44
|
Number of voxels in the neighbourhood, inclusive. Can be:
|
|
@@ -74,7 +68,7 @@ class ReHoSpheres(ReHoBase):
|
|
|
74
68
|
The number of voxels for +/- z-axis of cuboidal volumes
|
|
75
69
|
(default None).
|
|
76
70
|
|
|
77
|
-
else if ``using=
|
|
71
|
+
else if ``using=ReHoImpl.junifer``, then the valid keys are:
|
|
78
72
|
|
|
79
73
|
* ``nneigh`` : {7, 19, 27, 125}, optional (default 27)
|
|
80
74
|
Number of voxels in the neighbourhood, inclusive. Can be:
|
|
@@ -85,47 +79,30 @@ class ReHoSpheres(ReHoBase):
|
|
|
85
79
|
* 125 : for 5x5 cuboidal volume
|
|
86
80
|
|
|
87
81
|
agg_method : str, optional
|
|
88
|
-
The aggregation
|
|
89
|
-
See :func:`.get_aggfunc_by_name` for
|
|
90
|
-
(default
|
|
91
|
-
agg_method_params : dict, optional
|
|
92
|
-
The parameters to pass to the aggregation
|
|
93
|
-
|
|
82
|
+
The aggregation function to use.
|
|
83
|
+
See :func:`.get_aggfunc_by_name` for options
|
|
84
|
+
(default "mean").
|
|
85
|
+
agg_method_params : dict or None, optional
|
|
86
|
+
The parameters to pass to the aggregation function.
|
|
87
|
+
See :func:`.get_aggfunc_by_name` for options (default None).
|
|
88
|
+
masks : str, dict, list of them or None, optional
|
|
94
89
|
The specification of the masks to apply to regions before extracting
|
|
95
90
|
signals. Check :ref:`Using Masks <using_masks>` for more details.
|
|
96
91
|
If None, will not apply any mask (default None).
|
|
97
|
-
name : str, optional
|
|
98
|
-
The name of the marker.
|
|
99
|
-
(default None).
|
|
92
|
+
name : str or None, optional
|
|
93
|
+
The name of the marker.
|
|
94
|
+
If None, it will use the class name (default None).
|
|
100
95
|
|
|
101
96
|
"""
|
|
102
97
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
using: str,
|
|
107
|
-
radius: Optional[float] = None,
|
|
108
|
-
allow_overlap: bool = False,
|
|
109
|
-
reho_params: Optional[dict] = None,
|
|
110
|
-
agg_method: str = "mean",
|
|
111
|
-
agg_method_params: Optional[dict] = None,
|
|
112
|
-
masks: Union[str, dict, list[Union[dict, str]], None] = None,
|
|
113
|
-
name: Optional[str] = None,
|
|
114
|
-
) -> None:
|
|
115
|
-
# Superclass init first to validate `using` parameter
|
|
116
|
-
super().__init__(using=using, name=name)
|
|
117
|
-
self.coords = coords
|
|
118
|
-
self.radius = radius
|
|
119
|
-
self.allow_overlap = allow_overlap
|
|
120
|
-
self.reho_params = reho_params
|
|
121
|
-
self.agg_method = agg_method
|
|
122
|
-
self.agg_method_params = agg_method_params
|
|
123
|
-
self.masks = masks
|
|
98
|
+
coords: str
|
|
99
|
+
radius: Literal[0] | PositiveFloat | None = None
|
|
100
|
+
allow_overlap: bool = False
|
|
124
101
|
|
|
125
102
|
def compute(
|
|
126
103
|
self,
|
|
127
104
|
input: dict[str, Any],
|
|
128
|
-
extra_input:
|
|
105
|
+
extra_input: dict[str, Any] | None = None,
|
|
129
106
|
) -> dict[str, Any]:
|
|
130
107
|
"""Compute.
|
|
131
108
|
|
|
@@ -157,10 +134,12 @@ class ReHoSpheres(ReHoBase):
|
|
|
157
134
|
# transformation to native space.
|
|
158
135
|
if self.reho_params is not None:
|
|
159
136
|
reho_map, reho_file_path = self._compute(
|
|
160
|
-
input_data=input, **self.reho_params
|
|
137
|
+
input_data=input, extra_input=extra_input, **self.reho_params
|
|
161
138
|
)
|
|
162
139
|
else:
|
|
163
|
-
reho_map, reho_file_path = self._compute(
|
|
140
|
+
reho_map, reho_file_path = self._compute(
|
|
141
|
+
input_data=input, extra_input=extra_input
|
|
142
|
+
)
|
|
164
143
|
|
|
165
144
|
# Perform aggregation on reho map
|
|
166
145
|
aggregation_input = dict(input.items())
|
|
@@ -173,7 +152,7 @@ class ReHoSpheres(ReHoBase):
|
|
|
173
152
|
method=self.agg_method,
|
|
174
153
|
method_params=self.agg_method_params,
|
|
175
154
|
masks=self.masks,
|
|
176
|
-
on=
|
|
155
|
+
on=DataType.BOLD,
|
|
177
156
|
).compute(input=aggregation_input, extra_input=extra_input)
|
|
178
157
|
|
|
179
158
|
return {
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""Provide tests for ReHo computation using junifer."""
|
|
2
|
+
|
|
3
|
+
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
|
4
|
+
# License: AGPL
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import nibabel as nib
|
|
9
|
+
import numpy as np
|
|
10
|
+
import pytest
|
|
11
|
+
import scipy as sp
|
|
12
|
+
from numpy.testing import assert_allclose, assert_array_equal
|
|
13
|
+
|
|
14
|
+
from junifer.markers.reho._afni_reho import AFNIReHo
|
|
15
|
+
from junifer.markers.reho._junifer_reho import JuniferReHo, _rank_with_ties
|
|
16
|
+
from junifer.pipeline import WorkDirManager
|
|
17
|
+
from junifer.pipeline.utils import _check_afni
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _tied_rank_corrections(ranks: np.ndarray) -> np.ndarray:
|
|
21
|
+
"""Compute tied rank corrections one time series at a time."""
|
|
22
|
+
out = np.zeros(ranks.shape[:-1])
|
|
23
|
+
for idx in np.ndindex(ranks.shape[:-1]):
|
|
24
|
+
_, tie_count = np.unique(ranks[idx], return_counts=True)
|
|
25
|
+
out[idx] = np.sum(tie_count**3 - tie_count)
|
|
26
|
+
return out
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@pytest.mark.parametrize(
|
|
30
|
+
"shape, scale",
|
|
31
|
+
[
|
|
32
|
+
((4, 3, 2, 50), 3), # many ties
|
|
33
|
+
((3, 3, 3, 30), 100), # few ties
|
|
34
|
+
((2, 2, 2, 10), 0), # all values tied
|
|
35
|
+
],
|
|
36
|
+
)
|
|
37
|
+
def test_rank_with_ties(shape: tuple[int, ...], scale: float) -> None:
|
|
38
|
+
"""Test ranking with ties against scipy.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
shape : tuple of int
|
|
43
|
+
The shape of the data.
|
|
44
|
+
scale : float
|
|
45
|
+
The scale of the data before rounding.
|
|
46
|
+
|
|
47
|
+
"""
|
|
48
|
+
data = np.round(np.random.default_rng(0).normal(size=shape) * scale)
|
|
49
|
+
ranks, tied_rank_corrections = _rank_with_ties(data)
|
|
50
|
+
expected_ranks = sp.stats.rankdata(data, axis=-1)
|
|
51
|
+
assert_array_equal(ranks, expected_ranks)
|
|
52
|
+
assert_array_equal(
|
|
53
|
+
tied_rank_corrections, _tied_rank_corrections(expected_ranks)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_rank_with_ties_nan() -> None:
|
|
58
|
+
"""Test NaN propagates to the whole time series."""
|
|
59
|
+
data = np.array([[1.0, np.nan, 2.0], [1.0, 3.0, 2.0]])
|
|
60
|
+
ranks, tied_rank_corrections = _rank_with_ties(data)
|
|
61
|
+
assert np.isnan(ranks[0]).all()
|
|
62
|
+
assert np.isnan(tied_rank_corrections[0])
|
|
63
|
+
assert_array_equal(ranks[1], [1, 3, 2])
|
|
64
|
+
assert tied_rank_corrections[1] == 0
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _save(data: np.ndarray, path: Path) -> Path:
|
|
68
|
+
"""Save data as NIfTI."""
|
|
69
|
+
nib.save(nib.Nifti1Image(data, np.eye(4)), path)
|
|
70
|
+
return path
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_JuniferReHo_nan(tmp_path: Path) -> None:
|
|
74
|
+
"""Test NaN time series do not give valid ReHo values.
|
|
75
|
+
|
|
76
|
+
Parameters
|
|
77
|
+
----------
|
|
78
|
+
tmp_path : pathlib.Path
|
|
79
|
+
The path to the test directory.
|
|
80
|
+
|
|
81
|
+
"""
|
|
82
|
+
WorkDirManager().workdir = tmp_path
|
|
83
|
+
data = np.random.default_rng(0).normal(size=(7, 7, 7, 20))
|
|
84
|
+
data[3, 3, 3, 5] = np.nan
|
|
85
|
+
bold_path = _save(data.astype(np.float32), tmp_path / "bold_nan.nii")
|
|
86
|
+
mask_path = _save(np.ones((7, 7, 7), dtype=np.uint8), tmp_path / "m.nii")
|
|
87
|
+
|
|
88
|
+
# With a mask including the NaN voxel, every neighbourhood with it is NaN
|
|
89
|
+
reho = JuniferReHo().compute(bold_path, mask_path=mask_path)[0]
|
|
90
|
+
reho = reho.get_fdata()
|
|
91
|
+
assert np.isnan(reho[2:5, 2:5, 2:5]).all()
|
|
92
|
+
reho[2:5, 2:5, 2:5] = 0
|
|
93
|
+
assert np.isfinite(reho).all()
|
|
94
|
+
|
|
95
|
+
# Without mask, the NaN voxel is excluded as AFNI's 3dReHo does
|
|
96
|
+
reho = JuniferReHo().compute(bold_path)[0].get_fdata()
|
|
97
|
+
assert np.isfinite(reho).all()
|
|
98
|
+
assert reho[3, 3, 3] == 0
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def test_JuniferReHo_mask(tmp_path: Path) -> None:
|
|
102
|
+
"""Test ReHo is restricted to the mask.
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
tmp_path : pathlib.Path
|
|
107
|
+
The path to the test directory.
|
|
108
|
+
|
|
109
|
+
"""
|
|
110
|
+
WorkDirManager().workdir = tmp_path
|
|
111
|
+
data = np.random.default_rng(0).normal(size=(7, 7, 7, 20))
|
|
112
|
+
bold_path = _save(data.astype(np.float32), tmp_path / "bold.nii")
|
|
113
|
+
mask = np.ones((7, 7, 7), dtype=np.uint8)
|
|
114
|
+
mask[:3] = 0
|
|
115
|
+
mask_path = _save(mask, tmp_path / "mask.nii")
|
|
116
|
+
|
|
117
|
+
masked = JuniferReHo().compute(bold_path, mask_path=mask_path)[0]
|
|
118
|
+
masked = masked.get_fdata()
|
|
119
|
+
unmasked = JuniferReHo().compute(bold_path)[0].get_fdata()
|
|
120
|
+
# Outside the mask is 0
|
|
121
|
+
assert (masked[:3] == 0).all()
|
|
122
|
+
# Next to the mask boundary, neighbours outside the mask are excluded
|
|
123
|
+
assert not np.allclose(masked[3, 1:-1, 1:-1], unmasked[3, 1:-1, 1:-1])
|
|
124
|
+
# Far from the mask boundary, nothing changes
|
|
125
|
+
assert_array_equal(masked[4:-1, 1:-1, 1:-1], unmasked[4:-1, 1:-1, 1:-1])
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@pytest.mark.external
|
|
129
|
+
@pytest.mark.skipif(
|
|
130
|
+
_check_afni() is False, reason="requires AFNI to be in PATH"
|
|
131
|
+
)
|
|
132
|
+
@pytest.mark.parametrize("nneigh", [7, 19, 27])
|
|
133
|
+
@pytest.mark.parametrize("use_mask", [False, True])
|
|
134
|
+
def test_JuniferReHo_vs_AFNI(
|
|
135
|
+
tmp_path: Path, nneigh: int, use_mask: bool
|
|
136
|
+
) -> None:
|
|
137
|
+
"""Test junifer and AFNI give the same ReHo map.
|
|
138
|
+
|
|
139
|
+
The data covers the edges of the volume, fully tied neighbourhoods (the
|
|
140
|
+
denominator of KCC is 0), voxels with all-zero time series and ties.
|
|
141
|
+
|
|
142
|
+
Parameters
|
|
143
|
+
----------
|
|
144
|
+
tmp_path : pathlib.Path
|
|
145
|
+
The path to the test directory.
|
|
146
|
+
nneigh : int
|
|
147
|
+
The number of voxels in the neighbourhood.
|
|
148
|
+
use_mask : bool
|
|
149
|
+
Whether to use a mask.
|
|
150
|
+
|
|
151
|
+
"""
|
|
152
|
+
WorkDirManager().workdir = tmp_path
|
|
153
|
+
data = np.round(
|
|
154
|
+
np.random.default_rng(0).normal(size=(9, 8, 7, 25)) * 3
|
|
155
|
+
).astype(np.float32)
|
|
156
|
+
# Constant time series: fully tied neighbourhoods
|
|
157
|
+
data[:4, :4, :4] = 5
|
|
158
|
+
# All-zero time series: outside AFNI's implicit mask
|
|
159
|
+
data[6:, 5:, 4:] = 0
|
|
160
|
+
bold_path = _save(data, tmp_path / "bold.nii")
|
|
161
|
+
mask_path = None
|
|
162
|
+
if use_mask:
|
|
163
|
+
mask = np.ones(data.shape[:3], dtype=np.uint8)
|
|
164
|
+
mask[:, :, 0] = 0
|
|
165
|
+
mask[4, 4, 3] = 0
|
|
166
|
+
mask_path = _save(mask, tmp_path / "mask.nii")
|
|
167
|
+
|
|
168
|
+
junifer_reho = JuniferReHo().compute(
|
|
169
|
+
bold_path, nneigh=nneigh, mask_path=mask_path
|
|
170
|
+
)[0]
|
|
171
|
+
afni_reho = AFNIReHo().compute(
|
|
172
|
+
bold_path, nneigh=nneigh, mask_path=mask_path
|
|
173
|
+
)[0]
|
|
174
|
+
assert_allclose(
|
|
175
|
+
junifer_reho.get_fdata(),
|
|
176
|
+
np.squeeze(afni_reho.get_fdata()),
|
|
177
|
+
atol=1e-6,
|
|
178
|
+
)
|
|
@@ -7,20 +7,23 @@ import logging
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
9
|
import pytest
|
|
10
|
-
|
|
10
|
+
from numpy.testing import assert_allclose
|
|
11
11
|
|
|
12
|
-
from junifer.datagrabber import
|
|
12
|
+
from junifer.datagrabber import DataType
|
|
13
13
|
from junifer.datareader import DefaultDataReader
|
|
14
|
-
from junifer.markers import ReHoMaps
|
|
14
|
+
from junifer.markers import ReHoImpl, ReHoMaps
|
|
15
15
|
from junifer.pipeline import WorkDirManager
|
|
16
16
|
from junifer.pipeline.utils import _check_afni
|
|
17
17
|
from junifer.storage import HDF5FeatureStorage
|
|
18
|
+
from junifer.testing.datagrabbers import ADHDTestingDataGrabber
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
pytestmark = pytest.mark.external
|
|
18
22
|
|
|
19
23
|
|
|
20
24
|
def test_ReHoMaps(
|
|
21
25
|
caplog: pytest.LogCaptureFixture,
|
|
22
26
|
tmp_path: Path,
|
|
23
|
-
maps_datagrabber: PatternDataladDataGrabber,
|
|
24
27
|
) -> None:
|
|
25
28
|
"""Test ReHoMaps.
|
|
26
29
|
|
|
@@ -30,26 +33,24 @@ def test_ReHoMaps(
|
|
|
30
33
|
The pytest.LogCaptureFixture object.
|
|
31
34
|
tmp_path : pathlib.Path
|
|
32
35
|
The path to the test directory.
|
|
33
|
-
maps_datagrabber : PatternDataladDataGrabber
|
|
34
|
-
The testing PatternDataladDataGrabber, as fixture.
|
|
35
36
|
|
|
36
37
|
"""
|
|
37
38
|
# Update workdir to current test's tmp_path
|
|
38
39
|
WorkDirManager().workdir = tmp_path
|
|
39
40
|
|
|
40
41
|
with caplog.at_level(logging.DEBUG):
|
|
41
|
-
with
|
|
42
|
-
element = dg[
|
|
42
|
+
with ADHDTestingDataGrabber() as dg:
|
|
43
|
+
element = dg["sub-01"]
|
|
43
44
|
element_data = DefaultDataReader().fit_transform(element)
|
|
44
45
|
|
|
45
46
|
# Initialize marker
|
|
46
47
|
marker = ReHoMaps(
|
|
47
48
|
maps="Smith_rsn_10",
|
|
48
|
-
using=
|
|
49
|
+
using=ReHoImpl.junifer,
|
|
49
50
|
)
|
|
50
51
|
# Check correct output
|
|
51
52
|
assert "vector" == marker.storage_type(
|
|
52
|
-
input_type=
|
|
53
|
+
input_type=DataType.BOLD, output_feature="reho"
|
|
53
54
|
)
|
|
54
55
|
|
|
55
56
|
# Fit transform marker on data
|
|
@@ -75,7 +76,7 @@ def test_ReHoMaps(
|
|
|
75
76
|
# Reset log capture
|
|
76
77
|
caplog.clear()
|
|
77
78
|
# Initialize storage
|
|
78
|
-
storage = HDF5FeatureStorage(tmp_path / "reho_maps.hdf5")
|
|
79
|
+
storage = HDF5FeatureStorage(uri=tmp_path / "reho_maps.hdf5")
|
|
79
80
|
# Fit transform marker on data with storage
|
|
80
81
|
marker.fit_transform(
|
|
81
82
|
input=element_data,
|
|
@@ -93,43 +94,44 @@ def test_ReHoMaps(
|
|
|
93
94
|
@pytest.mark.skipif(
|
|
94
95
|
_check_afni() is False, reason="requires AFNI to be in PATH"
|
|
95
96
|
)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
) -> None:
|
|
97
|
+
@pytest.mark.parametrize("masks", [None, "compute_brain_mask"])
|
|
98
|
+
def test_ReHoMaps_comparison(tmp_path: Path, masks: str | None) -> None:
|
|
99
99
|
"""Test ReHoMaps implementation comparison.
|
|
100
100
|
|
|
101
101
|
Parameters
|
|
102
102
|
----------
|
|
103
103
|
tmp_path : pathlib.Path
|
|
104
104
|
The path to the test directory.
|
|
105
|
-
|
|
106
|
-
The
|
|
105
|
+
masks : str or None
|
|
106
|
+
The masks to use.
|
|
107
107
|
|
|
108
108
|
"""
|
|
109
109
|
# Update workdir to current test's tmp_path
|
|
110
110
|
WorkDirManager().workdir = tmp_path
|
|
111
111
|
|
|
112
|
-
with
|
|
113
|
-
element = dg[
|
|
112
|
+
with ADHDTestingDataGrabber() as dg:
|
|
113
|
+
element = dg["sub-01"]
|
|
114
114
|
element_data = DefaultDataReader().fit_transform(element)
|
|
115
115
|
|
|
116
116
|
# Initialize marker
|
|
117
|
-
junifer_marker = ReHoMaps(
|
|
117
|
+
junifer_marker = ReHoMaps(
|
|
118
|
+
maps="Smith_rsn_10", using=ReHoImpl.junifer, masks=masks
|
|
119
|
+
)
|
|
118
120
|
# Fit transform marker on data
|
|
119
121
|
junifer_output = junifer_marker.fit_transform(element_data)
|
|
120
122
|
# Get BOLD output
|
|
121
123
|
junifer_output_bold = junifer_output["BOLD"]["reho"]
|
|
122
124
|
|
|
123
125
|
# Initialize marker
|
|
124
|
-
afni_marker = ReHoMaps(
|
|
126
|
+
afni_marker = ReHoMaps(
|
|
127
|
+
maps="Smith_rsn_10", using=ReHoImpl.afni, masks=masks
|
|
128
|
+
)
|
|
125
129
|
# Fit transform marker on data
|
|
126
130
|
afni_output = afni_marker.fit_transform(element_data)
|
|
127
131
|
# Get BOLD output
|
|
128
132
|
afni_output_bold = afni_output["BOLD"]["reho"]
|
|
129
133
|
|
|
130
|
-
#
|
|
131
|
-
|
|
132
|
-
junifer_output_bold["data"]
|
|
133
|
-
afni_output_bold["data"].flatten(),
|
|
134
|
+
# Both implementations should give the same results
|
|
135
|
+
assert_allclose(
|
|
136
|
+
junifer_output_bold["data"], afni_output_bold["data"], atol=1e-6
|
|
134
137
|
)
|
|
135
|
-
assert r >= 0.2 # this is very bad, but they differ...
|