junifer 0.0.4.dev829__py3-none-any.whl → 0.0.5__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 +17 -0
- junifer/_version.py +2 -2
- junifer/api/__init__.py +4 -1
- junifer/api/cli.py +91 -1
- junifer/api/decorators.py +9 -0
- junifer/api/functions.py +56 -10
- junifer/api/parser.py +3 -0
- junifer/api/queue_context/__init__.py +4 -1
- junifer/api/queue_context/gnu_parallel_local_adapter.py +16 -6
- junifer/api/queue_context/htcondor_adapter.py +16 -5
- junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +41 -12
- junifer/api/queue_context/tests/test_htcondor_adapter.py +48 -15
- junifer/api/res/afni/run_afni_docker.sh +1 -1
- junifer/api/res/ants/run_ants_docker.sh +1 -1
- junifer/api/res/freesurfer/mri_binarize +3 -0
- junifer/api/res/freesurfer/mri_mc +3 -0
- junifer/api/res/freesurfer/mri_pretess +3 -0
- junifer/api/res/freesurfer/mris_convert +3 -0
- junifer/api/res/freesurfer/run_freesurfer_docker.sh +61 -0
- junifer/api/res/fsl/run_fsl_docker.sh +1 -1
- junifer/api/res/{run_conda.sh → run_conda.bash} +1 -1
- junifer/api/res/run_conda.zsh +23 -0
- junifer/api/res/run_venv.bash +22 -0
- junifer/api/res/{run_venv.sh → run_venv.zsh} +1 -1
- junifer/api/tests/test_api_utils.py +4 -2
- junifer/api/tests/test_cli.py +83 -0
- junifer/api/tests/test_functions.py +27 -2
- junifer/configs/__init__.py +1 -1
- junifer/configs/juseless/__init__.py +4 -1
- junifer/configs/juseless/datagrabbers/__init__.py +10 -1
- junifer/configs/juseless/datagrabbers/aomic_id1000_vbm.py +4 -3
- junifer/configs/juseless/datagrabbers/camcan_vbm.py +3 -0
- junifer/configs/juseless/datagrabbers/ixi_vbm.py +4 -3
- junifer/configs/juseless/datagrabbers/tests/test_ucla.py +1 -3
- junifer/configs/juseless/datagrabbers/ucla.py +12 -9
- junifer/configs/juseless/datagrabbers/ukb_vbm.py +3 -0
- junifer/data/__init__.py +21 -1
- junifer/data/coordinates.py +10 -19
- junifer/data/masks/ukb/UKB_15K_GM_template.nii.gz +0 -0
- junifer/data/masks.py +58 -87
- junifer/data/parcellations.py +14 -3
- junifer/data/template_spaces.py +4 -1
- junifer/data/tests/test_masks.py +26 -37
- junifer/data/utils.py +3 -0
- junifer/datagrabber/__init__.py +18 -1
- junifer/datagrabber/aomic/__init__.py +3 -0
- junifer/datagrabber/aomic/id1000.py +70 -37
- junifer/datagrabber/aomic/piop1.py +69 -36
- junifer/datagrabber/aomic/piop2.py +71 -38
- junifer/datagrabber/aomic/tests/test_id1000.py +44 -100
- junifer/datagrabber/aomic/tests/test_piop1.py +65 -108
- junifer/datagrabber/aomic/tests/test_piop2.py +45 -102
- junifer/datagrabber/base.py +13 -6
- junifer/datagrabber/datalad_base.py +13 -1
- junifer/datagrabber/dmcc13_benchmark.py +36 -53
- junifer/datagrabber/hcp1200/__init__.py +3 -0
- junifer/datagrabber/hcp1200/datalad_hcp1200.py +3 -0
- junifer/datagrabber/hcp1200/hcp1200.py +4 -1
- junifer/datagrabber/multiple.py +45 -6
- junifer/datagrabber/pattern.py +170 -62
- junifer/datagrabber/pattern_datalad.py +25 -12
- junifer/datagrabber/pattern_validation_mixin.py +388 -0
- junifer/datagrabber/tests/test_datalad_base.py +4 -4
- junifer/datagrabber/tests/test_dmcc13_benchmark.py +46 -19
- junifer/datagrabber/tests/test_multiple.py +161 -84
- junifer/datagrabber/tests/test_pattern.py +45 -0
- junifer/datagrabber/tests/test_pattern_datalad.py +4 -4
- junifer/datagrabber/tests/test_pattern_validation_mixin.py +249 -0
- junifer/datareader/__init__.py +4 -1
- junifer/datareader/default.py +95 -43
- junifer/external/BrainPrint/brainprint/__init__.py +4 -0
- junifer/external/BrainPrint/brainprint/_version.py +3 -0
- junifer/external/BrainPrint/brainprint/asymmetry.py +91 -0
- junifer/external/BrainPrint/brainprint/brainprint.py +441 -0
- junifer/external/BrainPrint/brainprint/surfaces.py +258 -0
- junifer/external/BrainPrint/brainprint/utils/__init__.py +1 -0
- junifer/external/BrainPrint/brainprint/utils/_config.py +112 -0
- junifer/external/BrainPrint/brainprint/utils/utils.py +188 -0
- junifer/external/__init__.py +1 -1
- junifer/external/nilearn/__init__.py +5 -1
- junifer/external/nilearn/junifer_connectivity_measure.py +483 -0
- junifer/external/nilearn/junifer_nifti_spheres_masker.py +23 -9
- junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +1089 -0
- junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +76 -1
- junifer/markers/__init__.py +23 -1
- junifer/markers/base.py +68 -28
- junifer/markers/brainprint.py +459 -0
- junifer/markers/collection.py +10 -2
- junifer/markers/complexity/__init__.py +10 -0
- junifer/markers/complexity/complexity_base.py +26 -43
- junifer/markers/complexity/hurst_exponent.py +3 -0
- junifer/markers/complexity/multiscale_entropy_auc.py +3 -0
- junifer/markers/complexity/perm_entropy.py +3 -0
- junifer/markers/complexity/range_entropy.py +3 -0
- junifer/markers/complexity/range_entropy_auc.py +3 -0
- junifer/markers/complexity/sample_entropy.py +3 -0
- junifer/markers/complexity/tests/test_hurst_exponent.py +11 -3
- junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +11 -3
- junifer/markers/complexity/tests/test_perm_entropy.py +11 -3
- junifer/markers/complexity/tests/test_range_entropy.py +11 -3
- junifer/markers/complexity/tests/test_range_entropy_auc.py +11 -3
- junifer/markers/complexity/tests/test_sample_entropy.py +11 -3
- junifer/markers/complexity/tests/test_weighted_perm_entropy.py +11 -3
- junifer/markers/complexity/weighted_perm_entropy.py +3 -0
- junifer/markers/ets_rss.py +27 -42
- junifer/markers/falff/__init__.py +3 -0
- junifer/markers/falff/_afni_falff.py +5 -2
- junifer/markers/falff/_junifer_falff.py +3 -0
- junifer/markers/falff/falff_base.py +20 -46
- junifer/markers/falff/falff_parcels.py +56 -27
- junifer/markers/falff/falff_spheres.py +60 -29
- junifer/markers/falff/tests/test_falff_parcels.py +39 -23
- junifer/markers/falff/tests/test_falff_spheres.py +39 -23
- junifer/markers/functional_connectivity/__init__.py +9 -0
- junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +63 -60
- junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +45 -32
- junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +49 -36
- junifer/markers/functional_connectivity/functional_connectivity_base.py +71 -70
- junifer/markers/functional_connectivity/functional_connectivity_parcels.py +34 -25
- junifer/markers/functional_connectivity/functional_connectivity_spheres.py +40 -30
- junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +11 -7
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +27 -7
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +28 -12
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +35 -11
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +36 -62
- junifer/markers/parcel_aggregation.py +47 -61
- junifer/markers/reho/__init__.py +3 -0
- junifer/markers/reho/_afni_reho.py +5 -2
- junifer/markers/reho/_junifer_reho.py +4 -1
- junifer/markers/reho/reho_base.py +8 -27
- junifer/markers/reho/reho_parcels.py +28 -17
- junifer/markers/reho/reho_spheres.py +27 -18
- junifer/markers/reho/tests/test_reho_parcels.py +8 -3
- junifer/markers/reho/tests/test_reho_spheres.py +8 -3
- junifer/markers/sphere_aggregation.py +43 -59
- junifer/markers/temporal_snr/__init__.py +3 -0
- junifer/markers/temporal_snr/temporal_snr_base.py +23 -32
- junifer/markers/temporal_snr/temporal_snr_parcels.py +9 -6
- junifer/markers/temporal_snr/temporal_snr_spheres.py +9 -6
- junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +6 -3
- junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +6 -3
- junifer/markers/tests/test_brainprint.py +58 -0
- junifer/markers/tests/test_collection.py +9 -8
- junifer/markers/tests/test_ets_rss.py +15 -9
- junifer/markers/tests/test_markers_base.py +17 -18
- junifer/markers/tests/test_parcel_aggregation.py +93 -32
- junifer/markers/tests/test_sphere_aggregation.py +72 -19
- junifer/onthefly/__init__.py +4 -1
- junifer/onthefly/read_transform.py +3 -0
- junifer/pipeline/__init__.py +9 -1
- junifer/pipeline/pipeline_step_mixin.py +21 -4
- junifer/pipeline/registry.py +3 -0
- junifer/pipeline/singleton.py +3 -0
- junifer/pipeline/tests/test_registry.py +1 -1
- junifer/pipeline/update_meta_mixin.py +3 -0
- junifer/pipeline/utils.py +67 -1
- junifer/pipeline/workdir_manager.py +3 -0
- junifer/preprocess/__init__.py +10 -2
- junifer/preprocess/base.py +6 -3
- junifer/preprocess/confounds/__init__.py +3 -0
- junifer/preprocess/confounds/fmriprep_confound_remover.py +47 -60
- junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +72 -113
- junifer/preprocess/smoothing/__init__.py +9 -0
- junifer/preprocess/smoothing/_afni_smoothing.py +119 -0
- junifer/preprocess/smoothing/_fsl_smoothing.py +116 -0
- junifer/preprocess/smoothing/_nilearn_smoothing.py +69 -0
- junifer/preprocess/smoothing/smoothing.py +174 -0
- junifer/preprocess/smoothing/tests/test_smoothing.py +94 -0
- junifer/preprocess/warping/__init__.py +3 -0
- junifer/preprocess/warping/_ants_warper.py +3 -0
- junifer/preprocess/warping/_fsl_warper.py +3 -0
- junifer/stats.py +4 -1
- junifer/storage/__init__.py +9 -1
- junifer/storage/base.py +40 -1
- junifer/storage/hdf5.py +71 -9
- junifer/storage/pandas_base.py +3 -0
- junifer/storage/sqlite.py +3 -0
- junifer/storage/tests/test_hdf5.py +82 -10
- junifer/storage/utils.py +9 -0
- junifer/testing/__init__.py +4 -1
- junifer/testing/datagrabbers.py +13 -6
- junifer/testing/tests/test_partlycloudytesting_datagrabber.py +7 -7
- junifer/testing/utils.py +3 -0
- junifer/utils/__init__.py +13 -2
- junifer/utils/fs.py +3 -0
- junifer/utils/helpers.py +32 -1
- junifer/utils/logging.py +33 -4
- junifer/utils/tests/test_logging.py +8 -0
- {junifer-0.0.4.dev829.dist-info → junifer-0.0.5.dist-info}/METADATA +17 -16
- junifer-0.0.5.dist-info/RECORD +275 -0
- {junifer-0.0.4.dev829.dist-info → junifer-0.0.5.dist-info}/WHEEL +1 -1
- junifer/datagrabber/tests/test_datagrabber_utils.py +0 -218
- junifer/datagrabber/utils.py +0 -230
- junifer/preprocess/ants/__init__.py +0 -4
- junifer/preprocess/ants/ants_apply_transforms_warper.py +0 -185
- junifer/preprocess/ants/tests/test_ants_apply_transforms_warper.py +0 -56
- junifer/preprocess/bold_warper.py +0 -265
- junifer/preprocess/fsl/__init__.py +0 -4
- junifer/preprocess/fsl/apply_warper.py +0 -179
- junifer/preprocess/fsl/tests/test_apply_warper.py +0 -45
- junifer/preprocess/tests/test_bold_warper.py +0 -159
- junifer-0.0.4.dev829.dist-info/RECORD +0 -257
- {junifer-0.0.4.dev829.dist-info → junifer-0.0.5.dist-info}/AUTHORS.rst +0 -0
- {junifer-0.0.4.dev829.dist-info → junifer-0.0.5.dist-info}/LICENSE.md +0 -0
- {junifer-0.0.4.dev829.dist-info → junifer-0.0.5.dist-info}/entry_points.txt +0 -0
- {junifer-0.0.4.dev829.dist-info → junifer-0.0.5.dist-info}/top_level.txt +0 -0
@@ -4,12 +4,14 @@
|
|
4
4
|
# License: AGPL
|
5
5
|
|
6
6
|
import warnings
|
7
|
+
from typing import List, Tuple
|
7
8
|
|
8
9
|
import nibabel
|
9
10
|
import numpy as np
|
10
11
|
import pytest
|
11
12
|
from nilearn._utils import data_gen
|
12
13
|
from nilearn.image import get_data
|
14
|
+
from nilearn.maskers import NiftiSpheresMasker
|
13
15
|
from numpy.testing import assert_array_equal
|
14
16
|
|
15
17
|
from junifer.external.nilearn import JuniferNiftiSpheresMasker
|
@@ -17,7 +19,7 @@ from junifer.external.nilearn import JuniferNiftiSpheresMasker
|
|
17
19
|
|
18
20
|
# New BSD License
|
19
21
|
|
20
|
-
# Copyright (c)
|
22
|
+
# Copyright (c) The nilearn developers.
|
21
23
|
# All rights reserved.
|
22
24
|
|
23
25
|
|
@@ -331,3 +333,76 @@ def test_nifti_spheres_masker_io_shapes() -> None:
|
|
331
333
|
)
|
332
334
|
test_data = masker.transform(img_4d)
|
333
335
|
assert test_data.shape == (n_volumes, n_regions)
|
336
|
+
|
337
|
+
|
338
|
+
@pytest.mark.parametrize(
|
339
|
+
"shape",
|
340
|
+
[
|
341
|
+
(10, 11, 12),
|
342
|
+
(10, 11, 12, 5),
|
343
|
+
],
|
344
|
+
)
|
345
|
+
@pytest.mark.parametrize(
|
346
|
+
"radius, allow_overlap",
|
347
|
+
[
|
348
|
+
(2.0, True),
|
349
|
+
(2.0, False),
|
350
|
+
(3.0, True),
|
351
|
+
(4.0, True),
|
352
|
+
(5.0, True),
|
353
|
+
],
|
354
|
+
)
|
355
|
+
@pytest.mark.parametrize(
|
356
|
+
"coords",
|
357
|
+
[
|
358
|
+
[(1, 1, 1)],
|
359
|
+
[(1, 1, 1), (4, 4, 4)],
|
360
|
+
[(1, 1, 1), (4, 4, 4), (10, 10, 10)],
|
361
|
+
],
|
362
|
+
)
|
363
|
+
def test_junifer_and_nilearn_mean_agg_are_equal(
|
364
|
+
shape: Tuple[int, ...],
|
365
|
+
radius: float,
|
366
|
+
allow_overlap: bool,
|
367
|
+
coords: List[Tuple[int, int, int]],
|
368
|
+
) -> None:
|
369
|
+
"""Test junifer's masker behaves same as nilearn's when agg is mean.
|
370
|
+
|
371
|
+
Parameters
|
372
|
+
----------
|
373
|
+
shape : tuple of int
|
374
|
+
The parametrized shape of the input image.
|
375
|
+
radius : float
|
376
|
+
The parametrized radius of the spheres.
|
377
|
+
allow_overlap : bool
|
378
|
+
The parametrized option to overlap spheres or not.
|
379
|
+
coords : list of tuple of int, int and int
|
380
|
+
The parametrized seeds.
|
381
|
+
|
382
|
+
"""
|
383
|
+
# Set affine
|
384
|
+
affine = np.eye(4)
|
385
|
+
# Generate random image
|
386
|
+
input_img, mask_img = data_gen.generate_random_img(
|
387
|
+
shape=shape,
|
388
|
+
affine=affine,
|
389
|
+
)
|
390
|
+
# Compute junifer's version
|
391
|
+
junifer_masker = JuniferNiftiSpheresMasker(
|
392
|
+
seeds=coords,
|
393
|
+
radius=radius,
|
394
|
+
allow_overlap=allow_overlap,
|
395
|
+
mask_img=mask_img,
|
396
|
+
)
|
397
|
+
junifer_output = junifer_masker.fit_transform(input_img)
|
398
|
+
# Compute nilearn's version
|
399
|
+
nilearn_masker = NiftiSpheresMasker(
|
400
|
+
seeds=coords,
|
401
|
+
radius=radius,
|
402
|
+
allow_overlap=allow_overlap,
|
403
|
+
mask_img=mask_img,
|
404
|
+
)
|
405
|
+
nilearn_output = nilearn_masker.fit_transform(input_img)
|
406
|
+
# Checks
|
407
|
+
assert junifer_output.shape == nilearn_output.shape
|
408
|
+
np.testing.assert_almost_equal(junifer_output, nilearn_output)
|
junifer/markers/__init__.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
"""
|
1
|
+
"""Markers for feature extraction."""
|
2
2
|
|
3
3
|
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
4
4
|
# Leonard Sasse <l.sasse@fz-juelich.de>
|
@@ -23,3 +23,25 @@ from .temporal_snr import (
|
|
23
23
|
TemporalSNRParcels,
|
24
24
|
TemporalSNRSpheres,
|
25
25
|
)
|
26
|
+
from .brainprint import BrainPrint
|
27
|
+
|
28
|
+
|
29
|
+
__all__ = [
|
30
|
+
"BaseMarker",
|
31
|
+
"MarkerCollection",
|
32
|
+
"RSSETSMarker",
|
33
|
+
"ParcelAggregation",
|
34
|
+
"SphereAggregation",
|
35
|
+
"FunctionalConnectivityParcels",
|
36
|
+
"FunctionalConnectivitySpheres",
|
37
|
+
"CrossParcellationFC",
|
38
|
+
"EdgeCentricFCParcels",
|
39
|
+
"EdgeCentricFCSpheres",
|
40
|
+
"ReHoParcels",
|
41
|
+
"ReHoSpheres",
|
42
|
+
"ALFFParcels",
|
43
|
+
"ALFFSpheres",
|
44
|
+
"TemporalSNRParcels",
|
45
|
+
"TemporalSNRSpheres",
|
46
|
+
"BrainPrint",
|
47
|
+
]
|
junifer/markers/base.py
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
# License: AGPL
|
6
6
|
|
7
7
|
from abc import ABC, abstractmethod
|
8
|
+
from copy import deepcopy
|
8
9
|
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
|
9
10
|
|
10
11
|
from ..pipeline import PipelineStepMixin, UpdateMetaMixin
|
@@ -15,20 +16,28 @@ if TYPE_CHECKING:
|
|
15
16
|
from junifer.storage import BaseFeatureStorage
|
16
17
|
|
17
18
|
|
19
|
+
__all__ = ["BaseMarker"]
|
20
|
+
|
21
|
+
|
18
22
|
class BaseMarker(ABC, PipelineStepMixin, UpdateMetaMixin):
|
19
23
|
"""Abstract base class for all markers.
|
20
24
|
|
25
|
+
For every interface that is required, one needs to provide a concrete
|
26
|
+
implementation of this abstract class.
|
27
|
+
|
21
28
|
Parameters
|
22
29
|
----------
|
23
|
-
on : str or list of str
|
24
|
-
The
|
25
|
-
available data.
|
30
|
+
on : str or list of str or None, optional
|
31
|
+
The data type to apply the marker on. If None,
|
32
|
+
will work on all available data types (default None).
|
26
33
|
name : str, optional
|
27
|
-
The name of the marker.
|
34
|
+
The name of the marker. If None, will use the class name as the
|
28
35
|
name of the marker (default None).
|
29
36
|
|
30
37
|
Raises
|
31
38
|
------
|
39
|
+
AttributeError
|
40
|
+
If the marker does not have `_MARKER_INOUT_MAPPINGS` attribute.
|
32
41
|
ValueError
|
33
42
|
If required input data type(s) is(are) not found.
|
34
43
|
|
@@ -39,6 +48,12 @@ class BaseMarker(ABC, PipelineStepMixin, UpdateMetaMixin):
|
|
39
48
|
on: Optional[Union[List[str], str]] = None,
|
40
49
|
name: Optional[str] = None,
|
41
50
|
) -> None:
|
51
|
+
# Check for missing mapping attribute
|
52
|
+
if not hasattr(self, "_MARKER_INOUT_MAPPINGS"):
|
53
|
+
raise_error(
|
54
|
+
msg=("Missing `_MARKER_INOUT_MAPPINGS` for the marker"),
|
55
|
+
klass=AttributeError,
|
56
|
+
)
|
42
57
|
# Use all data types if not provided
|
43
58
|
if on is None:
|
44
59
|
on = self.get_valid_inputs()
|
@@ -82,7 +97,6 @@ class BaseMarker(ABC, PipelineStepMixin, UpdateMetaMixin):
|
|
82
97
|
)
|
83
98
|
return [x for x in self._on if x in input]
|
84
99
|
|
85
|
-
@abstractmethod
|
86
100
|
def get_valid_inputs(self) -> List[str]:
|
87
101
|
"""Get valid data types for input.
|
88
102
|
|
@@ -92,30 +106,25 @@ class BaseMarker(ABC, PipelineStepMixin, UpdateMetaMixin):
|
|
92
106
|
The list of data types that can be used as input for this marker.
|
93
107
|
|
94
108
|
"""
|
95
|
-
|
96
|
-
msg="Concrete classes need to implement get_valid_inputs().",
|
97
|
-
klass=NotImplementedError,
|
98
|
-
)
|
109
|
+
return list(self._MARKER_INOUT_MAPPINGS.keys())
|
99
110
|
|
100
|
-
|
101
|
-
def get_output_type(self, input_type: str) -> str:
|
111
|
+
def get_output_type(self, input_type: str, output_feature: str) -> str:
|
102
112
|
"""Get output type.
|
103
113
|
|
104
114
|
Parameters
|
105
115
|
----------
|
106
116
|
input_type : str
|
107
117
|
The data type input to the marker.
|
118
|
+
output_feature : str
|
119
|
+
The feature output of the marker.
|
108
120
|
|
109
121
|
Returns
|
110
122
|
-------
|
111
123
|
str
|
112
|
-
The storage type output
|
124
|
+
The storage type output of the marker.
|
113
125
|
|
114
126
|
"""
|
115
|
-
|
116
|
-
msg="Concrete classes need to implement get_output_type().",
|
117
|
-
klass=NotImplementedError,
|
118
|
-
)
|
127
|
+
return self._MARKER_INOUT_MAPPINGS[input_type][output_feature]
|
119
128
|
|
120
129
|
@abstractmethod
|
121
130
|
def compute(self, input: Dict, extra_input: Optional[Dict] = None) -> Dict:
|
@@ -148,6 +157,7 @@ class BaseMarker(ABC, PipelineStepMixin, UpdateMetaMixin):
|
|
148
157
|
def store(
|
149
158
|
self,
|
150
159
|
type_: str,
|
160
|
+
feature: str,
|
151
161
|
out: Dict[str, Any],
|
152
162
|
storage: "BaseFeatureStorage",
|
153
163
|
) -> None:
|
@@ -157,13 +167,15 @@ class BaseMarker(ABC, PipelineStepMixin, UpdateMetaMixin):
|
|
157
167
|
----------
|
158
168
|
type_ : str
|
159
169
|
The data type to store.
|
170
|
+
feature : str
|
171
|
+
The feature to store.
|
160
172
|
out : dict
|
161
173
|
The computed result as a dictionary to store.
|
162
174
|
storage : storage-like
|
163
175
|
The storage class, for example, SQLiteFeatureStorage.
|
164
176
|
|
165
177
|
"""
|
166
|
-
output_type_ = self.get_output_type(type_)
|
178
|
+
output_type_ = self.get_output_type(type_, feature)
|
167
179
|
logger.debug(f"Storing {output_type_} in {storage}")
|
168
180
|
storage.store(kind=output_type_, **out)
|
169
181
|
|
@@ -192,22 +204,50 @@ class BaseMarker(ABC, PipelineStepMixin, UpdateMetaMixin):
|
|
192
204
|
for type_ in self._on:
|
193
205
|
if type_ in input.keys():
|
194
206
|
logger.info(f"Computing {type_}")
|
207
|
+
# Get data dict for data type
|
195
208
|
t_input = input[type_]
|
209
|
+
# Pass the other data types as extra input, removing
|
210
|
+
# the current type
|
196
211
|
extra_input = input.copy()
|
197
212
|
extra_input.pop(type_)
|
213
|
+
logger.debug(
|
214
|
+
f"Extra data type for feature extraction: "
|
215
|
+
f"{extra_input.keys()}"
|
216
|
+
)
|
217
|
+
# Copy metadata
|
198
218
|
t_meta = t_input["meta"].copy()
|
199
219
|
t_meta["type"] = type_
|
200
|
-
|
220
|
+
# Compute marker
|
201
221
|
t_out = self.compute(input=t_input, extra_input=extra_input)
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
222
|
+
# Initialize empty dictionary if no storage object is provided
|
223
|
+
if storage is None:
|
224
|
+
out[type_] = {}
|
225
|
+
# Store individual features
|
226
|
+
for feature_name, feature_data in t_out.items():
|
227
|
+
# Make deep copy of the feature data for manipulation
|
228
|
+
feature_data_copy = deepcopy(feature_data)
|
229
|
+
# Make deep copy of metadata and add to feature data
|
230
|
+
feature_data_copy["meta"] = deepcopy(t_meta)
|
231
|
+
# Update metadata for the feature,
|
232
|
+
# feature data is not manipulated, only meta
|
233
|
+
self.update_meta(feature_data_copy, "marker")
|
234
|
+
# Update marker feature's metadata name
|
235
|
+
feature_data_copy["meta"]["marker"][
|
236
|
+
"name"
|
237
|
+
] += f"_{feature_name}"
|
238
|
+
|
239
|
+
if storage is not None:
|
240
|
+
logger.info(f"Storing in {storage}")
|
241
|
+
self.store(
|
242
|
+
type_=type_,
|
243
|
+
feature=feature_name,
|
244
|
+
out=feature_data_copy,
|
245
|
+
storage=storage,
|
246
|
+
)
|
247
|
+
else:
|
248
|
+
logger.info(
|
249
|
+
"No storage specified, returning dictionary"
|
250
|
+
)
|
251
|
+
out[type_][feature_name] = feature_data_copy
|
212
252
|
|
213
253
|
return out
|