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,138 @@
|
|
1
|
+
"""Provide onthefly functions for BrainPrint post-analysis."""
|
2
|
+
|
3
|
+
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
|
+
# License: AGPL
|
5
|
+
|
6
|
+
from typing import Optional
|
7
|
+
|
8
|
+
import numpy as np
|
9
|
+
import pandas as pd
|
10
|
+
|
11
|
+
from ..typing import StorageLike
|
12
|
+
from ..utils import raise_error
|
13
|
+
|
14
|
+
|
15
|
+
__all__ = ["normalize", "reweight"]
|
16
|
+
|
17
|
+
|
18
|
+
def normalize(
|
19
|
+
storage: StorageLike,
|
20
|
+
features: dict[str, dict[str, Optional[str]]],
|
21
|
+
kind: str,
|
22
|
+
) -> pd.DataFrame:
|
23
|
+
"""Read stored brainprint data and normalize either surfaces or volumes.
|
24
|
+
|
25
|
+
Parameters
|
26
|
+
----------
|
27
|
+
storage : storage-like
|
28
|
+
The storage class, for example, :class:`.HDF5FeatureStorage`.
|
29
|
+
features : dict, optional
|
30
|
+
The feature names or MD5 hashes to read as dict.
|
31
|
+
The dict should have the keys:
|
32
|
+
|
33
|
+
* ``"areas"`` (if ``kind="surface"``)
|
34
|
+
* ``"volumes"`` (if ``kind="volume"``)
|
35
|
+
* ``"eigenvalues"``
|
36
|
+
|
37
|
+
and the corresponding value for each of the keys is again
|
38
|
+
a dict with the keys:
|
39
|
+
|
40
|
+
* ``"feature_name"`` : str or None
|
41
|
+
* ``"feature_md5"`` : str or None
|
42
|
+
|
43
|
+
Either one of ``"feature_name"`` or ``"feature_md5"`` needs to be
|
44
|
+
not None for each first-level key, but both keys are mandatory.
|
45
|
+
|
46
|
+
kind : {"surface", "volume"}
|
47
|
+
The kind of normalization.
|
48
|
+
|
49
|
+
Returns
|
50
|
+
-------
|
51
|
+
pandas.DataFrame
|
52
|
+
The transformed feature as a ``pandas.DataFrame``.
|
53
|
+
|
54
|
+
Raises
|
55
|
+
------
|
56
|
+
ValueError
|
57
|
+
If ``kind`` is invalid.
|
58
|
+
|
59
|
+
"""
|
60
|
+
# Read storage
|
61
|
+
data_dict = {}
|
62
|
+
for k, v in features.items():
|
63
|
+
data_dict[k] = storage.read_df(**v) # type: ignore
|
64
|
+
|
65
|
+
# Check and normalize
|
66
|
+
valid_kind = ["surface", "volume"]
|
67
|
+
normalized_df = None
|
68
|
+
if kind == "surface":
|
69
|
+
eigenvalues_df = data_dict["eigenvalues"]
|
70
|
+
areas_df = data_dict["areas"]
|
71
|
+
normalized_df = eigenvalues_df.combine(
|
72
|
+
areas_df, lambda left, right: left * right
|
73
|
+
)
|
74
|
+
elif kind == "volume":
|
75
|
+
eigenvalues_df = data_dict["eigenvalues"]
|
76
|
+
volumes_df = data_dict["volumes"]
|
77
|
+
normalized_df = eigenvalues_df.combine(
|
78
|
+
volumes_df, lambda left, right: left * right ** np.divide(2.0, 3.0)
|
79
|
+
)
|
80
|
+
else:
|
81
|
+
raise_error(
|
82
|
+
"Invalid value for `kind`, should be one of: " f"{valid_kind}"
|
83
|
+
)
|
84
|
+
|
85
|
+
return normalized_df
|
86
|
+
|
87
|
+
|
88
|
+
def reweight(
|
89
|
+
storage: StorageLike,
|
90
|
+
feature_name: Optional[str] = None,
|
91
|
+
feature_md5: Optional[str] = None,
|
92
|
+
) -> pd.DataFrame:
|
93
|
+
"""Read stored brainprint data and reweight eigenvalues.
|
94
|
+
|
95
|
+
Parameters
|
96
|
+
----------
|
97
|
+
storage : storage-like
|
98
|
+
The storage class, for example, :class:`.HDF5FeatureStorage`.
|
99
|
+
feature_name : str, optional
|
100
|
+
Name of the feature to read (default None).
|
101
|
+
feature_md5 : str, optional
|
102
|
+
MD5 hash of the feature to read (default None).
|
103
|
+
|
104
|
+
Returns
|
105
|
+
-------
|
106
|
+
pandas.DataFrame
|
107
|
+
The transformed feature as a ``pandas.DataFrame``.
|
108
|
+
|
109
|
+
"""
|
110
|
+
# Read storage
|
111
|
+
eigenvalues_df = storage.read_df(
|
112
|
+
feature_name=feature_name, feature_md5=feature_md5
|
113
|
+
) # type: ignore
|
114
|
+
|
115
|
+
# Create data for operation
|
116
|
+
exploded_count_idx_df = (
|
117
|
+
eigenvalues_df.reset_index("eigenvalue")
|
118
|
+
.index.value_counts()
|
119
|
+
.apply(lambda x: np.arange(1, x + 1).astype(float))
|
120
|
+
.to_frame()
|
121
|
+
.explode("count")
|
122
|
+
)
|
123
|
+
idx_data = (
|
124
|
+
pd.concat(
|
125
|
+
[exploded_count_idx_df] * len(eigenvalues_df.columns), axis=1
|
126
|
+
)
|
127
|
+
.reset_index()
|
128
|
+
.drop("subject", axis=1, inplace=False)
|
129
|
+
.to_numpy()
|
130
|
+
)
|
131
|
+
idx_df = pd.DataFrame(
|
132
|
+
data=idx_data,
|
133
|
+
index=eigenvalues_df.index,
|
134
|
+
columns=eigenvalues_df.columns,
|
135
|
+
)
|
136
|
+
|
137
|
+
# Combine
|
138
|
+
return eigenvalues_df.combine(idx_df, lambda left, right: left / right)
|
@@ -4,27 +4,24 @@
|
|
4
4
|
# License: AGPL
|
5
5
|
|
6
6
|
|
7
|
-
from typing import
|
7
|
+
from typing import Optional
|
8
8
|
|
9
9
|
import pandas as pd
|
10
10
|
|
11
|
+
from ..typing import StorageLike
|
11
12
|
from ..utils import logger, raise_error, warn_with_log
|
12
13
|
|
13
14
|
|
14
|
-
if TYPE_CHECKING:
|
15
|
-
from junifer.storage import BaseFeatureStorage
|
16
|
-
|
17
|
-
|
18
15
|
__all__ = ["read_transform"]
|
19
16
|
|
20
17
|
|
21
18
|
def read_transform(
|
22
|
-
storage:
|
19
|
+
storage: StorageLike,
|
23
20
|
transform: str,
|
24
21
|
feature_name: Optional[str] = None,
|
25
22
|
feature_md5: Optional[str] = None,
|
26
|
-
transform_args: Optional[
|
27
|
-
transform_kw_args: Optional[
|
23
|
+
transform_args: Optional[tuple] = None,
|
24
|
+
transform_kw_args: Optional[dict] = None,
|
28
25
|
) -> pd.DataFrame:
|
29
26
|
"""Read stored feature and transform to specific statistical output.
|
30
27
|
|
junifer/pipeline/__init__.py
CHANGED
@@ -3,15 +3,7 @@
|
|
3
3
|
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
4
|
# License: AGPL
|
5
5
|
|
6
|
-
|
7
|
-
from .pipeline_step_mixin import PipelineStepMixin
|
8
|
-
from .update_meta_mixin import UpdateMetaMixin
|
9
|
-
from .workdir_manager import WorkDirManager
|
6
|
+
import lazy_loader as lazy
|
10
7
|
|
11
8
|
|
12
|
-
__all__ =
|
13
|
-
"registry",
|
14
|
-
"PipelineStepMixin",
|
15
|
-
"UpdateMetaMixin",
|
16
|
-
"WorkDirManager",
|
17
|
-
]
|
9
|
+
__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
__all__ = [
|
2
|
+
"PipelineComponentRegistry",
|
3
|
+
"PipelineStepMixin",
|
4
|
+
"UpdateMetaMixin",
|
5
|
+
"WorkDirManager",
|
6
|
+
"MarkerCollection",
|
7
|
+
]
|
8
|
+
|
9
|
+
from .pipeline_component_registry import PipelineComponentRegistry
|
10
|
+
from .pipeline_step_mixin import PipelineStepMixin
|
11
|
+
from .update_meta_mixin import UpdateMetaMixin
|
12
|
+
from .workdir_manager import WorkDirManager
|
13
|
+
from .marker_collection import MarkerCollection
|
@@ -5,20 +5,14 @@
|
|
5
5
|
# License: AGPL
|
6
6
|
|
7
7
|
from collections import Counter
|
8
|
-
from typing import
|
8
|
+
from typing import Optional
|
9
9
|
|
10
|
-
from ..datareader
|
11
|
-
from ..markers.base import BaseMarker
|
10
|
+
from ..datareader import DefaultDataReader
|
12
11
|
from ..pipeline import PipelineStepMixin, WorkDirManager
|
13
|
-
from ..
|
14
|
-
from ..storage.base import BaseFeatureStorage
|
12
|
+
from ..typing import DataGrabberLike, MarkerLike, PreprocessorLike, StorageLike
|
15
13
|
from ..utils import logger, raise_error
|
16
14
|
|
17
15
|
|
18
|
-
if TYPE_CHECKING:
|
19
|
-
from junifer.datagrabber import BaseDataGrabber
|
20
|
-
|
21
|
-
|
22
16
|
__all__ = ["MarkerCollection"]
|
23
17
|
|
24
18
|
|
@@ -45,10 +39,10 @@ class MarkerCollection:
|
|
45
39
|
|
46
40
|
def __init__(
|
47
41
|
self,
|
48
|
-
markers:
|
42
|
+
markers: list[MarkerLike],
|
49
43
|
datareader: Optional[PipelineStepMixin] = None,
|
50
|
-
preprocessors: Optional[
|
51
|
-
storage: Optional[
|
44
|
+
preprocessors: Optional[list[PreprocessorLike]] = None,
|
45
|
+
storage: Optional[StorageLike] = None,
|
52
46
|
):
|
53
47
|
# Check that the markers have different names
|
54
48
|
marker_names = [m.name for m in markers]
|
@@ -65,7 +59,7 @@ class MarkerCollection:
|
|
65
59
|
self._preprocessors = preprocessors
|
66
60
|
self._storage = storage
|
67
61
|
|
68
|
-
def fit(self, input:
|
62
|
+
def fit(self, input: dict[str, dict]) -> Optional[dict]:
|
69
63
|
"""Fit the pipeline.
|
70
64
|
|
71
65
|
Parameters
|
@@ -111,7 +105,7 @@ class MarkerCollection:
|
|
111
105
|
|
112
106
|
return None if self._storage else out
|
113
107
|
|
114
|
-
def validate(self, datagrabber:
|
108
|
+
def validate(self, datagrabber: DataGrabberLike) -> None:
|
115
109
|
"""Validate the pipeline.
|
116
110
|
|
117
111
|
Without doing any computation, check if the marker collection can
|
@@ -0,0 +1,294 @@
|
|
1
|
+
"""Provide a class for centralized pipeline component registry."""
|
2
|
+
|
3
|
+
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
4
|
+
# Leonard Sasse <l.sasse@fz-juelich.de>
|
5
|
+
# Synchon Mandal <s.mandal@fz-juelich.de>
|
6
|
+
# License: AGPL
|
7
|
+
|
8
|
+
import importlib
|
9
|
+
from collections.abc import Mapping
|
10
|
+
from typing import Optional, Union
|
11
|
+
|
12
|
+
from ..typing import DataGrabberLike, MarkerLike, PreprocessorLike, StorageLike
|
13
|
+
from ..utils import logger, raise_error
|
14
|
+
from ..utils.singleton import Singleton
|
15
|
+
|
16
|
+
|
17
|
+
__all__ = ["PipelineComponentRegistry"]
|
18
|
+
|
19
|
+
|
20
|
+
class PipelineComponentRegistry(metaclass=Singleton):
|
21
|
+
"""Class for pipeline component registry.
|
22
|
+
|
23
|
+
This class is a singleton and is used for managing pipeline components.
|
24
|
+
It serves as a centralized registry for built-in and third-party pipeline
|
25
|
+
components like datagrabbers, datareaders, preprocessors, markers and
|
26
|
+
storage.
|
27
|
+
|
28
|
+
Attributes
|
29
|
+
----------
|
30
|
+
steps : list of str
|
31
|
+
Valid pipeline steps.
|
32
|
+
components : dict
|
33
|
+
Registered components for valid pipeline steps.
|
34
|
+
|
35
|
+
"""
|
36
|
+
|
37
|
+
def __init__(self) -> None:
|
38
|
+
"""Initialize the class."""
|
39
|
+
# Valid steps for operation
|
40
|
+
self._steps = [
|
41
|
+
"datagrabber",
|
42
|
+
"datareader",
|
43
|
+
"preprocessing",
|
44
|
+
"marker",
|
45
|
+
"storage",
|
46
|
+
]
|
47
|
+
# Step to sub-package mapping
|
48
|
+
self._step_to_subpkg_mappings = {
|
49
|
+
"datagrabber": "datagrabber",
|
50
|
+
"datareader": "datareader",
|
51
|
+
"preprocessing": "preprocess",
|
52
|
+
"marker": "markers",
|
53
|
+
"storage": "storage",
|
54
|
+
}
|
55
|
+
# Component registry for valid steps
|
56
|
+
self._components = {
|
57
|
+
"datagrabber": {
|
58
|
+
"HCP1200": "HCP1200",
|
59
|
+
"BaseDataGrabber": "BaseDataGrabber",
|
60
|
+
"DataladAOMICID1000": "DataladAOMICID1000",
|
61
|
+
"DataladAOMICPIOP1": "DataladAOMICPIOP1",
|
62
|
+
"DataladAOMICPIOP2": "DataladAOMICPIOP2",
|
63
|
+
"DataladDataGrabber": "DataladDataGrabber",
|
64
|
+
"DataladHCP1200": "DataladHCP1200",
|
65
|
+
"DMCC13Benchmark": "DMCC13Benchmark",
|
66
|
+
"MultipleDataGrabber": "MultipleDataGrabber",
|
67
|
+
"PatternDataGrabber": "PatternDataGrabber",
|
68
|
+
"PatternDataladDataGrabber": "PatternDataladDataGrabber",
|
69
|
+
},
|
70
|
+
"datareader": {
|
71
|
+
"DefaultDataReader": "DefaultDataReader",
|
72
|
+
},
|
73
|
+
"preprocessing": {
|
74
|
+
"BasePreprocessor": "BasePreprocessor",
|
75
|
+
"Smoothing": "Smoothing",
|
76
|
+
"SpaceWarper": "SpaceWarper",
|
77
|
+
"fMRIPrepConfoundRemover": "fMRIPrepConfoundRemover",
|
78
|
+
},
|
79
|
+
"marker": {
|
80
|
+
"ALFFParcels": "ALFFParcels",
|
81
|
+
"ALFFSpheres": "ALFFSpheres",
|
82
|
+
"BaseMarker": "BaseMarker",
|
83
|
+
"BrainPrint": "BrainPrint",
|
84
|
+
"CrossParcellationFC": "CrossParcellationFC",
|
85
|
+
"EdgeCentricFCParcels": "EdgeCentricFCParcels",
|
86
|
+
"EdgeCentricFCSpheres": "EdgeCentricFCSpheres",
|
87
|
+
"FunctionalConnectivityParcels": (
|
88
|
+
"FunctionalConnectivityParcels"
|
89
|
+
),
|
90
|
+
"FunctionalConnectivitySpheres": (
|
91
|
+
"FunctionalConnectivitySpheres"
|
92
|
+
),
|
93
|
+
"ParcelAggregation": "ParcelAggregation",
|
94
|
+
"ReHoParcels": "ReHoParcels",
|
95
|
+
"ReHoSpheres": "ReHoSpheres",
|
96
|
+
"RSSETSMarker": "RSSETSMarker",
|
97
|
+
"SphereAggregation": "SphereAggregation",
|
98
|
+
"TemporalSNRParcels": "TemporalSNRParcels",
|
99
|
+
"TemporalSNRSpheres": "TemporalSNRSpheres",
|
100
|
+
},
|
101
|
+
"storage": {
|
102
|
+
"BaseFeatureStorage": "BaseFeatureStorage",
|
103
|
+
"HDF5FeatureStorage": "HDF5FeatureStorage",
|
104
|
+
"PandasBaseFeatureStorage": "PandasBaseFeatureStorage",
|
105
|
+
"SQLiteFeatureStorage": "SQLiteFeatureStorage",
|
106
|
+
},
|
107
|
+
}
|
108
|
+
|
109
|
+
def _check_valid_step(self, step: str) -> None:
|
110
|
+
"""Check if ``step`` is valid."""
|
111
|
+
if step not in self._steps:
|
112
|
+
raise_error(msg=f"Invalid step: {step}", klass=ValueError)
|
113
|
+
|
114
|
+
@property
|
115
|
+
def steps(self) -> list[str]:
|
116
|
+
"""Get valid pipeline steps."""
|
117
|
+
return self._steps
|
118
|
+
|
119
|
+
@property
|
120
|
+
def components(self) -> Mapping[str, Mapping[str, Union[str, type]]]:
|
121
|
+
"""Get registered components for valid pipeline steps."""
|
122
|
+
return self._components
|
123
|
+
|
124
|
+
def register(self, step: str, klass: type) -> None:
|
125
|
+
"""Register ``klass`` under ``step``.
|
126
|
+
|
127
|
+
Parameters
|
128
|
+
----------
|
129
|
+
step : str
|
130
|
+
Name of the pipeline step. For valid steps, check :meth:`.steps`.
|
131
|
+
klass : class
|
132
|
+
Class to be registered.
|
133
|
+
|
134
|
+
Raises
|
135
|
+
------
|
136
|
+
ValueError
|
137
|
+
If the ``step`` is invalid.
|
138
|
+
|
139
|
+
"""
|
140
|
+
# Verify step
|
141
|
+
self._check_valid_step(step)
|
142
|
+
# Log and register
|
143
|
+
name = klass.__name__
|
144
|
+
logger.info(f"Registering {name} in {step}")
|
145
|
+
self._components[step][name] = klass
|
146
|
+
|
147
|
+
def deregister(self, step: str, klass: type) -> None:
|
148
|
+
"""De-register ``klass`` under ``step``.
|
149
|
+
|
150
|
+
Parameters
|
151
|
+
----------
|
152
|
+
step : str
|
153
|
+
Name of the pipeline step. For valid steps, check :meth:`.steps`.
|
154
|
+
klass : class
|
155
|
+
Class to be de-registered.
|
156
|
+
|
157
|
+
Raises
|
158
|
+
------
|
159
|
+
ValueError
|
160
|
+
If the ``step`` is invalid.
|
161
|
+
|
162
|
+
"""
|
163
|
+
# Verify step
|
164
|
+
self._check_valid_step(step)
|
165
|
+
# Log and de-register
|
166
|
+
name = klass.__name__
|
167
|
+
logger.info(f"De-registering {name} in {step}")
|
168
|
+
_ = self._components[step].pop(name)
|
169
|
+
|
170
|
+
def step_components(self, step: str) -> list[str]:
|
171
|
+
"""Get registered components for ``step``.
|
172
|
+
|
173
|
+
Parameters
|
174
|
+
----------
|
175
|
+
step : str
|
176
|
+
Name of the pipeline step.
|
177
|
+
|
178
|
+
Returns
|
179
|
+
-------
|
180
|
+
list of str
|
181
|
+
List of registered component classes.
|
182
|
+
|
183
|
+
Raises
|
184
|
+
------
|
185
|
+
ValueError
|
186
|
+
If the ``step`` is invalid.
|
187
|
+
|
188
|
+
"""
|
189
|
+
# Verify step
|
190
|
+
self._check_valid_step(step)
|
191
|
+
|
192
|
+
return list(self._components[step].keys())
|
193
|
+
|
194
|
+
def get_class(self, step: str, name: str) -> type:
|
195
|
+
"""Get the class registered under ``name`` for ``step``.
|
196
|
+
|
197
|
+
Parameters
|
198
|
+
----------
|
199
|
+
step : str
|
200
|
+
Name of the pipeline step.
|
201
|
+
name : str
|
202
|
+
Name of the component.
|
203
|
+
|
204
|
+
Returns
|
205
|
+
-------
|
206
|
+
class
|
207
|
+
Registered class.
|
208
|
+
|
209
|
+
Raises
|
210
|
+
------
|
211
|
+
ValueError
|
212
|
+
If the ``step`` or ``name`` is invalid.
|
213
|
+
|
214
|
+
"""
|
215
|
+
# Verify step
|
216
|
+
self._check_valid_step(step)
|
217
|
+
# Verify step name
|
218
|
+
if name not in self._components[step]:
|
219
|
+
raise_error(msg=f"Invalid name: {name}", klass=ValueError)
|
220
|
+
|
221
|
+
# Check if first-time import, then import it
|
222
|
+
if isinstance(self._components[step][name], str):
|
223
|
+
klass = getattr(
|
224
|
+
importlib.import_module(
|
225
|
+
f"junifer.{self._step_to_subpkg_mappings[step]}"
|
226
|
+
),
|
227
|
+
name,
|
228
|
+
)
|
229
|
+
else:
|
230
|
+
klass = self._components[step][name]
|
231
|
+
|
232
|
+
return klass
|
233
|
+
|
234
|
+
def build_component_instance(
|
235
|
+
self,
|
236
|
+
step: str,
|
237
|
+
name: str,
|
238
|
+
baseclass: type,
|
239
|
+
init_params: Optional[dict] = None,
|
240
|
+
) -> Union[DataGrabberLike, PreprocessorLike, MarkerLike, StorageLike]:
|
241
|
+
"""Build an instance of class registered as ``name``.
|
242
|
+
|
243
|
+
Parameters
|
244
|
+
----------
|
245
|
+
step : str
|
246
|
+
Name of the pipeline step.
|
247
|
+
name : str
|
248
|
+
Name of the component.
|
249
|
+
baseclass : class
|
250
|
+
Base class to be checked against.
|
251
|
+
init_params : dict or None, optional
|
252
|
+
Parameters to pass to the class constructor (default None).
|
253
|
+
|
254
|
+
Returns
|
255
|
+
-------
|
256
|
+
object
|
257
|
+
An instance of the class registered as ``name`` under ``step``.
|
258
|
+
|
259
|
+
Raises
|
260
|
+
------
|
261
|
+
RuntimeError
|
262
|
+
If there is a problem creating the instance.
|
263
|
+
ValueError
|
264
|
+
If the created object with the given name is not a subclass of the
|
265
|
+
base class ``baseclass``.
|
266
|
+
|
267
|
+
"""
|
268
|
+
# Set default init parameters
|
269
|
+
if init_params is None:
|
270
|
+
init_params = {}
|
271
|
+
# Get registered class
|
272
|
+
logger.debug(f"Building {step}/{name}")
|
273
|
+
klass = self.get_class(step=step, name=name)
|
274
|
+
logger.debug(f"\tClass: {klass.__name__}")
|
275
|
+
logger.debug(f"\tInit params: {init_params}")
|
276
|
+
try:
|
277
|
+
# Create instance of the class
|
278
|
+
object_ = klass(**init_params)
|
279
|
+
except (ValueError, TypeError) as e:
|
280
|
+
raise_error(
|
281
|
+
msg=f"Failed to create {step} ({name}). Error: {e}",
|
282
|
+
klass=RuntimeError,
|
283
|
+
exception=e,
|
284
|
+
)
|
285
|
+
# Verify created instance belongs to the base class
|
286
|
+
if not isinstance(object_, baseclass):
|
287
|
+
raise_error(
|
288
|
+
msg=(
|
289
|
+
f"Invalid {step} ({object_.__class__.__name__}). "
|
290
|
+
f"Must inherit from {baseclass.__name__}"
|
291
|
+
),
|
292
|
+
klass=ValueError,
|
293
|
+
)
|
294
|
+
return object_
|
@@ -15,7 +15,7 @@ else:
|
|
15
15
|
|
16
16
|
from importlib.util import find_spec
|
17
17
|
from itertools import chain
|
18
|
-
from typing import Any
|
18
|
+
from typing import Any
|
19
19
|
|
20
20
|
from ..utils import raise_error
|
21
21
|
from .utils import check_ext_dependencies
|
@@ -27,7 +27,7 @@ __all__ = ["PipelineStepMixin"]
|
|
27
27
|
class PipelineStepMixin:
|
28
28
|
"""Mixin class for a pipeline step."""
|
29
29
|
|
30
|
-
def validate_input(self, input:
|
30
|
+
def validate_input(self, input: list[str]) -> list[str]:
|
31
31
|
"""Validate the input to the pipeline step.
|
32
32
|
|
33
33
|
Parameters
|
@@ -74,8 +74,8 @@ class PipelineStepMixin:
|
|
74
74
|
|
75
75
|
def _fit_transform(
|
76
76
|
self,
|
77
|
-
input:
|
78
|
-
) ->
|
77
|
+
input: dict[str, dict],
|
78
|
+
) -> dict[str, dict]:
|
79
79
|
"""Fit and transform.
|
80
80
|
|
81
81
|
Parameters
|
@@ -94,7 +94,7 @@ class PipelineStepMixin:
|
|
94
94
|
klass=NotImplementedError,
|
95
95
|
) # pragma: no cover
|
96
96
|
|
97
|
-
def validate(self, input:
|
97
|
+
def validate(self, input: list[str]) -> list[str]:
|
98
98
|
"""Validate the the pipeline step.
|
99
99
|
|
100
100
|
Parameters
|
@@ -196,10 +196,14 @@ class PipelineStepMixin:
|
|
196
196
|
for dependency in obj._CONDITIONAL_DEPENDENCIES:
|
197
197
|
if dependency["using"] == obj.using:
|
198
198
|
depends_on = dependency["depends_on"]
|
199
|
-
#
|
200
|
-
|
201
|
-
|
202
|
-
|
199
|
+
# Conditional to make `using="auto"` work
|
200
|
+
if not isinstance(depends_on, list):
|
201
|
+
depends_on = [depends_on]
|
202
|
+
for entry in depends_on:
|
203
|
+
# Check dependencies
|
204
|
+
_check_dependencies(entry)
|
205
|
+
# Check external dependencies
|
206
|
+
_check_ext_dependencies(entry)
|
203
207
|
|
204
208
|
# Check dependencies
|
205
209
|
_check_dependencies(self)
|
@@ -224,8 +228,8 @@ class PipelineStepMixin:
|
|
224
228
|
return outputs
|
225
229
|
|
226
230
|
def fit_transform(
|
227
|
-
self, input:
|
228
|
-
) ->
|
231
|
+
self, input: dict[str, dict], **kwargs: Any
|
232
|
+
) -> dict[str, dict]:
|
229
233
|
"""Fit and transform.
|
230
234
|
|
231
235
|
Parameters
|
File without changes
|
@@ -1,4 +1,4 @@
|
|
1
|
-
"""Provide tests for
|
1
|
+
"""Provide tests for MarkerCollection."""
|
2
2
|
|
3
3
|
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
4
4
|
# Synchon Mandal <s.mandal@fz-juelich.de>
|
@@ -12,10 +12,9 @@ from numpy.testing import assert_array_equal
|
|
12
12
|
from junifer.datareader.default import DefaultDataReader
|
13
13
|
from junifer.markers import (
|
14
14
|
FunctionalConnectivityParcels,
|
15
|
-
MarkerCollection,
|
16
15
|
ParcelAggregation,
|
17
16
|
)
|
18
|
-
from junifer.pipeline import PipelineStepMixin
|
17
|
+
from junifer.pipeline import MarkerCollection, PipelineStepMixin
|
19
18
|
from junifer.preprocess import fMRIPrepConfoundRemover
|
20
19
|
from junifer.storage import SQLiteFeatureStorage
|
21
20
|
from junifer.testing.datagrabbers import (
|