junifer 0.0.5.dev242__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.dev242.dist-info → junifer-0.0.6.dist-info}/METADATA +43 -38
- junifer-0.0.6.dist-info/RECORD +350 -0
- {junifer-0.0.5.dev242.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.dev242.dist-info/RECORD +0 -275
- junifer-0.0.5.dev242.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.dev242.dist-info → junifer-0.0.6.dist-info/licenses}/AUTHORS.rst +0 -0
- {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info/licenses}/LICENSE.md +0 -0
- {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
"""Provide abstract base class for pipeline data registry."""
|
2
|
+
|
3
|
+
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
|
+
# License: AGPL
|
5
|
+
|
6
|
+
from abc import ABC, abstractmethod
|
7
|
+
from collections.abc import Mapping
|
8
|
+
from typing import Any
|
9
|
+
|
10
|
+
from ..utils import raise_error
|
11
|
+
from ..utils.singleton import ABCSingleton
|
12
|
+
|
13
|
+
|
14
|
+
__all__ = ["BasePipelineDataRegistry"]
|
15
|
+
|
16
|
+
|
17
|
+
class BasePipelineDataRegistry(ABC, metaclass=ABCSingleton):
|
18
|
+
"""Abstract base class for pipeline data registry.
|
19
|
+
|
20
|
+
For every interface that is required, one needs to provide a concrete
|
21
|
+
implementation for this abstract class.
|
22
|
+
|
23
|
+
Attributes
|
24
|
+
----------
|
25
|
+
registry : dict
|
26
|
+
Registry of available pipeline data.
|
27
|
+
list : dict
|
28
|
+
Keys of available pipeline data registry.
|
29
|
+
|
30
|
+
"""
|
31
|
+
|
32
|
+
def __init__(self) -> None:
|
33
|
+
"""Initialize the class."""
|
34
|
+
self._registry: Mapping[str, Any] = {}
|
35
|
+
|
36
|
+
@property
|
37
|
+
def data(self) -> Mapping[str, Any]:
|
38
|
+
"""Get available pipeline data."""
|
39
|
+
return self._registry
|
40
|
+
|
41
|
+
@property
|
42
|
+
def list(self) -> list[str]:
|
43
|
+
"""List available pipeline data keys."""
|
44
|
+
return sorted(self._registry.keys())
|
45
|
+
|
46
|
+
@abstractmethod
|
47
|
+
def register(self) -> None:
|
48
|
+
"""Register data."""
|
49
|
+
raise_error(
|
50
|
+
msg="Concrete classes need to implement register().",
|
51
|
+
klass=NotImplementedError,
|
52
|
+
)
|
53
|
+
|
54
|
+
@abstractmethod
|
55
|
+
def deregister(self) -> None:
|
56
|
+
"""De-register data."""
|
57
|
+
raise_error(
|
58
|
+
msg="Concrete classes need to implement deregister().",
|
59
|
+
klass=NotImplementedError,
|
60
|
+
)
|
61
|
+
|
62
|
+
@abstractmethod
|
63
|
+
def load(self) -> Any:
|
64
|
+
"""Load data."""
|
65
|
+
raise_error(
|
66
|
+
msg="Concrete classes need to implement load().",
|
67
|
+
klass=NotImplementedError,
|
68
|
+
)
|
69
|
+
|
70
|
+
@abstractmethod
|
71
|
+
def get(self) -> Any:
|
72
|
+
"""Get tailored data for a target."""
|
73
|
+
raise_error(
|
74
|
+
msg="Concrete classes need to implement get().",
|
75
|
+
klass=NotImplementedError,
|
76
|
+
)
|
junifer/data/py.typed
ADDED
File without changes
|
junifer/data/template_spaces.py
CHANGED
@@ -4,23 +4,21 @@
|
|
4
4
|
# License: AGPL
|
5
5
|
|
6
6
|
from pathlib import Path
|
7
|
-
from typing import Any,
|
7
|
+
from typing import Any, Optional, Union
|
8
8
|
|
9
|
-
import httpx
|
10
9
|
import nibabel as nib
|
11
10
|
import numpy as np
|
11
|
+
from junifer_data import get
|
12
12
|
from templateflow import api as tflow
|
13
13
|
|
14
14
|
from ..utils import logger, raise_error
|
15
|
-
from .utils import closest_resolution
|
15
|
+
from .utils import JUNIFER_DATA_PARAMS, closest_resolution, get_dataset_path
|
16
16
|
|
17
17
|
|
18
|
-
__all__ = ["
|
18
|
+
__all__ = ["get_template", "get_xfm"]
|
19
19
|
|
20
20
|
|
21
|
-
def get_xfm(
|
22
|
-
src: str, dst: str, xfms_dir: Union[str, Path, None] = None
|
23
|
-
) -> Path: # pragma: no cover
|
21
|
+
def get_xfm(src: str, dst: str) -> Path: # pragma: no cover
|
24
22
|
"""Fetch warp files to convert from ``src`` to ``dst``.
|
25
23
|
|
26
24
|
Parameters
|
@@ -29,80 +27,29 @@ def get_xfm(
|
|
29
27
|
The template space to transform from.
|
30
28
|
dst : str
|
31
29
|
The template space to transform to.
|
32
|
-
xfms_dir : str or pathlib.Path, optional
|
33
|
-
Path where the retrieved transformation files are stored.
|
34
|
-
The default location is "$HOME/junifer/data/xfms" (default None).
|
35
30
|
|
36
31
|
Returns
|
37
32
|
-------
|
38
33
|
pathlib.Path
|
39
34
|
The path to the transformation file.
|
40
35
|
|
41
|
-
Raises
|
42
|
-
------
|
43
|
-
RuntimeError
|
44
|
-
If there is a problem fetching files.
|
45
|
-
|
46
36
|
"""
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
xfms_dir = Path(xfms_dir)
|
55
|
-
|
56
|
-
# Set local file prefix
|
57
|
-
xfm_file_prefix = f"{src}_to_{dst}"
|
58
|
-
# Set local file dir
|
59
|
-
xfm_file_dir = xfms_dir / xfm_file_prefix
|
60
|
-
# Create local directory if not present
|
61
|
-
xfm_file_dir.mkdir(exist_ok=True, parents=True)
|
62
|
-
# Set file name with extension
|
63
|
-
xfm_file = f"{src}_to_{dst}_Composite.h5"
|
64
|
-
# Set local file path
|
65
|
-
xfm_file_path = xfm_file_dir / xfm_file
|
66
|
-
# Check if the file exists
|
67
|
-
if xfm_file_path.exists():
|
68
|
-
logger.info(
|
69
|
-
f"Found existing xfm file for {src} to {dst} at "
|
70
|
-
f"{xfm_file_path.resolve()}"
|
71
|
-
)
|
72
|
-
return xfm_file_path
|
73
|
-
|
74
|
-
# Set URL
|
75
|
-
url = (
|
76
|
-
"https://gin.g-node.org/juaml/human-template-xfms/raw/main/xfms/"
|
77
|
-
f"{xfm_file_prefix}/{xfm_file}"
|
37
|
+
# Set file path to retrieve
|
38
|
+
xfm_file_path = Path(f"xfms/{src}_to_{dst}/{src}_to_{dst}_Composite.h5")
|
39
|
+
# Retrieve file
|
40
|
+
return get(
|
41
|
+
file_path=xfm_file_path,
|
42
|
+
dataset_path=get_dataset_path(),
|
43
|
+
**JUNIFER_DATA_PARAMS,
|
78
44
|
)
|
79
|
-
# Create the file before proceeding
|
80
|
-
xfm_file_path.touch()
|
81
|
-
|
82
|
-
logger.info(f"Downloading xfm file for {src} to {dst} from {url}")
|
83
|
-
# Steam response
|
84
|
-
with httpx.stream("GET", url) as resp:
|
85
|
-
try:
|
86
|
-
resp.raise_for_status()
|
87
|
-
except httpx.HTTPError as exc:
|
88
|
-
raise_error(
|
89
|
-
f"Error response {exc.response.status_code} while "
|
90
|
-
f"requesting {exc.request.url!r}",
|
91
|
-
klass=RuntimeError,
|
92
|
-
)
|
93
|
-
else:
|
94
|
-
with open(xfm_file_path, "ab") as f:
|
95
|
-
for chunk in resp.iter_bytes():
|
96
|
-
f.write(chunk)
|
97
|
-
|
98
|
-
return xfm_file_path
|
99
45
|
|
100
46
|
|
101
47
|
def get_template(
|
102
48
|
space: str,
|
103
|
-
|
104
|
-
extra_input: Optional[
|
49
|
+
target_img: nib.Nifti1Image,
|
50
|
+
extra_input: Optional[dict[str, Any]] = None,
|
105
51
|
template_type: str = "T1w",
|
52
|
+
resolution: Optional[Union[int, "str"]] = None,
|
106
53
|
) -> nib.Nifti1Image:
|
107
54
|
"""Get template for the space, tailored for the target image.
|
108
55
|
|
@@ -110,14 +57,18 @@ def get_template(
|
|
110
57
|
----------
|
111
58
|
space : str
|
112
59
|
The name of the template space.
|
113
|
-
|
114
|
-
The corresponding
|
115
|
-
|
60
|
+
target_img : Nifti1Image
|
61
|
+
The corresponding image for which the template space will be loaded.
|
62
|
+
This is used to obtain the best matching resolution.
|
116
63
|
extra_input : dict, optional
|
117
64
|
The other fields in the data object. Useful for accessing other data
|
118
65
|
types (default None).
|
119
66
|
template_type : {"T1w", "brain", "gm", "wm", "csf"}, optional
|
120
67
|
The template type to retrieve (default "T1w").
|
68
|
+
resolution : int or "highest", optional
|
69
|
+
The resolution of the template to fetch. If None, the closest
|
70
|
+
resolution to the target image is used (default None). If "highest",
|
71
|
+
the highest resolution is used.
|
121
72
|
|
122
73
|
Returns
|
123
74
|
-------
|
@@ -127,7 +78,8 @@ def get_template(
|
|
127
78
|
Raises
|
128
79
|
------
|
129
80
|
ValueError
|
130
|
-
If ``space`` or ``template_type`` is invalid
|
81
|
+
If ``space`` or ``template_type`` is invalid or
|
82
|
+
if ``resolution`` is not at int or "highest".
|
131
83
|
RuntimeError
|
132
84
|
If required template is not found.
|
133
85
|
|
@@ -140,19 +92,30 @@ def get_template(
|
|
140
92
|
if template_type not in ["T1w", "brain", "gm", "wm", "csf"]:
|
141
93
|
raise_error(f"Unknown template type: {template_type}")
|
142
94
|
|
143
|
-
|
144
|
-
|
145
|
-
|
95
|
+
if isinstance(resolution, str) and resolution != "highest":
|
96
|
+
raise_error(
|
97
|
+
"Invalid resolution value. Must be an integer or 'highest'"
|
98
|
+
)
|
146
99
|
|
147
100
|
# Fetch available resolutions for the template
|
148
101
|
available_resolutions = [
|
149
102
|
int(min(val["zooms"]))
|
150
103
|
for val in tflow.get_metadata(space)["res"].values()
|
151
104
|
]
|
105
|
+
|
106
|
+
# Get the min of the voxels sizes and use it as the resolution
|
107
|
+
if resolution is None:
|
108
|
+
resolution = np.min(target_img.header.get_zooms()[:3]).astype(int)
|
109
|
+
elif resolution == "highest":
|
110
|
+
resolution = 0
|
111
|
+
|
152
112
|
# Use the closest resolution if desired resolution is not found
|
153
113
|
resolution = closest_resolution(resolution, available_resolutions)
|
154
114
|
|
155
|
-
logger.info(
|
115
|
+
logger.info(
|
116
|
+
f"Downloading template {space} ({template_type} in "
|
117
|
+
f"resolution {resolution})"
|
118
|
+
)
|
156
119
|
# Retrieve template
|
157
120
|
try:
|
158
121
|
suffix = None
|
@@ -185,9 +148,11 @@ def get_template(
|
|
185
148
|
)
|
186
149
|
except Exception: # noqa: BLE001
|
187
150
|
raise_error(
|
188
|
-
|
189
|
-
|
151
|
+
msg=(
|
152
|
+
f"Template {space} ({template_type}) with resolution "
|
153
|
+
f"{resolution}) not found"
|
154
|
+
),
|
190
155
|
klass=RuntimeError,
|
191
156
|
)
|
192
157
|
else:
|
193
|
-
return nib.load(template_path)
|
158
|
+
return nib.load(template_path)
|
@@ -3,7 +3,6 @@
|
|
3
3
|
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
4
4
|
# License: AGPL
|
5
5
|
|
6
|
-
from typing import List
|
7
6
|
|
8
7
|
import numpy as np
|
9
8
|
import pytest
|
@@ -24,7 +23,7 @@ from junifer.data.utils import closest_resolution
|
|
24
23
|
],
|
25
24
|
)
|
26
25
|
def test_closest_resolution(
|
27
|
-
resolution: float, valid_resolutions:
|
26
|
+
resolution: float, valid_resolutions: list[float], expected: float
|
28
27
|
):
|
29
28
|
"""Test closest_resolution.
|
30
29
|
|
@@ -61,7 +61,9 @@ def test_get_template(template_type: str) -> None:
|
|
61
61
|
bold = element_data["BOLD"]
|
62
62
|
# Get tailored parcellation
|
63
63
|
tailored_template = get_template(
|
64
|
-
space=bold["space"],
|
64
|
+
space=bold["space"],
|
65
|
+
target_img=bold["data"],
|
66
|
+
template_type=template_type,
|
65
67
|
)
|
66
68
|
assert isinstance(tailored_template, nib.Nifti1Image)
|
67
69
|
|
@@ -74,7 +76,7 @@ def test_get_template_invalid_space() -> None:
|
|
74
76
|
vbm_gm = element_data["VBM_GM"]
|
75
77
|
# Get tailored parcellation
|
76
78
|
with pytest.raises(ValueError, match="Unknown template space:"):
|
77
|
-
get_template(space="andromeda",
|
79
|
+
get_template(space="andromeda", target_img=vbm_gm["data"])
|
78
80
|
|
79
81
|
|
80
82
|
def test_get_template_invalid_template_type() -> None:
|
@@ -87,7 +89,7 @@ def test_get_template_invalid_template_type() -> None:
|
|
87
89
|
with pytest.raises(ValueError, match="Unknown template type:"):
|
88
90
|
get_template(
|
89
91
|
space=vbm_gm["space"],
|
90
|
-
|
92
|
+
target_img=vbm_gm["data"],
|
91
93
|
template_type="xenon",
|
92
94
|
)
|
93
95
|
|
@@ -100,5 +102,7 @@ def test_get_template_closest_resolution() -> None:
|
|
100
102
|
vbm_gm = element_data["VBM_GM"]
|
101
103
|
# Change header resolution to fetch closest resolution
|
102
104
|
element_data["VBM_GM"]["data"].header.set_zooms((3, 3, 3))
|
103
|
-
template = get_template(
|
105
|
+
template = get_template(
|
106
|
+
space=vbm_gm["space"], target_img=vbm_gm["data"]
|
107
|
+
)
|
104
108
|
assert isinstance(template, nib.Nifti1Image)
|
junifer/data/utils.py
CHANGED
@@ -1,18 +1,43 @@
|
|
1
1
|
"""Provide utilities for data module."""
|
2
2
|
|
3
|
-
|
3
|
+
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
4
|
+
# Synchon Mandal <s.mandal@fz-juelich.de>
|
5
|
+
# License: AGPL
|
6
|
+
|
7
|
+
from collections.abc import MutableMapping
|
8
|
+
from pathlib import Path
|
9
|
+
from typing import Optional, Union
|
4
10
|
|
5
11
|
import numpy as np
|
6
12
|
|
7
|
-
from ..utils
|
13
|
+
from ..utils import config, logger, raise_error
|
14
|
+
|
15
|
+
|
16
|
+
__all__ = [
|
17
|
+
"JUNIFER_DATA_HEXSHA",
|
18
|
+
"JUNIFER_DATA_PARAMS",
|
19
|
+
"JUNIFER_DATA_VERSION",
|
20
|
+
"closest_resolution",
|
21
|
+
"get_dataset_path",
|
22
|
+
"get_native_warper",
|
23
|
+
]
|
24
|
+
|
8
25
|
|
26
|
+
# junifer-data version constant
|
27
|
+
JUNIFER_DATA_VERSION = "2"
|
9
28
|
|
10
|
-
|
29
|
+
# junifer-data hexsha constant
|
30
|
+
JUNIFER_DATA_HEXSHA = "015712689254c052fa64bca19f0f2da342e664ac"
|
31
|
+
|
32
|
+
JUNIFER_DATA_PARAMS = {
|
33
|
+
"tag": JUNIFER_DATA_VERSION,
|
34
|
+
"hexsha": JUNIFER_DATA_HEXSHA,
|
35
|
+
}
|
11
36
|
|
12
37
|
|
13
38
|
def closest_resolution(
|
14
39
|
resolution: Optional[Union[float, int]],
|
15
|
-
valid_resolution: Union[
|
40
|
+
valid_resolution: Union[list[float], list[int], np.ndarray],
|
16
41
|
) -> Union[float, int]:
|
17
42
|
"""Find the closest resolution.
|
18
43
|
|
@@ -45,3 +70,83 @@ def closest_resolution(
|
|
45
70
|
closest = np.min(valid_resolution)
|
46
71
|
|
47
72
|
return closest
|
73
|
+
|
74
|
+
|
75
|
+
def get_native_warper(
|
76
|
+
target_data: MutableMapping,
|
77
|
+
other_data: MutableMapping,
|
78
|
+
inverse: bool = False,
|
79
|
+
) -> dict:
|
80
|
+
"""Get correct warping specification for native space.
|
81
|
+
|
82
|
+
Parameters
|
83
|
+
----------
|
84
|
+
target_data : dict
|
85
|
+
The target data from the pipeline data object.
|
86
|
+
other_data : dict
|
87
|
+
The other data in the pipeline data object.
|
88
|
+
inverse : bool, optional
|
89
|
+
Whether to get the inverse warping specification (default False).
|
90
|
+
|
91
|
+
Returns
|
92
|
+
-------
|
93
|
+
dict
|
94
|
+
The correct warping specification.
|
95
|
+
|
96
|
+
Raises
|
97
|
+
------
|
98
|
+
RuntimeError
|
99
|
+
If no warper or multiple possible warpers are found.
|
100
|
+
|
101
|
+
"""
|
102
|
+
# Get possible warpers
|
103
|
+
possible_warpers = []
|
104
|
+
for entry in other_data["Warp"]:
|
105
|
+
if not inverse:
|
106
|
+
if (
|
107
|
+
entry["src"] == target_data["prewarp_space"]
|
108
|
+
and entry["dst"] == "native"
|
109
|
+
):
|
110
|
+
possible_warpers.append(entry)
|
111
|
+
else:
|
112
|
+
if (
|
113
|
+
entry["dst"] == target_data["prewarp_space"]
|
114
|
+
and entry["src"] == "native"
|
115
|
+
):
|
116
|
+
possible_warpers.append(entry)
|
117
|
+
|
118
|
+
# Check for no warper
|
119
|
+
if not possible_warpers:
|
120
|
+
raise_error(
|
121
|
+
klass=RuntimeError,
|
122
|
+
msg="Could not find correct warping specification",
|
123
|
+
)
|
124
|
+
|
125
|
+
# Check for multiple possible warpers
|
126
|
+
if len(possible_warpers) > 1:
|
127
|
+
raise_error(
|
128
|
+
klass=RuntimeError,
|
129
|
+
msg=(
|
130
|
+
"Cannot proceed as multiple warping specification found, "
|
131
|
+
"adjust either the DataGrabber or the working space: "
|
132
|
+
f"{possible_warpers}"
|
133
|
+
),
|
134
|
+
)
|
135
|
+
|
136
|
+
return possible_warpers[0]
|
137
|
+
|
138
|
+
|
139
|
+
def get_dataset_path() -> Optional[Path]:
|
140
|
+
"""Get junifer-data dataset path.
|
141
|
+
|
142
|
+
Returns
|
143
|
+
-------
|
144
|
+
pathlib.Path or None
|
145
|
+
Path to the dataset or None.
|
146
|
+
|
147
|
+
"""
|
148
|
+
return (
|
149
|
+
Path(config.get("data.location"))
|
150
|
+
if config.get("data.location") is not None
|
151
|
+
else None
|
152
|
+
)
|
junifer/datagrabber/__init__.py
CHANGED
@@ -5,31 +5,7 @@
|
|
5
5
|
# Synchon Mandal <s.mandal@fz-juelich.de>
|
6
6
|
# License: AGPL
|
7
7
|
|
8
|
+
import lazy_loader as lazy
|
8
9
|
|
9
|
-
# These 4 need to be in this order, otherwise it is a circular import
|
10
|
-
from .base import BaseDataGrabber
|
11
|
-
from .datalad_base import DataladDataGrabber
|
12
|
-
from .pattern import PatternDataGrabber
|
13
|
-
from .pattern_datalad import PatternDataladDataGrabber
|
14
10
|
|
15
|
-
|
16
|
-
from .hcp1200 import HCP1200, DataladHCP1200
|
17
|
-
from .multiple import MultipleDataGrabber
|
18
|
-
from .dmcc13_benchmark import DMCC13Benchmark
|
19
|
-
|
20
|
-
from .pattern_validation_mixin import PatternValidationMixin
|
21
|
-
|
22
|
-
__all__ = [
|
23
|
-
"BaseDataGrabber",
|
24
|
-
"DataladDataGrabber",
|
25
|
-
"PatternDataGrabber",
|
26
|
-
"PatternDataladDataGrabber",
|
27
|
-
"DataladAOMICID1000",
|
28
|
-
"DataladAOMICPIOP1",
|
29
|
-
"DataladAOMICPIOP2",
|
30
|
-
"HCP1200",
|
31
|
-
"DataladHCP1200",
|
32
|
-
"MultipleDataGrabber",
|
33
|
-
"DMCC13Benchmark",
|
34
|
-
"PatternValidationMixin",
|
35
|
-
]
|
11
|
+
__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
__all__ = [
|
2
|
+
"BaseDataGrabber",
|
3
|
+
"DataladDataGrabber",
|
4
|
+
"PatternDataGrabber",
|
5
|
+
"PatternDataladDataGrabber",
|
6
|
+
"DataladAOMICID1000",
|
7
|
+
"DataladAOMICPIOP1",
|
8
|
+
"DataladAOMICPIOP2",
|
9
|
+
"HCP1200",
|
10
|
+
"DataladHCP1200",
|
11
|
+
"MultipleDataGrabber",
|
12
|
+
"DMCC13Benchmark",
|
13
|
+
"PatternValidationMixin",
|
14
|
+
]
|
15
|
+
|
16
|
+
# These 4 need to be in this order, otherwise it is a circular import
|
17
|
+
from .base import BaseDataGrabber
|
18
|
+
from .datalad_base import DataladDataGrabber
|
19
|
+
from .pattern import PatternDataGrabber
|
20
|
+
from .pattern_datalad import PatternDataladDataGrabber
|
21
|
+
|
22
|
+
from .aomic import DataladAOMICID1000, DataladAOMICPIOP1, DataladAOMICPIOP2
|
23
|
+
from .hcp1200 import HCP1200, DataladHCP1200
|
24
|
+
from .multiple import MultipleDataGrabber
|
25
|
+
from .dmcc13_benchmark import DMCC13Benchmark
|
26
|
+
|
27
|
+
from .pattern_validation_mixin import PatternValidationMixin
|
@@ -4,9 +4,7 @@
|
|
4
4
|
# Leonard Sasse <l.sasse@fz-juelich.de>
|
5
5
|
# License: AGPL
|
6
6
|
|
7
|
-
|
8
|
-
from .piop1 import DataladAOMICPIOP1
|
9
|
-
from .piop2 import DataladAOMICPIOP2
|
7
|
+
import lazy_loader as lazy
|
10
8
|
|
11
9
|
|
12
|
-
__all__ =
|
10
|
+
__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
|