junifer 0.0.4.dev831__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.dev831.dist-info → junifer-0.0.5.dist-info}/METADATA +17 -16
- junifer-0.0.5.dist-info/RECORD +275 -0
- {junifer-0.0.4.dev831.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.dev831.dist-info/RECORD +0 -257
- {junifer-0.0.4.dev831.dist-info → junifer-0.0.5.dist-info}/AUTHORS.rst +0 -0
- {junifer-0.0.4.dev831.dist-info → junifer-0.0.5.dist-info}/LICENSE.md +0 -0
- {junifer-0.0.4.dev831.dist-info → junifer-0.0.5.dist-info}/entry_points.txt +0 -0
- {junifer-0.0.4.dev831.dist-info → junifer-0.0.5.dist-info}/top_level.txt +0 -0
junifer/datareader/default.py
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
# License: AGPL
|
6
6
|
|
7
7
|
from pathlib import Path
|
8
|
-
from typing import Dict, List, Optional
|
8
|
+
from typing import Dict, List, Optional, Union
|
9
9
|
|
10
10
|
import nibabel as nib
|
11
11
|
import pandas as pd
|
@@ -15,6 +15,9 @@ from ..pipeline import PipelineStepMixin, UpdateMetaMixin
|
|
15
15
|
from ..utils.logging import logger, warn_with_log
|
16
16
|
|
17
17
|
|
18
|
+
__all__ = ["DefaultDataReader"]
|
19
|
+
|
20
|
+
|
18
21
|
# Map each file extension to a type
|
19
22
|
_extensions = {
|
20
23
|
".nii": "NIFTI",
|
@@ -102,57 +105,106 @@ class DefaultDataReader(PipelineStepMixin, UpdateMetaMixin):
|
|
102
105
|
if params is None:
|
103
106
|
params = {}
|
104
107
|
# For each type of data, try to read it
|
105
|
-
for
|
106
|
-
# Skip Warp data type
|
107
|
-
if
|
108
|
+
for type_key, type_val in input.items():
|
109
|
+
# Skip Warp and FreeSurfer data type
|
110
|
+
if type_key in ["Warp", "FreeSurfer"]:
|
108
111
|
continue
|
109
112
|
|
110
113
|
# Check for malformed datagrabber specification
|
111
|
-
if "path" not in
|
114
|
+
if "path" not in type_val:
|
112
115
|
warn_with_log(
|
113
|
-
f"Input type {
|
116
|
+
f"Input type {type_key} does not provide a path. Skipping."
|
114
117
|
)
|
115
118
|
continue
|
116
119
|
|
117
|
-
#
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
# Lowercase path
|
131
|
-
fname = t_path.name.lower()
|
132
|
-
# Loop through extensions to find the correct one
|
133
|
-
for ext, ftype in _extensions.items():
|
134
|
-
if fname.endswith(ext):
|
135
|
-
logger.info(f"{type_} is type {ftype}")
|
136
|
-
# Retrieve reader function
|
137
|
-
reader_func = _readers[ftype]["func"]
|
138
|
-
# Retrieve reader function params
|
139
|
-
reader_params = _readers[ftype]["params"]
|
140
|
-
# Update reader function params
|
141
|
-
if reader_params is not None:
|
142
|
-
t_params.update(reader_params)
|
143
|
-
logger.debug(f"Calling {reader_func} with {t_params}")
|
120
|
+
# Iterate to check for nested "types" like mask;
|
121
|
+
# need to copy to avoid runtime error for changing dict size
|
122
|
+
for k, v in type_val.copy().items():
|
123
|
+
# Read data for base data type
|
124
|
+
if k == "path":
|
125
|
+
# Convert str to Path
|
126
|
+
if not isinstance(v, Path):
|
127
|
+
v = Path(v)
|
128
|
+
# Update path
|
129
|
+
out[type_key]["path"] = v
|
130
|
+
logger.info(f"Reading {type_key} from {v.absolute()!s}")
|
131
|
+
# Retrieve loading params for the data type
|
132
|
+
t_params = params.get(type_key, {})
|
144
133
|
# Read data
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
134
|
+
out[type_key]["data"] = _read_data(
|
135
|
+
data_type=type_key, path=v, read_params=t_params
|
136
|
+
)
|
137
|
+
# Read data for nested data type
|
138
|
+
if isinstance(v, dict) and "path" in v:
|
139
|
+
# Set path
|
140
|
+
nested_path = v["path"]
|
141
|
+
# Convert str to Path
|
142
|
+
if not isinstance(nested_path, Path):
|
143
|
+
nested_path = Path(nested_path)
|
144
|
+
# Update path
|
145
|
+
out[type_key][k]["path"] = nested_path
|
146
|
+
# Set nested type key for easier access
|
147
|
+
nested_type = f"{type_key}.{k}"
|
148
|
+
logger.info(
|
149
|
+
f"Reading {nested_type} from "
|
150
|
+
f"{nested_path.absolute()!s}"
|
151
|
+
)
|
152
|
+
# Retrieve loading params for the nested data type
|
153
|
+
nested_params = params.get(nested_type, {})
|
154
|
+
# Read data
|
155
|
+
out[type_key][k]["data"] = _read_data(
|
156
|
+
data_type=nested_type,
|
157
|
+
path=nested_path,
|
158
|
+
read_params=nested_params,
|
159
|
+
)
|
152
160
|
|
153
|
-
# Set file data for output
|
154
|
-
out[type_]["data"] = fread
|
155
161
|
# Update metadata for step
|
156
|
-
self.update_meta(out[
|
162
|
+
self.update_meta(out[type_key], "datareader")
|
157
163
|
|
158
164
|
return out
|
165
|
+
|
166
|
+
|
167
|
+
def _read_data(
|
168
|
+
data_type: str, path: Path, read_params: Dict
|
169
|
+
) -> Union[nib.Nifti1Image, pd.DataFrame, None]:
|
170
|
+
"""Read data for data type.
|
171
|
+
|
172
|
+
Parameters
|
173
|
+
----------
|
174
|
+
data_type : str
|
175
|
+
The data type being read.
|
176
|
+
path : pathlib.Path
|
177
|
+
The path to read data from.
|
178
|
+
read_params : dict
|
179
|
+
Parameters for reader function.
|
180
|
+
|
181
|
+
Returns
|
182
|
+
-------
|
183
|
+
nibabel.Nifti1Image or pandas.DataFrame or pandas.TextFileReader or None
|
184
|
+
The data loaded in memory if file type is known else None.
|
185
|
+
|
186
|
+
"""
|
187
|
+
# Initialize variable for file data
|
188
|
+
fread = None
|
189
|
+
# Lowercase path
|
190
|
+
fname = path.name.lower()
|
191
|
+
# Loop through extensions to find the correct one
|
192
|
+
for ext, ftype in _extensions.items():
|
193
|
+
if fname.endswith(ext):
|
194
|
+
logger.info(f"{data_type} is of type {ftype}")
|
195
|
+
# Retrieve reader function
|
196
|
+
reader_func = _readers[ftype]["func"]
|
197
|
+
# Retrieve reader function params
|
198
|
+
reader_params = _readers[ftype]["params"]
|
199
|
+
# Update reader function params
|
200
|
+
if reader_params is not None:
|
201
|
+
read_params.update(reader_params)
|
202
|
+
logger.debug(f"Calling {reader_func!s} with {read_params}")
|
203
|
+
# Read data
|
204
|
+
fread = reader_func(path, **read_params)
|
205
|
+
break
|
206
|
+
# If no file data is found due to unknown extension
|
207
|
+
if fread is None:
|
208
|
+
logger.info(f"Unknown file type {path.absolute()!s}, skipping reading")
|
209
|
+
|
210
|
+
return fread
|
@@ -0,0 +1,91 @@
|
|
1
|
+
"""
|
2
|
+
Contains asymmetry estimation functionality.
|
3
|
+
"""
|
4
|
+
from typing import Dict
|
5
|
+
|
6
|
+
import numpy as np
|
7
|
+
from lapy import shapedna
|
8
|
+
|
9
|
+
|
10
|
+
def compute_asymmetry(
|
11
|
+
eigenvalues, distance: str = "euc", skip_cortex: bool = False
|
12
|
+
) -> Dict[str, float]:
|
13
|
+
"""
|
14
|
+
Compute lateral shape distances from BrainPrint analysis results.
|
15
|
+
|
16
|
+
Parameters
|
17
|
+
----------
|
18
|
+
eigenvalues : _type_
|
19
|
+
BrainPrint analysis results.
|
20
|
+
distance : str, optional
|
21
|
+
ShapeDNA distance, by default "euc".
|
22
|
+
skip_cortex : bool, optional
|
23
|
+
Whether to skip white matter and pial surfaces, by default False.
|
24
|
+
|
25
|
+
Returns
|
26
|
+
-------
|
27
|
+
Dict[str, float]
|
28
|
+
{left_label}_{right_label}, distance.
|
29
|
+
"""
|
30
|
+
# Define structures
|
31
|
+
|
32
|
+
# combined and individual aseg labels:
|
33
|
+
# - Left Striatum: left Caudate + Putamen + Accumbens
|
34
|
+
# - Right Striatum: right Caudate + Putamen + Accumbens
|
35
|
+
# - CorpusCallosum: 5 subregions combined
|
36
|
+
# - Cerebellum: brainstem + (left+right) cerebellum WM and GM
|
37
|
+
# - Ventricles: (left+right) lat.vent + inf.lat.vent + choroidplexus + 3rdVent + CSF
|
38
|
+
# - Lateral-Ventricle: lat.vent + inf.lat.vent + choroidplexus
|
39
|
+
# - 3rd-Ventricle: 3rd-Ventricle + CSF
|
40
|
+
|
41
|
+
structures_left_right = [
|
42
|
+
("Left-Striatum", "Right-Striatum"),
|
43
|
+
("Left-Lateral-Ventricle", "Right-Lateral-Ventricle"),
|
44
|
+
(
|
45
|
+
"Left-Cerebellum-White-Matter",
|
46
|
+
"Right-Cerebellum-White-Matter",
|
47
|
+
),
|
48
|
+
("Left-Cerebellum-Cortex", "Right-Cerebellum-Cortex"),
|
49
|
+
("Left-Thalamus-Proper", "Right-Thalamus-Proper"),
|
50
|
+
("Left-Caudate", "Right-Caudate"),
|
51
|
+
("Left-Putamen", "Right-Putamen"),
|
52
|
+
("Left-Pallidum", "Right-Pallidum"),
|
53
|
+
("Left-Hippocampus", "Right-Hippocampus"),
|
54
|
+
("Left-Amygdala", "Right-Amygdala"),
|
55
|
+
("Left-Accumbens-area", "Right-Accumbens-area"),
|
56
|
+
("Left-VentralDC", "Right-VentralDC"),
|
57
|
+
]
|
58
|
+
|
59
|
+
cortex_2d_left_right = [
|
60
|
+
("lh-white-2d", "rh-white-2d"),
|
61
|
+
("lh-pial-2d", "rh-pial-2d"),
|
62
|
+
]
|
63
|
+
|
64
|
+
structures = structures_left_right
|
65
|
+
if not skip_cortex:
|
66
|
+
structures += cortex_2d_left_right
|
67
|
+
|
68
|
+
distances = dict()
|
69
|
+
for left_label, right_label in structures:
|
70
|
+
left_eigenvalues, right_eigenvalues = (
|
71
|
+
eigenvalues[left_label][2:],
|
72
|
+
eigenvalues[right_label][2:],
|
73
|
+
)
|
74
|
+
has_nan = np.isnan(left_eigenvalues).any() or np.isnan(right_eigenvalues).any()
|
75
|
+
key = f"{left_label}_{right_label}"
|
76
|
+
if has_nan:
|
77
|
+
message = (
|
78
|
+
"NaNs found for {left_label} or {right_label}, "
|
79
|
+
"skipping asymmetry computation...".format(
|
80
|
+
left_label=left_label, right_label=right_label
|
81
|
+
)
|
82
|
+
)
|
83
|
+
print(message)
|
84
|
+
distances[key] = np.nan
|
85
|
+
else:
|
86
|
+
distances[key] = shapedna.compute_distance(
|
87
|
+
left_eigenvalues,
|
88
|
+
right_eigenvalues,
|
89
|
+
dist=distance,
|
90
|
+
)
|
91
|
+
return distances
|