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,22 +3,19 @@
|
|
|
3
3
|
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
|
4
4
|
# License: AGPL
|
|
5
5
|
|
|
6
|
-
from
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from typing import TYPE_CHECKING, Union
|
|
7
8
|
|
|
8
9
|
import numpy as np
|
|
9
10
|
from nilearn import image, masking
|
|
10
|
-
from nilearn._utils.
|
|
11
|
-
from nilearn.
|
|
12
|
-
from nilearn._utils.niimg_conversions import (
|
|
13
|
-
check_niimg_3d,
|
|
14
|
-
check_niimg_4d,
|
|
15
|
-
safe_get_data,
|
|
16
|
-
)
|
|
11
|
+
from nilearn._utils.niimg import img_data_dtype, safe_get_data
|
|
12
|
+
from nilearn.image import check_niimg_3d, check_niimg_4d, load_img
|
|
17
13
|
from nilearn.maskers import NiftiSpheresMasker
|
|
18
|
-
from nilearn.maskers.base_masker import
|
|
14
|
+
from nilearn.maskers.base_masker import filter_and_extract
|
|
19
15
|
from sklearn import neighbors
|
|
16
|
+
from sklearn.utils.validation import check_is_fitted
|
|
20
17
|
|
|
21
|
-
from ...utils import raise_error, warn_with_log
|
|
18
|
+
from ...utils import config, raise_error, warn_with_log
|
|
22
19
|
|
|
23
20
|
|
|
24
21
|
if TYPE_CHECKING:
|
|
@@ -27,6 +24,7 @@ if TYPE_CHECKING:
|
|
|
27
24
|
from nibabel import Nifti1Image, Nifti2Image
|
|
28
25
|
from numpy.typing import ArrayLike, DTypeLike
|
|
29
26
|
from pandas import DataFrame
|
|
27
|
+
from scipy.sparse import lil_matrix
|
|
30
28
|
|
|
31
29
|
|
|
32
30
|
__all__ = ["JuniferNiftiSpheresMasker"]
|
|
@@ -65,14 +63,40 @@ __all__ = ["JuniferNiftiSpheresMasker"]
|
|
|
65
63
|
# DAMAGE.
|
|
66
64
|
|
|
67
65
|
|
|
68
|
-
def
|
|
66
|
+
def _get_chunk_size() -> int:
|
|
67
|
+
"""Get the number of volumes to read at once.
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
int
|
|
72
|
+
The value of ``markers.spheres.chunksize`` (default 100).
|
|
73
|
+
|
|
74
|
+
Raises
|
|
75
|
+
------
|
|
76
|
+
ValueError
|
|
77
|
+
If ``markers.spheres.chunksize`` is not a positive integer.
|
|
78
|
+
|
|
79
|
+
"""
|
|
80
|
+
chunk_size = config.get("markers.spheres.chunksize", 100)
|
|
81
|
+
if (
|
|
82
|
+
isinstance(chunk_size, bool)
|
|
83
|
+
or not isinstance(chunk_size, int)
|
|
84
|
+
or chunk_size < 1
|
|
85
|
+
):
|
|
86
|
+
raise_error(
|
|
87
|
+
"`markers.spheres.chunksize` must be a positive integer, "
|
|
88
|
+
f"but is {chunk_size}"
|
|
89
|
+
)
|
|
90
|
+
return chunk_size
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _get_sphere_voxels(
|
|
69
94
|
seeds, niimg, radius, allow_overlap, mask_img=None
|
|
70
|
-
):
|
|
71
|
-
"""
|
|
95
|
+
) -> tuple[np.ndarray, "lil_matrix"]:
|
|
96
|
+
"""Get the voxels of the spheres at given seed locations.
|
|
72
97
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
target_shape space.
|
|
98
|
+
The voxels only depend on the geometry (and the mask), so the data of
|
|
99
|
+
``niimg`` is not read.
|
|
76
100
|
|
|
77
101
|
Parameters
|
|
78
102
|
----------
|
|
@@ -82,8 +106,6 @@ def _apply_mask_and_get_affinity(
|
|
|
82
106
|
niimg : 3D/4D Niimg-like object
|
|
83
107
|
See :ref:`extracting_data`.
|
|
84
108
|
Images to process.
|
|
85
|
-
If a 3D niimg is provided, a singleton dimension will be added to
|
|
86
|
-
the output to represent the single scan in the niimg.
|
|
87
109
|
radius : float
|
|
88
110
|
Indicates, in millimeters, the radius for the sphere around the seed.
|
|
89
111
|
allow_overlap : boolean
|
|
@@ -95,9 +117,9 @@ def _apply_mask_and_get_affinity(
|
|
|
95
117
|
|
|
96
118
|
Returns
|
|
97
119
|
-------
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
120
|
+
voxels : 1D numpy.ndarray
|
|
121
|
+
The flat (C order) index in ``niimg`` of each voxel (column of ``A``):
|
|
122
|
+
the voxels in the mask or all the voxels if there is no mask.
|
|
101
123
|
A : scipy.sparse.lil_matrix
|
|
102
124
|
Contains the boolean indices for each sphere.
|
|
103
125
|
shape: (number of seeds, number of voxels)
|
|
@@ -105,54 +127,38 @@ def _apply_mask_and_get_affinity(
|
|
|
105
127
|
Raises
|
|
106
128
|
------
|
|
107
129
|
ValueError
|
|
108
|
-
If ``niimg`` and ``mask_img`` are both provided or
|
|
130
|
+
If ``niimg`` and ``mask_img`` are both not provided or
|
|
109
131
|
if overlap is detected between spheres.
|
|
110
132
|
|
|
111
|
-
Warns
|
|
112
|
-
-----
|
|
113
|
-
RuntimeWarning
|
|
114
|
-
If the provided images contain NaN, they will be converted to zeroes.
|
|
115
|
-
|
|
116
133
|
"""
|
|
117
134
|
seeds = list(seeds)
|
|
118
|
-
|
|
119
135
|
# Compute world coordinates of all in-mask voxels.
|
|
120
136
|
if niimg is None:
|
|
137
|
+
if mask_img is None:
|
|
138
|
+
raise_error("Either a niimg or a mask_img must be provided.")
|
|
121
139
|
mask, affine = masking.load_mask_img(mask_img)
|
|
140
|
+
shape = mask.shape
|
|
122
141
|
# Get coordinate for all voxels inside of mask
|
|
123
142
|
mask_coords = np.asarray(np.nonzero(mask)).T.tolist()
|
|
124
|
-
X = None
|
|
125
|
-
|
|
126
143
|
elif mask_img is not None:
|
|
127
144
|
affine = niimg.affine
|
|
145
|
+
shape = niimg.shape[:3]
|
|
128
146
|
mask_img = check_niimg_3d(mask_img)
|
|
129
147
|
mask_img = image.resample_img(
|
|
130
148
|
mask_img,
|
|
131
149
|
target_affine=affine,
|
|
132
|
-
target_shape=
|
|
150
|
+
target_shape=shape,
|
|
133
151
|
interpolation="nearest",
|
|
134
152
|
)
|
|
135
153
|
mask, _ = masking.load_mask_img(mask_img)
|
|
136
|
-
mask_coords = list(zip(*np.where(mask != 0)))
|
|
137
|
-
|
|
138
|
-
X = masking.apply_mask_fmri(niimg, mask_img)
|
|
139
|
-
|
|
140
|
-
elif niimg is not None:
|
|
141
|
-
affine = niimg.affine
|
|
142
|
-
if np.isnan(np.sum(safe_get_data(niimg))):
|
|
143
|
-
warn_with_log(
|
|
144
|
-
"The imgs you have fed into fit_transform() contains NaN "
|
|
145
|
-
"values which will be converted to zeroes."
|
|
146
|
-
)
|
|
147
|
-
X = safe_get_data(niimg, True).reshape([-1, niimg.shape[3]]).T
|
|
148
|
-
else:
|
|
149
|
-
X = safe_get_data(niimg).reshape([-1, niimg.shape[3]]).T
|
|
150
|
-
|
|
151
|
-
mask_coords = list(np.ndindex(niimg.shape[:3]))
|
|
152
|
-
|
|
154
|
+
mask_coords = list(zip(*np.where(mask != 0), strict=False))
|
|
153
155
|
else:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
+
affine = niimg.affine
|
|
157
|
+
shape = niimg.shape[:3]
|
|
158
|
+
mask_coords = list(np.ndindex(shape))
|
|
159
|
+
voxels = np.ravel_multi_index(
|
|
160
|
+
tuple(np.asarray(mask_coords, dtype=int).reshape(-1, 3).T), shape
|
|
161
|
+
)
|
|
156
162
|
# For each seed, get coordinates of nearest voxel
|
|
157
163
|
nearests = []
|
|
158
164
|
for sx, sy, sz in seeds:
|
|
@@ -166,7 +172,7 @@ def _apply_mask_and_get_affinity(
|
|
|
166
172
|
except ValueError:
|
|
167
173
|
nearests.append(None)
|
|
168
174
|
|
|
169
|
-
mask_coords = np.asarray(list(zip(*mask_coords)))
|
|
175
|
+
mask_coords = np.asarray(list(zip(*mask_coords, strict=False)))
|
|
170
176
|
mask_coords = image.resampling.coord_transform(
|
|
171
177
|
mask_coords[0], mask_coords[1], mask_coords[2], affine
|
|
172
178
|
)
|
|
@@ -193,6 +199,132 @@ def _apply_mask_and_get_affinity(
|
|
|
193
199
|
if (not allow_overlap) and np.any(A.sum(axis=0) >= 2):
|
|
194
200
|
raise_error("Overlap detected between spheres")
|
|
195
201
|
|
|
202
|
+
return voxels, A
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def _read_signals(niimg, voxels, masked) -> np.ndarray:
|
|
206
|
+
"""Read the signals of some voxels, a few volumes at a time.
|
|
207
|
+
|
|
208
|
+
The data is read in chunks of ``markers.spheres.chunksize`` volumes and
|
|
209
|
+
only the signals of ``voxels`` are kept, so the whole data is never in
|
|
210
|
+
memory. The values are the same as extracting the signals from the whole
|
|
211
|
+
data with :func:`nilearn.masking.apply_mask_fmri` (``masked``) or
|
|
212
|
+
:func:`nilearn._utils.niimg.safe_get_data` (not ``masked``).
|
|
213
|
+
|
|
214
|
+
Parameters
|
|
215
|
+
----------
|
|
216
|
+
niimg : 4D Niimg-like object
|
|
217
|
+
The image to read.
|
|
218
|
+
voxels : 1D numpy.ndarray
|
|
219
|
+
The flat (C order) indices of the voxels to read.
|
|
220
|
+
masked : bool
|
|
221
|
+
Whether the voxels are the ones of a mask: as
|
|
222
|
+
:func:`nilearn.masking.apply_mask_fmri` does, the signals are then
|
|
223
|
+
float32 if the data is not floating point, and the non-finite values
|
|
224
|
+
are set to 0. Otherwise, the signals keep the data type of the image
|
|
225
|
+
and the non-finite values are set to 0 only if the image has NaN
|
|
226
|
+
values, with a warning.
|
|
227
|
+
|
|
228
|
+
Returns
|
|
229
|
+
-------
|
|
230
|
+
numpy.ndarray of shape (number of scans, number of voxels)
|
|
231
|
+
The signals of the voxels.
|
|
232
|
+
|
|
233
|
+
"""
|
|
234
|
+
n_scans = niimg.shape[3]
|
|
235
|
+
chunk_size = _get_chunk_size()
|
|
236
|
+
signals = None
|
|
237
|
+
has_nan = False
|
|
238
|
+
for start in range(0, n_scans, chunk_size):
|
|
239
|
+
chunk = np.asanyarray(niimg.dataobj[..., start : start + chunk_size])
|
|
240
|
+
if not masked and not has_nan:
|
|
241
|
+
has_nan = bool(np.isnan(np.sum(chunk)))
|
|
242
|
+
chunk = chunk.reshape(-1, chunk.shape[-1])[voxels].T
|
|
243
|
+
if masked and chunk.dtype.kind != "f":
|
|
244
|
+
chunk = chunk.astype(np.float32)
|
|
245
|
+
if signals is None:
|
|
246
|
+
signals = np.empty((n_scans, len(voxels)), dtype=chunk.dtype)
|
|
247
|
+
signals[start : start + chunk.shape[0]] = chunk
|
|
248
|
+
if masked or has_nan:
|
|
249
|
+
if has_nan:
|
|
250
|
+
warn_with_log(
|
|
251
|
+
"The imgs you have fed into fit_transform() contains NaN "
|
|
252
|
+
"values which will be converted to zeroes."
|
|
253
|
+
)
|
|
254
|
+
signals[~np.isfinite(signals)] = 0
|
|
255
|
+
return signals
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _apply_mask_and_get_affinity(
|
|
259
|
+
seeds, niimg, radius, allow_overlap, mask_img=None
|
|
260
|
+
):
|
|
261
|
+
"""Apply mask and get affinity matrix for given seeds.
|
|
262
|
+
|
|
263
|
+
Utility function to get only the rows which are occupied by sphere at
|
|
264
|
+
given seed locations and the provided radius. Rows are in target_affine and
|
|
265
|
+
target_shape space.
|
|
266
|
+
|
|
267
|
+
Parameters
|
|
268
|
+
----------
|
|
269
|
+
seeds : List of triplets of coordinates in native space
|
|
270
|
+
Seed definitions. List of coordinates of the seeds in the same space
|
|
271
|
+
as target_affine.
|
|
272
|
+
niimg : 3D/4D Niimg-like object
|
|
273
|
+
See :ref:`extracting_data`.
|
|
274
|
+
Images to process.
|
|
275
|
+
If a 3D niimg is provided, a singleton dimension will be added to
|
|
276
|
+
the output to represent the single scan in the niimg.
|
|
277
|
+
radius : float
|
|
278
|
+
Indicates, in millimeters, the radius for the sphere around the seed.
|
|
279
|
+
allow_overlap : boolean
|
|
280
|
+
If False, a ValueError is raised if VOIs overlap
|
|
281
|
+
mask_img : Niimg-like object, optional
|
|
282
|
+
Mask to apply to regions before extracting signals. If niimg is None,
|
|
283
|
+
mask_img is used as a reference space in which the spheres 'indices are
|
|
284
|
+
placed.
|
|
285
|
+
|
|
286
|
+
Returns
|
|
287
|
+
-------
|
|
288
|
+
X : 2D numpy.ndarray
|
|
289
|
+
Signal for each brain voxel in the (masked) niimgs.
|
|
290
|
+
shape: (number of scans, number of voxels)
|
|
291
|
+
A : scipy.sparse.lil_matrix
|
|
292
|
+
Contains the boolean indices for each sphere.
|
|
293
|
+
shape: (number of seeds, number of voxels)
|
|
294
|
+
|
|
295
|
+
Raises
|
|
296
|
+
------
|
|
297
|
+
ValueError
|
|
298
|
+
If ``niimg`` and ``mask_img`` are both provided or
|
|
299
|
+
if overlap is detected between spheres.
|
|
300
|
+
|
|
301
|
+
Warns
|
|
302
|
+
-----
|
|
303
|
+
RuntimeWarning
|
|
304
|
+
If the provided images contain NaN, they will be converted to zeroes.
|
|
305
|
+
|
|
306
|
+
"""
|
|
307
|
+
_, A = _get_sphere_voxels(
|
|
308
|
+
seeds, niimg, radius, allow_overlap, mask_img=mask_img
|
|
309
|
+
)
|
|
310
|
+
X = None
|
|
311
|
+
if niimg is not None and mask_img is not None:
|
|
312
|
+
mask_img = image.resample_img(
|
|
313
|
+
check_niimg_3d(mask_img),
|
|
314
|
+
target_affine=niimg.affine,
|
|
315
|
+
target_shape=niimg.shape[:3],
|
|
316
|
+
interpolation="nearest",
|
|
317
|
+
)
|
|
318
|
+
X = masking.apply_mask_fmri(niimg, mask_img)
|
|
319
|
+
elif niimg is not None:
|
|
320
|
+
if np.isnan(np.sum(safe_get_data(niimg))):
|
|
321
|
+
warn_with_log(
|
|
322
|
+
"The imgs you have fed into fit_transform() contains NaN "
|
|
323
|
+
"values which will be converted to zeroes."
|
|
324
|
+
)
|
|
325
|
+
X = safe_get_data(niimg, True).reshape([-1, niimg.shape[3]]).T
|
|
326
|
+
else:
|
|
327
|
+
X = safe_get_data(niimg).reshape([-1, niimg.shape[3]]).T
|
|
196
328
|
return X, A
|
|
197
329
|
|
|
198
330
|
|
|
@@ -201,16 +333,17 @@ def _iter_signals_from_spheres(
|
|
|
201
333
|
):
|
|
202
334
|
"""Iterate over spheres.
|
|
203
335
|
|
|
336
|
+
Only the signals of the voxels of the spheres are read, a few volumes at
|
|
337
|
+
a time (see :func:`_read_signals`), so the whole data is never in memory.
|
|
338
|
+
|
|
204
339
|
Parameters
|
|
205
340
|
----------
|
|
206
341
|
seeds : :obj:`list` of triplets of coordinates in native space
|
|
207
342
|
Seed definitions. List of coordinates of the seeds in the same space
|
|
208
343
|
as the images (typically MNI or TAL).
|
|
209
|
-
niimg :
|
|
344
|
+
niimg : 4D Niimg-like object
|
|
210
345
|
See :ref:`extracting_data`.
|
|
211
346
|
Images to process.
|
|
212
|
-
If a 3D niimg is provided, a singleton dimension will be added to
|
|
213
|
-
the output to represent the single scan in the niimg.
|
|
214
347
|
radius: float
|
|
215
348
|
Indicates, in millimeters, the radius for the sphere around the seed.
|
|
216
349
|
allow_overlap: boolean
|
|
@@ -221,11 +354,17 @@ def _iter_signals_from_spheres(
|
|
|
221
354
|
Mask to apply to regions before extracting signals.
|
|
222
355
|
|
|
223
356
|
"""
|
|
224
|
-
|
|
357
|
+
voxels, A = _get_sphere_voxels(
|
|
225
358
|
seeds, niimg, radius, allow_overlap, mask_img=mask_img
|
|
226
359
|
)
|
|
227
|
-
for row in A.rows
|
|
228
|
-
|
|
360
|
+
rows = [np.asarray(row, dtype=int) for row in A.rows]
|
|
361
|
+
# The voxels of any sphere, and their position in the signals read
|
|
362
|
+
used = np.unique(np.concatenate([np.zeros(0, dtype=int), *rows]))
|
|
363
|
+
position = np.full(len(voxels), -1, dtype=int)
|
|
364
|
+
position[used] = np.arange(len(used))
|
|
365
|
+
signals = _read_signals(niimg, voxels[used], masked=mask_img is not None)
|
|
366
|
+
for row in rows:
|
|
367
|
+
yield signals[:, position[row]]
|
|
229
368
|
|
|
230
369
|
|
|
231
370
|
class _JuniferExtractionFunctor:
|
|
@@ -255,7 +394,7 @@ class _JuniferExtractionFunctor:
|
|
|
255
394
|
def __init__(
|
|
256
395
|
self,
|
|
257
396
|
seeds_: "ArrayLike",
|
|
258
|
-
radius:
|
|
397
|
+
radius: float | None,
|
|
259
398
|
mask_img: Union["Nifti1Image", "Nifti2Image", None],
|
|
260
399
|
agg_func: Callable,
|
|
261
400
|
allow_overlap: bool,
|
|
@@ -324,6 +463,11 @@ class JuniferNiftiSpheresMasker(NiftiSpheresMasker):
|
|
|
324
463
|
* it allows to pass any callable as the ``agg_func`` parameter.
|
|
325
464
|
* empty spheres do not create an error. Instead, ``agg_func`` is applied to
|
|
326
465
|
an empty array and the result is passed.
|
|
466
|
+
* only the signals of the voxels of the spheres are read, a few volumes at
|
|
467
|
+
a time (``markers.spheres.chunksize``), so the whole data is never in
|
|
468
|
+
memory.
|
|
469
|
+
* ``reports`` is False by default, as the data for the reports (e.g., the
|
|
470
|
+
middle volume of the resampled images) needs the whole data in memory.
|
|
327
471
|
|
|
328
472
|
Parameters
|
|
329
473
|
----------
|
|
@@ -352,7 +496,7 @@ class JuniferNiftiSpheresMasker(NiftiSpheresMasker):
|
|
|
352
496
|
def __init__(
|
|
353
497
|
self,
|
|
354
498
|
seeds: "ArrayLike",
|
|
355
|
-
radius:
|
|
499
|
+
radius: float | None = None,
|
|
356
500
|
mask_img: Union["Nifti1Image", "Nifti2Image", None] = None,
|
|
357
501
|
agg_func: Callable = np.mean,
|
|
358
502
|
allow_overlap: bool = False,
|
|
@@ -360,11 +504,17 @@ class JuniferNiftiSpheresMasker(NiftiSpheresMasker):
|
|
|
360
504
|
**kwargs, # TODO: to keep or not?
|
|
361
505
|
) -> None:
|
|
362
506
|
self.agg_func = agg_func
|
|
507
|
+
# nilearn's default (False) is deprecated, use the new equivalent
|
|
508
|
+
kwargs.setdefault("standardize", None)
|
|
509
|
+
# The reports are not used, and computing their data at fit time
|
|
510
|
+
# loads (and resamples) the whole data
|
|
511
|
+
kwargs.setdefault("reports", False)
|
|
363
512
|
super().__init__(
|
|
364
513
|
seeds=seeds,
|
|
365
514
|
radius=radius,
|
|
366
515
|
mask_img=mask_img,
|
|
367
516
|
allow_overlap=allow_overlap,
|
|
517
|
+
dtype=dtype,
|
|
368
518
|
**kwargs,
|
|
369
519
|
)
|
|
370
520
|
|
|
@@ -409,16 +559,19 @@ class JuniferNiftiSpheresMasker(NiftiSpheresMasker):
|
|
|
409
559
|
inputs.
|
|
410
560
|
|
|
411
561
|
"""
|
|
412
|
-
self
|
|
562
|
+
check_is_fitted(self)
|
|
413
563
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
564
|
+
# The parameters are taken from NiftiSpheresMasker, as the ones not
|
|
565
|
+
# in this class' signature are passed as keyword arguments
|
|
566
|
+
params = {
|
|
567
|
+
k: getattr(self, k)
|
|
568
|
+
for k in NiftiSpheresMasker._get_param_names()
|
|
569
|
+
if k not in {"memory", "memory_level", "verbose", "copy", "n_jobs"}
|
|
570
|
+
}
|
|
571
|
+
params["clean_kwargs"] = self.clean_args_
|
|
419
572
|
|
|
420
573
|
signals, _ = self._cache(
|
|
421
|
-
|
|
574
|
+
filter_and_extract, ignore=["verbose", "memory", "memory_level"]
|
|
422
575
|
)(
|
|
423
576
|
imgs,
|
|
424
577
|
_JuniferExtractionFunctor(
|
|
@@ -434,12 +587,18 @@ class JuniferNiftiSpheresMasker(NiftiSpheresMasker):
|
|
|
434
587
|
confounds=confounds,
|
|
435
588
|
sample_mask=sample_mask,
|
|
436
589
|
dtype=self.dtype,
|
|
590
|
+
sklearn_output_config=getattr(
|
|
591
|
+
self, "_sklearn_output_config", None
|
|
592
|
+
),
|
|
437
593
|
# Caching
|
|
438
|
-
memory=self.
|
|
594
|
+
memory=self.memory_,
|
|
439
595
|
memory_level=self.memory_level,
|
|
440
596
|
# kwargs
|
|
441
597
|
verbose=self.verbose,
|
|
442
598
|
)
|
|
599
|
+
target_dtype = self._get_target_dtype(load_img(imgs))
|
|
600
|
+
if target_dtype is not None:
|
|
601
|
+
signals = signals.astype(target_dtype)
|
|
443
602
|
return signals
|
|
444
603
|
|
|
445
604
|
def inverse_transform(self, region_signals: "ArrayLike") -> "Nifti1Image":
|
|
@@ -7,11 +7,15 @@ import copy
|
|
|
7
7
|
import sys
|
|
8
8
|
import warnings
|
|
9
9
|
from math import cosh, exp, log, sinh, sqrt
|
|
10
|
-
from typing import TYPE_CHECKING, Optional
|
|
10
|
+
from typing import TYPE_CHECKING, Optional
|
|
11
11
|
|
|
12
12
|
import numpy as np
|
|
13
13
|
import pytest
|
|
14
14
|
from nilearn.connectome.connectivity_matrices import sym_matrix_to_vec
|
|
15
|
+
|
|
16
|
+
# Not part of nilearn's public API, so it might move in future versions.
|
|
17
|
+
# Importing it evaluates the markers of nilearn's test module, which need to
|
|
18
|
+
# be registered in the pytest markers (see pyproject.toml).
|
|
15
19
|
from nilearn.tests.test_signal import generate_signals
|
|
16
20
|
from numpy.testing import (
|
|
17
21
|
assert_allclose,
|
|
@@ -21,6 +25,7 @@ from numpy.testing import (
|
|
|
21
25
|
from pandas import DataFrame
|
|
22
26
|
from scipy import linalg
|
|
23
27
|
from sklearn.covariance import EmpiricalCovariance, LedoitWolf
|
|
28
|
+
from sklearn.exceptions import NotFittedError
|
|
24
29
|
|
|
25
30
|
from junifer.external.nilearn import JuniferConnectivityMeasure
|
|
26
31
|
from junifer.external.nilearn.junifer_connectivity_measure import (
|
|
@@ -88,7 +93,7 @@ def random_diagonal(
|
|
|
88
93
|
p: int,
|
|
89
94
|
v_min: float = 1.0,
|
|
90
95
|
v_max: float = 2.0,
|
|
91
|
-
random_state:
|
|
96
|
+
random_state: int | np.random.RandomState = 0,
|
|
92
97
|
) -> np.ndarray:
|
|
93
98
|
"""Generate a random diagonal matrix.
|
|
94
99
|
|
|
@@ -120,7 +125,7 @@ def random_spd(
|
|
|
120
125
|
p: int,
|
|
121
126
|
eig_min: float,
|
|
122
127
|
cond: float,
|
|
123
|
-
random_state:
|
|
128
|
+
random_state: int | np.random.RandomState = 0,
|
|
124
129
|
) -> np.ndarray:
|
|
125
130
|
"""Generate a random symmetric positive definite matrix.
|
|
126
131
|
|
|
@@ -190,7 +195,7 @@ def signals() -> list[np.ndarray]:
|
|
|
190
195
|
|
|
191
196
|
@pytest.fixture
|
|
192
197
|
def signals_and_covariances(
|
|
193
|
-
cov_estimator:
|
|
198
|
+
cov_estimator: LedoitWolf | EmpiricalCovariance,
|
|
194
199
|
) -> tuple[list[np.ndarray], list[float]]:
|
|
195
200
|
"""Return signals and covariances for a covariance estimator.
|
|
196
201
|
|
|
@@ -343,7 +348,7 @@ def test_geometric_mean_properties() -> None:
|
|
|
343
348
|
|
|
344
349
|
# Generic
|
|
345
350
|
assert isinstance(spds, list)
|
|
346
|
-
for spd, input_spd in zip(spds, input_spds):
|
|
351
|
+
for spd, input_spd in zip(spds, input_spds, strict=False):
|
|
347
352
|
assert_array_equal(spd, input_spd)
|
|
348
353
|
assert is_spd(gmean, decimal=7)
|
|
349
354
|
|
|
@@ -352,7 +357,7 @@ def random_non_singular(
|
|
|
352
357
|
p: int,
|
|
353
358
|
sing_min: float = 1.0,
|
|
354
359
|
sing_max: float = 2.0,
|
|
355
|
-
random_state:
|
|
360
|
+
random_state: int | np.random.RandomState = 0,
|
|
356
361
|
) -> np.ndarray:
|
|
357
362
|
"""Generate a random nonsingular matrix.
|
|
358
363
|
|
|
@@ -587,9 +592,7 @@ def test_connectivity_measure_errors():
|
|
|
587
592
|
# Raising error for input subjects not iterable
|
|
588
593
|
conn_measure = JuniferConnectivityMeasure()
|
|
589
594
|
|
|
590
|
-
with pytest.raises(
|
|
591
|
-
ValueError, match=r"'subjects' input argument must be an iterable"
|
|
592
|
-
):
|
|
595
|
+
with pytest.raises(TypeError, match=r"Input must be an iterable"):
|
|
593
596
|
conn_measure.fit(1.0)
|
|
594
597
|
|
|
595
598
|
# input subjects not 2D numpy.ndarrays
|
|
@@ -605,6 +608,15 @@ def test_connectivity_measure_errors():
|
|
|
605
608
|
):
|
|
606
609
|
conn_measure.fit([np.ones((100, 40)), np.ones((100, 41))])
|
|
607
610
|
|
|
611
|
+
# invalid kind, listing all the allowed kinds
|
|
612
|
+
conn_measure = JuniferConnectivityMeasure(kind="foo")
|
|
613
|
+
with pytest.raises(
|
|
614
|
+
ValueError,
|
|
615
|
+
match=r"Allowed connectivity kinds .*'spearman correlation'.*"
|
|
616
|
+
r"'xi correlation'.* Got kind foo",
|
|
617
|
+
):
|
|
618
|
+
conn_measure.fit([np.ones((100, 40))])
|
|
619
|
+
|
|
608
620
|
# fit_transform with a single subject and kind=tangent
|
|
609
621
|
conn_measure = JuniferConnectivityMeasure(kind="tangent")
|
|
610
622
|
|
|
@@ -669,7 +681,7 @@ def _assert_connectivity_tangent(connectivities, conn_measure, covs) -> None:
|
|
|
669
681
|
|
|
670
682
|
"""
|
|
671
683
|
for true_covariance_matrix, estimated_covariance_matrix in zip(
|
|
672
|
-
covs, connectivities
|
|
684
|
+
covs, connectivities, strict=False
|
|
673
685
|
):
|
|
674
686
|
assert_array_almost_equal(
|
|
675
687
|
estimated_covariance_matrix, estimated_covariance_matrix.T
|
|
@@ -701,7 +713,7 @@ def _assert_connectivity_precision(connectivities, covs) -> None:
|
|
|
701
713
|
|
|
702
714
|
"""
|
|
703
715
|
for true_covariance_matrix, estimated_covariance_matrix in zip(
|
|
704
|
-
covs, connectivities
|
|
716
|
+
covs, connectivities, strict=False
|
|
705
717
|
):
|
|
706
718
|
assert is_spd(estimated_covariance_matrix, decimal=7)
|
|
707
719
|
assert_array_almost_equal(
|
|
@@ -729,7 +741,7 @@ def _assert_connectivity_correlation(
|
|
|
729
741
|
|
|
730
742
|
"""
|
|
731
743
|
for true_covariance_matrix, estimated_covariance_matrix in zip(
|
|
732
|
-
covs, connectivities
|
|
744
|
+
covs, connectivities, strict=False
|
|
733
745
|
):
|
|
734
746
|
assert is_spd(estimated_covariance_matrix, decimal=7)
|
|
735
747
|
|
|
@@ -750,7 +762,7 @@ def _assert_connectivity_correlation(
|
|
|
750
762
|
def _assert_connectivity_partial_correlation(connectivities, covs) -> None:
|
|
751
763
|
"""Assert partial correlation connectivity matrix."""
|
|
752
764
|
for true_covariance_matrix, estimated_covariance_matrix in zip(
|
|
753
|
-
covs, connectivities
|
|
765
|
+
covs, connectivities, strict=False
|
|
754
766
|
):
|
|
755
767
|
precision_matrix = linalg.inv(true_covariance_matrix)
|
|
756
768
|
|
|
@@ -874,7 +886,7 @@ def test_connectivity_measure_check_vectorization_option(
|
|
|
874
886
|
)
|
|
875
887
|
|
|
876
888
|
# Check not fitted error
|
|
877
|
-
with pytest.raises(
|
|
889
|
+
with pytest.raises(NotFittedError):
|
|
878
890
|
JuniferConnectivityMeasure().inverse_transform(
|
|
879
891
|
vectorized_connectivities
|
|
880
892
|
)
|
|
@@ -1053,15 +1065,15 @@ def test_confounds_connectivity_measure_errors() -> None:
|
|
|
1053
1065
|
conn_measure = JuniferConnectivityMeasure(vectorize=True)
|
|
1054
1066
|
msg = r"'confounds' input argument must be an iterable"
|
|
1055
1067
|
|
|
1056
|
-
with pytest.raises(
|
|
1068
|
+
with pytest.raises(TypeError, match=msg):
|
|
1057
1069
|
conn_measure._check_input(X=signals, confounds=1.0)
|
|
1058
1070
|
|
|
1059
|
-
with pytest.raises(
|
|
1071
|
+
with pytest.raises(TypeError, match=msg):
|
|
1060
1072
|
conn_measure._fit_transform(
|
|
1061
1073
|
X=signals, do_fit=True, do_transform=True, confounds=1.0
|
|
1062
1074
|
)
|
|
1063
1075
|
|
|
1064
|
-
with pytest.raises(
|
|
1076
|
+
with pytest.raises(TypeError, match=msg):
|
|
1065
1077
|
conn_measure.fit_transform(X=signals, y=None, confounds=1.0)
|
|
1066
1078
|
|
|
1067
1079
|
# Raising error for input confounds are given but not vectorize=True
|
|
@@ -1075,7 +1087,7 @@ def test_confounds_connectivity_measure_errors() -> None:
|
|
|
1075
1087
|
def test_connectivity_measure_standardize(
|
|
1076
1088
|
signals: list[np.ndarray],
|
|
1077
1089
|
) -> None:
|
|
1078
|
-
"""Check
|
|
1090
|
+
"""Check standardize strategies and the error for booleans.
|
|
1079
1091
|
|
|
1080
1092
|
Parameters
|
|
1081
1093
|
----------
|
|
@@ -1083,17 +1095,17 @@ def test_connectivity_measure_standardize(
|
|
|
1083
1095
|
The input signals.
|
|
1084
1096
|
|
|
1085
1097
|
"""
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1098
|
+
# No warnings about standardize with the default strategy
|
|
1099
|
+
with warnings.catch_warnings(record=True) as record:
|
|
1100
|
+
warnings.simplefilter("always")
|
|
1089
1101
|
JuniferConnectivityMeasure(kind="correlation").fit_transform(signals)
|
|
1102
|
+
assert not [m for m in record if "standardize" in str(m.message)]
|
|
1090
1103
|
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
assert match not in m.message
|
|
1104
|
+
for standardize in (True, False):
|
|
1105
|
+
with pytest.raises(ValueError, match="does not accept booleans"):
|
|
1106
|
+
JuniferConnectivityMeasure(
|
|
1107
|
+
kind="correlation", standardize=standardize
|
|
1108
|
+
).fit_transform(signals)
|
|
1097
1109
|
|
|
1098
1110
|
|
|
1099
1111
|
@pytest.mark.skipif(
|