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
junifer/pipeline/__init__.pyi
CHANGED
|
@@ -3,11 +3,12 @@ __all__ = [
|
|
|
3
3
|
"AssetLoaderDispatcher",
|
|
4
4
|
"BaseDataDumpAsset",
|
|
5
5
|
"DataObjectDumper",
|
|
6
|
+
"ExtDep",
|
|
7
|
+
"MarkerCollection",
|
|
6
8
|
"PipelineComponentRegistry",
|
|
7
9
|
"PipelineStepMixin",
|
|
8
10
|
"UpdateMetaMixin",
|
|
9
11
|
"WorkDirManager",
|
|
10
|
-
"MarkerCollection",
|
|
11
12
|
]
|
|
12
13
|
|
|
13
14
|
from ._data_object_dumper import (
|
|
@@ -16,8 +17,9 @@ from ._data_object_dumper import (
|
|
|
16
17
|
BaseDataDumpAsset,
|
|
17
18
|
DataObjectDumper,
|
|
18
19
|
)
|
|
20
|
+
from .marker_collection import MarkerCollection
|
|
19
21
|
from .pipeline_component_registry import PipelineComponentRegistry
|
|
20
22
|
from .pipeline_step_mixin import PipelineStepMixin
|
|
21
23
|
from .update_meta_mixin import UpdateMetaMixin
|
|
24
|
+
from .utils import ExtDep
|
|
22
25
|
from .workdir_manager import WorkDirManager
|
|
23
|
-
from .marker_collection import MarkerCollection
|
|
@@ -6,16 +6,20 @@
|
|
|
6
6
|
|
|
7
7
|
from collections import Counter
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
import structlog
|
|
10
11
|
|
|
11
12
|
from ..datareader import DefaultDataReader
|
|
12
13
|
from ..pipeline import DataObjectDumper, PipelineStepMixin, WorkDirManager
|
|
13
14
|
from ..typing import DataGrabberLike, MarkerLike, PreprocessorLike, StorageLike
|
|
14
|
-
from ..utils import config,
|
|
15
|
+
from ..utils import config, raise_error
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
__all__ = ["MarkerCollection"]
|
|
18
19
|
|
|
20
|
+
_log = structlog.get_logger("junifer")
|
|
21
|
+
logger = _log.bind(pkg="pipeline")
|
|
22
|
+
|
|
19
23
|
|
|
20
24
|
class MarkerCollection:
|
|
21
25
|
"""Class for marker collection.
|
|
@@ -41,9 +45,9 @@ class MarkerCollection:
|
|
|
41
45
|
def __init__(
|
|
42
46
|
self,
|
|
43
47
|
markers: list[MarkerLike],
|
|
44
|
-
datareader:
|
|
45
|
-
preprocessors:
|
|
46
|
-
storage:
|
|
48
|
+
datareader: PipelineStepMixin | None = None,
|
|
49
|
+
preprocessors: list[PreprocessorLike] | None = None,
|
|
50
|
+
storage: StorageLike | None = None,
|
|
47
51
|
):
|
|
48
52
|
# Check that the markers have different names
|
|
49
53
|
marker_names = [m.name for m in markers]
|
|
@@ -60,7 +64,7 @@ class MarkerCollection:
|
|
|
60
64
|
self._preprocessors = preprocessors
|
|
61
65
|
self._storage = storage
|
|
62
66
|
|
|
63
|
-
def fit(self, input: dict[str, dict]) ->
|
|
67
|
+
def fit(self, input: dict[str, dict]) -> dict | None:
|
|
64
68
|
"""Fit the pipeline.
|
|
65
69
|
|
|
66
70
|
Parameters
|
|
@@ -162,7 +166,7 @@ class MarkerCollection:
|
|
|
162
166
|
logger.info(f"DataGrabber output type: {t_data}")
|
|
163
167
|
|
|
164
168
|
logger.info("Validating Data Reader:")
|
|
165
|
-
t_data = self._datareader.
|
|
169
|
+
t_data = self._datareader.validate_component(t_data)
|
|
166
170
|
logger.info(f"Data Reader output type: {t_data}")
|
|
167
171
|
|
|
168
172
|
if self._preprocessors is not None:
|
|
@@ -175,7 +179,7 @@ class MarkerCollection:
|
|
|
175
179
|
old_t_data = t_data.copy()
|
|
176
180
|
logger.info(f"Preprocessor input type: {t_data}")
|
|
177
181
|
# Validate preprocessor
|
|
178
|
-
new_t_data = preprocessor.
|
|
182
|
+
new_t_data = preprocessor.validate_component(old_t_data)
|
|
179
183
|
# Set new data types
|
|
180
184
|
t_data = list(set(old_t_data) | set(new_t_data))
|
|
181
185
|
logger.info(f"Preprocessor output type: {t_data}")
|
|
@@ -183,10 +187,10 @@ class MarkerCollection:
|
|
|
183
187
|
for marker in self._markers:
|
|
184
188
|
logger.info(f"Validating Marker: {marker.name}")
|
|
185
189
|
# Validate marker
|
|
186
|
-
m_data = marker.
|
|
190
|
+
m_data = marker.validate_component(input=t_data)
|
|
187
191
|
logger.info(f"Marker output type: {m_data}")
|
|
188
192
|
# Check storage for the marker
|
|
189
193
|
if self._storage is not None:
|
|
190
194
|
logger.info(f"Validating storage for {marker.name}")
|
|
191
195
|
# Validate storage
|
|
192
|
-
self._storage.
|
|
196
|
+
self._storage.validate_input(input_=m_data)
|
|
@@ -7,15 +7,19 @@
|
|
|
7
7
|
|
|
8
8
|
import importlib
|
|
9
9
|
from collections.abc import Mapping
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
import structlog
|
|
11
12
|
|
|
12
13
|
from ..typing import DataGrabberLike, MarkerLike, PreprocessorLike, StorageLike
|
|
13
|
-
from ..utils import
|
|
14
|
+
from ..utils import raise_error
|
|
14
15
|
from ..utils.singleton import Singleton
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
__all__ = ["PipelineComponentRegistry"]
|
|
18
19
|
|
|
20
|
+
_log = structlog.get_logger("junifer")
|
|
21
|
+
logger = _log.bind(pkg="pipeline")
|
|
22
|
+
|
|
19
23
|
|
|
20
24
|
class PipelineComponentRegistry(metaclass=Singleton):
|
|
21
25
|
"""Class for pipeline component registry.
|
|
@@ -79,24 +83,30 @@ class PipelineComponentRegistry(metaclass=Singleton):
|
|
|
79
83
|
"TemporalFilter": "TemporalFilter",
|
|
80
84
|
},
|
|
81
85
|
"marker": {
|
|
86
|
+
"ALFFMaps": "ALFFMaps",
|
|
82
87
|
"ALFFParcels": "ALFFParcels",
|
|
83
88
|
"ALFFSpheres": "ALFFSpheres",
|
|
84
89
|
"BaseMarker": "BaseMarker",
|
|
85
90
|
"BrainPrint": "BrainPrint",
|
|
86
91
|
"CrossParcellationFC": "CrossParcellationFC",
|
|
92
|
+
"EdgeCentricFCMaps": "EdgeCentricFCMaps",
|
|
87
93
|
"EdgeCentricFCParcels": "EdgeCentricFCParcels",
|
|
88
94
|
"EdgeCentricFCSpheres": "EdgeCentricFCSpheres",
|
|
95
|
+
"FunctionalConnectivityMaps": "FunctionalConnectivityMaps",
|
|
89
96
|
"FunctionalConnectivityParcels": (
|
|
90
97
|
"FunctionalConnectivityParcels"
|
|
91
98
|
),
|
|
92
99
|
"FunctionalConnectivitySpheres": (
|
|
93
100
|
"FunctionalConnectivitySpheres"
|
|
94
101
|
),
|
|
102
|
+
"MapsAggregation": "MapsAggregation",
|
|
95
103
|
"ParcelAggregation": "ParcelAggregation",
|
|
104
|
+
"ReHoMaps": "ReHoMaps",
|
|
96
105
|
"ReHoParcels": "ReHoParcels",
|
|
97
106
|
"ReHoSpheres": "ReHoSpheres",
|
|
98
107
|
"RSSETSMarker": "RSSETSMarker",
|
|
99
108
|
"SphereAggregation": "SphereAggregation",
|
|
109
|
+
"TemporalSNRMaps": "TemporalSNRMaps",
|
|
100
110
|
"TemporalSNRParcels": "TemporalSNRParcels",
|
|
101
111
|
"TemporalSNRSpheres": "TemporalSNRSpheres",
|
|
102
112
|
},
|
|
@@ -119,7 +129,7 @@ class PipelineComponentRegistry(metaclass=Singleton):
|
|
|
119
129
|
return self._steps
|
|
120
130
|
|
|
121
131
|
@property
|
|
122
|
-
def components(self) -> Mapping[str, Mapping[str,
|
|
132
|
+
def components(self) -> Mapping[str, Mapping[str, str | type]]:
|
|
123
133
|
"""Get registered components for valid pipeline steps."""
|
|
124
134
|
return self._components
|
|
125
135
|
|
|
@@ -238,8 +248,8 @@ class PipelineComponentRegistry(metaclass=Singleton):
|
|
|
238
248
|
step: str,
|
|
239
249
|
name: str,
|
|
240
250
|
baseclass: type,
|
|
241
|
-
init_params:
|
|
242
|
-
) ->
|
|
251
|
+
init_params: dict | None = None,
|
|
252
|
+
) -> DataGrabberLike | PreprocessorLike | MarkerLike | StorageLike:
|
|
243
253
|
"""Build an instance of class registered as ``name``.
|
|
244
254
|
|
|
245
255
|
Parameters
|
|
@@ -277,7 +287,16 @@ class PipelineComponentRegistry(metaclass=Singleton):
|
|
|
277
287
|
logger.debug(f"\tInit params: {init_params}")
|
|
278
288
|
try:
|
|
279
289
|
# Create instance of the class
|
|
280
|
-
|
|
290
|
+
if step == "datagrabber" and name == "MultipleDataGrabber":
|
|
291
|
+
dgs = []
|
|
292
|
+
for d in init_params["datagrabbers"]:
|
|
293
|
+
k = d.pop("kind")
|
|
294
|
+
dg_klass = self.get_class(step=step, name=k)
|
|
295
|
+
dg_obj = dg_klass(**d)
|
|
296
|
+
dgs.append(dg_obj)
|
|
297
|
+
object_ = klass(datagrabbers=dgs)
|
|
298
|
+
else:
|
|
299
|
+
object_ = klass(**init_params)
|
|
281
300
|
except (ValueError, TypeError) as e:
|
|
282
301
|
raise_error(
|
|
283
302
|
msg=f"Failed to create {step} ({name}). Error: {e}",
|
|
@@ -4,15 +4,7 @@
|
|
|
4
4
|
# Synchon Mandal <s.mandal@fz-juelich.de>
|
|
5
5
|
# License: AGPL
|
|
6
6
|
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if sys.version_info < (3, 11): # pragma: no cover
|
|
11
|
-
from importlib_metadata import packages_distributions
|
|
12
|
-
else:
|
|
13
|
-
from importlib.metadata import packages_distributions
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
from importlib.metadata import packages_distributions
|
|
16
8
|
from importlib.util import find_spec
|
|
17
9
|
from itertools import chain
|
|
18
10
|
from typing import Any
|
|
@@ -75,8 +67,8 @@ class PipelineStepMixin:
|
|
|
75
67
|
klass=NotImplementedError,
|
|
76
68
|
) # pragma: no cover
|
|
77
69
|
|
|
78
|
-
def
|
|
79
|
-
"""Validate the
|
|
70
|
+
def validate_component(self, input: list[str]) -> list[str]:
|
|
71
|
+
"""Validate the pipeline component.
|
|
80
72
|
|
|
81
73
|
Parameters
|
|
82
74
|
----------
|
|
@@ -228,5 +220,6 @@ class PipelineStepMixin:
|
|
|
228
220
|
The processed output of the pipeline step.
|
|
229
221
|
|
|
230
222
|
"""
|
|
231
|
-
|
|
223
|
+
# Needs to be validated if called directly via API
|
|
224
|
+
self.validate_component(input=list(input.keys()))
|
|
232
225
|
return self._fit_transform(input=input, **kwargs)
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
import pickle
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Union
|
|
9
8
|
|
|
10
9
|
import nibabel
|
|
11
10
|
import pytest
|
|
@@ -23,6 +22,9 @@ from junifer.testing.datagrabbers import PartlyCloudyTestingDataGrabber
|
|
|
23
22
|
from junifer.utils import config
|
|
24
23
|
|
|
25
24
|
|
|
25
|
+
pytestmark = pytest.mark.external
|
|
26
|
+
|
|
27
|
+
|
|
26
28
|
@pytest.mark.parametrize(
|
|
27
29
|
"dispatcher, inbuilt_key, ext_key, val",
|
|
28
30
|
[
|
|
@@ -36,9 +38,9 @@ from junifer.utils import config
|
|
|
36
38
|
],
|
|
37
39
|
)
|
|
38
40
|
def test_dispatcher_addition_errors(
|
|
39
|
-
dispatcher:
|
|
40
|
-
inbuilt_key:
|
|
41
|
-
ext_key:
|
|
41
|
+
dispatcher: AssetDumperDispatcher | AssetLoaderDispatcher,
|
|
42
|
+
inbuilt_key: str | type,
|
|
43
|
+
ext_key: str | type,
|
|
42
44
|
val: type,
|
|
43
45
|
) -> None:
|
|
44
46
|
"""Test asset dumper / loader addition errors.
|
|
@@ -70,9 +72,9 @@ def test_dispatcher_addition_errors(
|
|
|
70
72
|
],
|
|
71
73
|
)
|
|
72
74
|
def test_dispatcher_removal_errors(
|
|
73
|
-
dispatcher:
|
|
74
|
-
inbuilt_key:
|
|
75
|
-
ext_key:
|
|
75
|
+
dispatcher: AssetDumperDispatcher | AssetLoaderDispatcher,
|
|
76
|
+
inbuilt_key: str | type,
|
|
77
|
+
ext_key: str | type,
|
|
76
78
|
) -> None:
|
|
77
79
|
"""Test asset dumper / loader removal errors.
|
|
78
80
|
|
|
@@ -157,9 +159,7 @@ def test_data_object_dumper(
|
|
|
157
159
|
"wm_csf": "full",
|
|
158
160
|
},
|
|
159
161
|
detrend=True,
|
|
160
|
-
standardize=
|
|
161
|
-
low_pass=0.08,
|
|
162
|
-
high_pass=0.01,
|
|
162
|
+
standardize="zscore_sample",
|
|
163
163
|
),
|
|
164
164
|
],
|
|
165
165
|
markers=[
|
|
@@ -6,141 +6,145 @@
|
|
|
6
6
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
+
import numpy as np
|
|
9
10
|
import pytest
|
|
10
|
-
from numpy.testing import assert_array_equal
|
|
11
|
+
from numpy.testing import assert_allclose, assert_array_equal
|
|
11
12
|
|
|
12
|
-
from junifer.
|
|
13
|
-
from junifer.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
)
|
|
13
|
+
from junifer.datagrabber import DataType
|
|
14
|
+
from junifer.datareader import DefaultDataReader
|
|
15
|
+
from junifer.markers import FunctionalConnectivityParcels, ParcelAggregation
|
|
16
|
+
from junifer.markers.base import BaseMarker
|
|
17
17
|
from junifer.pipeline import MarkerCollection, PipelineStepMixin
|
|
18
18
|
from junifer.preprocess import fMRIPrepConfoundRemover
|
|
19
|
-
from junifer.storage import
|
|
20
|
-
from junifer.testing.datagrabbers import
|
|
21
|
-
PartlyCloudyTestingDataGrabber,
|
|
22
|
-
)
|
|
19
|
+
from junifer.storage import HDF5FeatureStorage, StorageType
|
|
20
|
+
from junifer.testing.datagrabbers import PartlyCloudyTestingDataGrabber
|
|
23
21
|
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
"""Test incorrect markers for MarkerCollection."""
|
|
27
|
-
wrong_markers = [
|
|
28
|
-
ParcelAggregation(
|
|
29
|
-
parcellation="Schaefer100x7",
|
|
30
|
-
method="mean",
|
|
31
|
-
name="gmd_schaefer100x7_mean",
|
|
32
|
-
),
|
|
33
|
-
ParcelAggregation(
|
|
34
|
-
parcellation="Schaefer100x7",
|
|
35
|
-
method="mean",
|
|
36
|
-
name="gmd_schaefer100x7_mean",
|
|
37
|
-
),
|
|
38
|
-
]
|
|
39
|
-
with pytest.raises(ValueError, match=r"must have different names"):
|
|
40
|
-
MarkerCollection(wrong_markers) # type: ignore
|
|
23
|
+
pytestmark = pytest.mark.external
|
|
41
24
|
|
|
25
|
+
PARCELLATION = "TianxS2x3TxMNInonlinear2009cAsym"
|
|
42
26
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
markers
|
|
27
|
+
|
|
28
|
+
def _markers() -> list[ParcelAggregation]:
|
|
29
|
+
"""Get markers aggregating the BOLD data in different ways.
|
|
30
|
+
|
|
31
|
+
Returns
|
|
32
|
+
-------
|
|
33
|
+
list of ParcelAggregation
|
|
34
|
+
The markers, named ``tian_mean``, ``tian_std`` and
|
|
35
|
+
``tian_trim_mean90``.
|
|
36
|
+
|
|
37
|
+
"""
|
|
38
|
+
return [
|
|
46
39
|
ParcelAggregation(
|
|
47
|
-
parcellation="
|
|
48
|
-
method="mean",
|
|
49
|
-
name="tian_mean",
|
|
40
|
+
parcellation=PARCELLATION, method="mean", name="tian_mean"
|
|
50
41
|
),
|
|
51
42
|
ParcelAggregation(
|
|
52
|
-
parcellation="
|
|
53
|
-
method="std",
|
|
54
|
-
name="tian_std",
|
|
43
|
+
parcellation=PARCELLATION, method="std", name="tian_std"
|
|
55
44
|
),
|
|
56
45
|
ParcelAggregation(
|
|
57
|
-
parcellation=
|
|
46
|
+
parcellation=PARCELLATION,
|
|
58
47
|
method="trim_mean",
|
|
59
48
|
method_params={"proportiontocut": 0.1},
|
|
60
49
|
name="tian_trim_mean90",
|
|
61
50
|
),
|
|
62
51
|
]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _fit(mc: MarkerCollection) -> dict | None:
|
|
55
|
+
"""Validate and fit a marker collection on one subject.
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
mc : MarkerCollection
|
|
60
|
+
The marker collection.
|
|
61
|
+
|
|
62
|
+
Returns
|
|
63
|
+
-------
|
|
64
|
+
dict or None
|
|
65
|
+
The output of the marker collection.
|
|
66
|
+
|
|
67
|
+
"""
|
|
68
|
+
dg = PartlyCloudyTestingDataGrabber(n_timepoints=50)
|
|
69
|
+
mc.validate(dg)
|
|
70
|
+
with dg:
|
|
71
|
+
return mc.fit(dg["sub-01"])
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_marker_collection_same_names() -> None:
|
|
75
|
+
"""Test markers must have different names."""
|
|
76
|
+
markers = [
|
|
77
|
+
ParcelAggregation(parcellation=PARCELLATION, method="mean", name="a"),
|
|
78
|
+
ParcelAggregation(parcellation=PARCELLATION, method="std", name="a"),
|
|
79
|
+
]
|
|
80
|
+
with pytest.raises(ValueError, match=r"must have different names"):
|
|
81
|
+
MarkerCollection(markers=markers) # type: ignore
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def test_marker_collection_defaults() -> None:
|
|
85
|
+
"""Test the defaults of MarkerCollection."""
|
|
86
|
+
markers = _markers()
|
|
63
87
|
mc = MarkerCollection(markers=markers) # type: ignore
|
|
64
88
|
assert mc._markers == markers
|
|
65
89
|
assert mc._preprocessors is None
|
|
66
90
|
assert mc._storage is None
|
|
67
91
|
assert isinstance(mc._datareader, DefaultDataReader)
|
|
68
92
|
|
|
69
|
-
# Create testing datagrabber
|
|
70
|
-
dg = PartlyCloudyTestingDataGrabber()
|
|
71
|
-
mc.validate(dg)
|
|
72
93
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
assert "
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
class BypassPreprocessing(PipelineStepMixin):
|
|
94
|
+
def test_marker_collection_fit() -> None:
|
|
95
|
+
"""Test MarkerCollection returns the output of each marker."""
|
|
96
|
+
out = _fit(MarkerCollection(markers=_markers())) # type: ignore
|
|
97
|
+
assert out is not None
|
|
98
|
+
assert set(out) == {"tian_mean", "tian_std", "tian_trim_mean90"}
|
|
99
|
+
for name in out:
|
|
100
|
+
aggregation = out[name]["BOLD"]["aggregation"]
|
|
101
|
+
assert {"data", "col_names", "meta"} <= set(aggregation)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_marker_collection_preprocessing() -> None:
|
|
105
|
+
"""Test MarkerCollection computes the markers on the preprocessed data."""
|
|
106
|
+
|
|
107
|
+
class Unchanged(PipelineStepMixin):
|
|
108
|
+
"""Preprocessing that returns the data unchanged."""
|
|
109
|
+
|
|
110
|
+
def validate_input(self, input):
|
|
111
|
+
return input
|
|
112
|
+
|
|
93
113
|
def fit_transform(self, input):
|
|
94
114
|
return input
|
|
95
115
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
116
|
+
out = _fit(MarkerCollection(markers=_markers())) # type: ignore
|
|
117
|
+
out_preprocessed = _fit(
|
|
118
|
+
MarkerCollection(
|
|
119
|
+
markers=_markers(), # type: ignore
|
|
120
|
+
preprocessors=[Unchanged()], # type: ignore
|
|
121
|
+
)
|
|
100
122
|
)
|
|
101
|
-
assert
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
def test_marker_collection_with_preprocessing() -> None:
|
|
115
|
-
"""Test MarkerCollection with preprocessing."""
|
|
116
|
-
markers = [
|
|
117
|
-
FunctionalConnectivityParcels(
|
|
118
|
-
parcellation="Schaefer100x17",
|
|
119
|
-
agg_method="mean",
|
|
120
|
-
name="Schaefer100x17_mean_FC",
|
|
121
|
-
),
|
|
122
|
-
FunctionalConnectivityParcels(
|
|
123
|
-
parcellation="TianxS2x3TxMNInonlinear2009cAsym",
|
|
124
|
-
agg_method="mean",
|
|
125
|
-
name="TianxS2x3TxMNInonlinear2009cAsym_mean_FC",
|
|
126
|
-
),
|
|
127
|
-
]
|
|
123
|
+
assert out is not None
|
|
124
|
+
assert out_preprocessed is not None
|
|
125
|
+
for name in out:
|
|
126
|
+
assert_array_equal(
|
|
127
|
+
out[name]["BOLD"]["aggregation"]["data"],
|
|
128
|
+
out_preprocessed[name]["BOLD"]["aggregation"]["data"],
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def test_marker_collection_validate_preprocessing() -> None:
|
|
133
|
+
"""Test MarkerCollection validates with a confound removal step."""
|
|
128
134
|
mc = MarkerCollection(
|
|
129
|
-
markers=
|
|
135
|
+
markers=[ # type: ignore
|
|
136
|
+
FunctionalConnectivityParcels(
|
|
137
|
+
parcellation=PARCELLATION, agg_method="mean", name="tian_fc"
|
|
138
|
+
),
|
|
139
|
+
],
|
|
130
140
|
preprocessors=[fMRIPrepConfoundRemover()],
|
|
131
141
|
)
|
|
132
|
-
assert mc._markers == markers
|
|
133
142
|
assert mc._preprocessors is not None
|
|
134
|
-
|
|
135
|
-
assert isinstance(mc._datareader, DefaultDataReader)
|
|
136
|
-
|
|
137
|
-
# Create testing datagrabber
|
|
138
|
-
dg = PartlyCloudyTestingDataGrabber(reduce_confounds=False)
|
|
139
|
-
mc.validate(dg)
|
|
143
|
+
mc.validate(PartlyCloudyTestingDataGrabber(reduce_confounds=False))
|
|
140
144
|
|
|
141
145
|
|
|
142
146
|
def test_marker_collection_storage(tmp_path: Path) -> None:
|
|
143
|
-
"""Test
|
|
147
|
+
"""Test MarkerCollection stores the output of each marker.
|
|
144
148
|
|
|
145
149
|
Parameters
|
|
146
150
|
----------
|
|
@@ -148,74 +152,47 @@ def test_marker_collection_storage(tmp_path: Path) -> None:
|
|
|
148
152
|
The path to the test directory.
|
|
149
153
|
|
|
150
154
|
"""
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
155
|
+
storage = HDF5FeatureStorage(uri=tmp_path / "features.hdf5")
|
|
156
|
+
mc = MarkerCollection(markers=_markers(), storage=storage) # type: ignore
|
|
157
|
+
assert mc._storage is storage
|
|
158
|
+
# Nothing is returned when storing
|
|
159
|
+
assert _fit(mc) is None
|
|
160
|
+
|
|
161
|
+
# The stored features are the same as the ones returned without storage
|
|
162
|
+
out = _fit(MarkerCollection(markers=_markers())) # type: ignore
|
|
163
|
+
assert out is not None
|
|
164
|
+
features = storage.list_features()
|
|
165
|
+
assert len(features) == len(out)
|
|
166
|
+
for md5, feature in features.items():
|
|
167
|
+
# Features are named "<type>_<marker>_<feature>"
|
|
168
|
+
name = feature["name"].removeprefix("BOLD_")
|
|
169
|
+
name = name.removesuffix("_aggregation")
|
|
170
|
+
aggregation = out[name]["BOLD"]["aggregation"]
|
|
171
|
+
stored = storage.read_df(feature_md5=md5)
|
|
172
|
+
# The storage casts to float32
|
|
173
|
+
assert_allclose(
|
|
174
|
+
stored[aggregation["col_names"]].to_numpy(),
|
|
175
|
+
aggregation["data"],
|
|
176
|
+
rtol=1e-6,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def test_marker_collection_marker_changes_data() -> None:
|
|
181
|
+
"""Test markers cannot change the data shared with the other markers."""
|
|
182
|
+
|
|
183
|
+
class ChangingMarker(BaseMarker):
|
|
184
|
+
"""Marker that replaces the BOLD data."""
|
|
185
|
+
|
|
186
|
+
_MARKER_INOUT_MAPPINGS = { # noqa: RUF012
|
|
187
|
+
DataType.BOLD: {"feat": StorageType.Vector},
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
def compute(self, input, extra_input=None):
|
|
191
|
+
input["data"] = "changed"
|
|
192
|
+
return {"feat": {"data": np.zeros((1, 1)), "col_names": ["x"]}}
|
|
187
193
|
|
|
188
|
-
|
|
189
|
-
markers=
|
|
190
|
-
datareader=DefaultDataReader(), # type: ignore
|
|
194
|
+
mc = MarkerCollection(
|
|
195
|
+
markers=[ChangingMarker(name="changing"), *_markers()] # type: ignore
|
|
191
196
|
)
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
with dg:
|
|
196
|
-
input = dg["sub-01"]
|
|
197
|
-
out = mc2.fit(input)
|
|
198
|
-
|
|
199
|
-
features = storage.list_features()
|
|
200
|
-
assert len(features) == 3
|
|
201
|
-
|
|
202
|
-
feature_md5 = next(iter(features.keys()))
|
|
203
|
-
t_feature = storage.read_df(feature_md5=feature_md5)
|
|
204
|
-
fname = "tian_mean"
|
|
205
|
-
t_data = out[fname]["BOLD"]["aggregation"]["data"] # type: ignore
|
|
206
|
-
cols = out[fname]["BOLD"]["aggregation"]["col_names"] # type: ignore
|
|
207
|
-
assert_array_equal(t_feature[cols].values, t_data) # type: ignore
|
|
208
|
-
|
|
209
|
-
feature_md5 = list(features.keys())[1]
|
|
210
|
-
t_feature = storage.read_df(feature_md5=feature_md5)
|
|
211
|
-
fname = "tian_std"
|
|
212
|
-
t_data = out[fname]["BOLD"]["aggregation"]["data"] # type: ignore
|
|
213
|
-
cols = out[fname]["BOLD"]["aggregation"]["col_names"] # type: ignore
|
|
214
|
-
assert_array_equal(t_feature[cols].values, t_data) # type: ignore
|
|
215
|
-
|
|
216
|
-
feature_md5 = list(features.keys())[2]
|
|
217
|
-
t_feature = storage.read_df(feature_md5=feature_md5)
|
|
218
|
-
fname = "tian_trim_mean90"
|
|
219
|
-
t_data = out[fname]["BOLD"]["aggregation"]["data"] # type: ignore
|
|
220
|
-
cols = out[fname]["BOLD"]["aggregation"]["col_names"] # type: ignore
|
|
221
|
-
assert_array_equal(t_feature[cols].values, t_data) # type: ignore
|
|
197
|
+
with pytest.raises(RuntimeError, match=r"changing changed .*BOLD.data"):
|
|
198
|
+
_fit(mc)
|