junifer 0.0.5__py3-none-any.whl → 0.0.5.dev24__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.
Files changed (194) hide show
  1. junifer/__init__.py +0 -17
  2. junifer/_version.py +2 -2
  3. junifer/api/__init__.py +1 -4
  4. junifer/api/cli.py +1 -91
  5. junifer/api/decorators.py +0 -9
  6. junifer/api/functions.py +10 -56
  7. junifer/api/parser.py +0 -3
  8. junifer/api/queue_context/__init__.py +1 -4
  9. junifer/api/res/afni/run_afni_docker.sh +1 -1
  10. junifer/api/res/ants/run_ants_docker.sh +1 -1
  11. junifer/api/res/fsl/run_fsl_docker.sh +1 -1
  12. junifer/api/tests/test_api_utils.py +2 -4
  13. junifer/api/tests/test_cli.py +0 -83
  14. junifer/api/tests/test_functions.py +2 -27
  15. junifer/configs/__init__.py +1 -1
  16. junifer/configs/juseless/__init__.py +1 -4
  17. junifer/configs/juseless/datagrabbers/__init__.py +1 -10
  18. junifer/configs/juseless/datagrabbers/aomic_id1000_vbm.py +0 -3
  19. junifer/configs/juseless/datagrabbers/camcan_vbm.py +0 -3
  20. junifer/configs/juseless/datagrabbers/ixi_vbm.py +0 -3
  21. junifer/configs/juseless/datagrabbers/tests/test_ucla.py +3 -1
  22. junifer/configs/juseless/datagrabbers/ucla.py +9 -12
  23. junifer/configs/juseless/datagrabbers/ukb_vbm.py +0 -3
  24. junifer/data/__init__.py +1 -21
  25. junifer/data/coordinates.py +19 -10
  26. junifer/data/masks.py +87 -58
  27. junifer/data/parcellations.py +3 -14
  28. junifer/data/template_spaces.py +1 -4
  29. junifer/data/tests/test_masks.py +37 -26
  30. junifer/data/utils.py +0 -3
  31. junifer/datagrabber/__init__.py +1 -18
  32. junifer/datagrabber/aomic/__init__.py +0 -3
  33. junifer/datagrabber/aomic/id1000.py +37 -70
  34. junifer/datagrabber/aomic/piop1.py +36 -69
  35. junifer/datagrabber/aomic/piop2.py +38 -71
  36. junifer/datagrabber/aomic/tests/test_id1000.py +99 -44
  37. junifer/datagrabber/aomic/tests/test_piop1.py +108 -65
  38. junifer/datagrabber/aomic/tests/test_piop2.py +102 -45
  39. junifer/datagrabber/base.py +6 -13
  40. junifer/datagrabber/datalad_base.py +1 -13
  41. junifer/datagrabber/dmcc13_benchmark.py +53 -36
  42. junifer/datagrabber/hcp1200/__init__.py +0 -3
  43. junifer/datagrabber/hcp1200/datalad_hcp1200.py +0 -3
  44. junifer/datagrabber/hcp1200/hcp1200.py +1 -4
  45. junifer/datagrabber/multiple.py +6 -45
  46. junifer/datagrabber/pattern.py +62 -170
  47. junifer/datagrabber/pattern_datalad.py +12 -25
  48. junifer/datagrabber/tests/test_datagrabber_utils.py +218 -0
  49. junifer/datagrabber/tests/test_datalad_base.py +4 -4
  50. junifer/datagrabber/tests/test_dmcc13_benchmark.py +19 -46
  51. junifer/datagrabber/tests/test_multiple.py +84 -161
  52. junifer/datagrabber/tests/test_pattern.py +0 -45
  53. junifer/datagrabber/tests/test_pattern_datalad.py +4 -4
  54. junifer/datagrabber/utils.py +230 -0
  55. junifer/datareader/__init__.py +1 -4
  56. junifer/datareader/default.py +43 -95
  57. junifer/external/__init__.py +1 -1
  58. junifer/external/nilearn/__init__.py +1 -5
  59. junifer/external/nilearn/junifer_nifti_spheres_masker.py +9 -23
  60. junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +1 -76
  61. junifer/markers/__init__.py +1 -23
  62. junifer/markers/base.py +28 -68
  63. junifer/markers/collection.py +2 -10
  64. junifer/markers/complexity/__init__.py +0 -10
  65. junifer/markers/complexity/complexity_base.py +43 -26
  66. junifer/markers/complexity/hurst_exponent.py +0 -3
  67. junifer/markers/complexity/multiscale_entropy_auc.py +0 -3
  68. junifer/markers/complexity/perm_entropy.py +0 -3
  69. junifer/markers/complexity/range_entropy.py +0 -3
  70. junifer/markers/complexity/range_entropy_auc.py +0 -3
  71. junifer/markers/complexity/sample_entropy.py +0 -3
  72. junifer/markers/complexity/tests/test_hurst_exponent.py +3 -11
  73. junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +3 -11
  74. junifer/markers/complexity/tests/test_perm_entropy.py +3 -11
  75. junifer/markers/complexity/tests/test_range_entropy.py +3 -11
  76. junifer/markers/complexity/tests/test_range_entropy_auc.py +3 -11
  77. junifer/markers/complexity/tests/test_sample_entropy.py +3 -11
  78. junifer/markers/complexity/tests/test_weighted_perm_entropy.py +3 -11
  79. junifer/markers/complexity/weighted_perm_entropy.py +0 -3
  80. junifer/markers/ets_rss.py +42 -27
  81. junifer/markers/falff/__init__.py +0 -3
  82. junifer/markers/falff/_afni_falff.py +2 -5
  83. junifer/markers/falff/_junifer_falff.py +0 -3
  84. junifer/markers/falff/falff_base.py +46 -20
  85. junifer/markers/falff/falff_parcels.py +27 -56
  86. junifer/markers/falff/falff_spheres.py +29 -60
  87. junifer/markers/falff/tests/test_falff_parcels.py +23 -39
  88. junifer/markers/falff/tests/test_falff_spheres.py +23 -39
  89. junifer/markers/functional_connectivity/__init__.py +0 -9
  90. junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +60 -63
  91. junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +32 -45
  92. junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +36 -49
  93. junifer/markers/functional_connectivity/functional_connectivity_base.py +70 -71
  94. junifer/markers/functional_connectivity/functional_connectivity_parcels.py +25 -34
  95. junifer/markers/functional_connectivity/functional_connectivity_spheres.py +30 -40
  96. junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +7 -11
  97. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +7 -27
  98. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +12 -28
  99. junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +11 -35
  100. junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +62 -36
  101. junifer/markers/parcel_aggregation.py +61 -47
  102. junifer/markers/reho/__init__.py +0 -3
  103. junifer/markers/reho/_afni_reho.py +2 -5
  104. junifer/markers/reho/_junifer_reho.py +1 -4
  105. junifer/markers/reho/reho_base.py +27 -8
  106. junifer/markers/reho/reho_parcels.py +17 -28
  107. junifer/markers/reho/reho_spheres.py +18 -27
  108. junifer/markers/reho/tests/test_reho_parcels.py +3 -8
  109. junifer/markers/reho/tests/test_reho_spheres.py +3 -8
  110. junifer/markers/sphere_aggregation.py +59 -43
  111. junifer/markers/temporal_snr/__init__.py +0 -3
  112. junifer/markers/temporal_snr/temporal_snr_base.py +32 -23
  113. junifer/markers/temporal_snr/temporal_snr_parcels.py +6 -9
  114. junifer/markers/temporal_snr/temporal_snr_spheres.py +6 -9
  115. junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +3 -6
  116. junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +3 -6
  117. junifer/markers/tests/test_collection.py +8 -9
  118. junifer/markers/tests/test_ets_rss.py +9 -15
  119. junifer/markers/tests/test_markers_base.py +18 -17
  120. junifer/markers/tests/test_parcel_aggregation.py +32 -93
  121. junifer/markers/tests/test_sphere_aggregation.py +19 -72
  122. junifer/onthefly/__init__.py +1 -4
  123. junifer/onthefly/read_transform.py +0 -3
  124. junifer/pipeline/__init__.py +1 -9
  125. junifer/pipeline/pipeline_step_mixin.py +4 -21
  126. junifer/pipeline/registry.py +0 -3
  127. junifer/pipeline/singleton.py +0 -3
  128. junifer/pipeline/tests/test_registry.py +1 -1
  129. junifer/pipeline/update_meta_mixin.py +0 -3
  130. junifer/pipeline/utils.py +1 -67
  131. junifer/pipeline/workdir_manager.py +0 -3
  132. junifer/preprocess/__init__.py +2 -9
  133. junifer/preprocess/ants/__init__.py +4 -0
  134. junifer/preprocess/ants/ants_apply_transforms_warper.py +185 -0
  135. junifer/preprocess/ants/tests/test_ants_apply_transforms_warper.py +56 -0
  136. junifer/preprocess/base.py +3 -6
  137. junifer/preprocess/bold_warper.py +265 -0
  138. junifer/preprocess/confounds/__init__.py +0 -3
  139. junifer/preprocess/confounds/fmriprep_confound_remover.py +60 -47
  140. junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +113 -72
  141. junifer/preprocess/fsl/__init__.py +4 -0
  142. junifer/preprocess/fsl/apply_warper.py +179 -0
  143. junifer/preprocess/fsl/tests/test_apply_warper.py +45 -0
  144. junifer/preprocess/smoothing/__init__.py +0 -3
  145. junifer/preprocess/smoothing/_afni_smoothing.py +1 -1
  146. junifer/preprocess/tests/test_bold_warper.py +159 -0
  147. junifer/preprocess/warping/__init__.py +0 -3
  148. junifer/preprocess/warping/_ants_warper.py +0 -3
  149. junifer/preprocess/warping/_fsl_warper.py +0 -3
  150. junifer/stats.py +1 -4
  151. junifer/storage/__init__.py +1 -9
  152. junifer/storage/base.py +1 -40
  153. junifer/storage/hdf5.py +9 -71
  154. junifer/storage/pandas_base.py +0 -3
  155. junifer/storage/sqlite.py +0 -3
  156. junifer/storage/tests/test_hdf5.py +10 -82
  157. junifer/storage/utils.py +0 -9
  158. junifer/testing/__init__.py +1 -4
  159. junifer/testing/datagrabbers.py +6 -13
  160. junifer/testing/tests/test_partlycloudytesting_datagrabber.py +7 -7
  161. junifer/testing/utils.py +0 -3
  162. junifer/utils/__init__.py +2 -13
  163. junifer/utils/fs.py +0 -3
  164. junifer/utils/helpers.py +1 -32
  165. junifer/utils/logging.py +4 -33
  166. junifer/utils/tests/test_logging.py +0 -8
  167. {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/METADATA +16 -17
  168. junifer-0.0.5.dev24.dist-info/RECORD +265 -0
  169. {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/WHEEL +1 -1
  170. junifer/api/res/freesurfer/mri_binarize +0 -3
  171. junifer/api/res/freesurfer/mri_mc +0 -3
  172. junifer/api/res/freesurfer/mri_pretess +0 -3
  173. junifer/api/res/freesurfer/mris_convert +0 -3
  174. junifer/api/res/freesurfer/run_freesurfer_docker.sh +0 -61
  175. junifer/data/masks/ukb/UKB_15K_GM_template.nii.gz +0 -0
  176. junifer/datagrabber/pattern_validation_mixin.py +0 -388
  177. junifer/datagrabber/tests/test_pattern_validation_mixin.py +0 -249
  178. junifer/external/BrainPrint/brainprint/__init__.py +0 -4
  179. junifer/external/BrainPrint/brainprint/_version.py +0 -3
  180. junifer/external/BrainPrint/brainprint/asymmetry.py +0 -91
  181. junifer/external/BrainPrint/brainprint/brainprint.py +0 -441
  182. junifer/external/BrainPrint/brainprint/surfaces.py +0 -258
  183. junifer/external/BrainPrint/brainprint/utils/__init__.py +0 -1
  184. junifer/external/BrainPrint/brainprint/utils/_config.py +0 -112
  185. junifer/external/BrainPrint/brainprint/utils/utils.py +0 -188
  186. junifer/external/nilearn/junifer_connectivity_measure.py +0 -483
  187. junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +0 -1089
  188. junifer/markers/brainprint.py +0 -459
  189. junifer/markers/tests/test_brainprint.py +0 -58
  190. junifer-0.0.5.dist-info/RECORD +0 -275
  191. {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/AUTHORS.rst +0 -0
  192. {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/LICENSE.md +0 -0
  193. {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/entry_points.txt +0 -0
  194. {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/top_level.txt +0 -0
@@ -1,459 +0,0 @@
1
- """Provide class for BrainPrint."""
2
-
3
- # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
- # License: AGPL
5
-
6
- import uuid
7
- from pathlib import Path
8
- from typing import (
9
- Any,
10
- ClassVar,
11
- Dict,
12
- List,
13
- Optional,
14
- Set,
15
- Union,
16
- )
17
-
18
- import numpy as np
19
- import numpy.typing as npt
20
-
21
- from ..api.decorators import register_marker
22
- from ..external.BrainPrint.brainprint.brainprint import (
23
- compute_asymmetry,
24
- compute_brainprint,
25
- )
26
- from ..external.BrainPrint.brainprint.surfaces import surf_to_vtk
27
- from ..pipeline import WorkDirManager
28
- from ..utils import logger, run_ext_cmd
29
- from .base import BaseMarker
30
-
31
-
32
- __all__ = ["BrainPrint"]
33
-
34
-
35
- @register_marker
36
- class BrainPrint(BaseMarker):
37
- """Class for BrainPrint.
38
-
39
- Parameters
40
- ----------
41
- num : positive int, optional
42
- Number of eigenvalues to compute (default 50).
43
- skip_cortex : bool, optional
44
- Whether to skip cortical surface or not (default False).
45
- keep_eigenvectors : bool, optional
46
- Whether to also return eigenvectors or not (default False).
47
- norm : str, optional
48
- Eigenvalues normalization method (default "none").
49
- reweight : bool, optional
50
- Whether to reweight eigenvalues or not (default False).
51
- asymmetry : bool, optional
52
- Whether to calculate asymmetry between lateral structures
53
- (default False).
54
- asymmetry_distance : {"euc"}, optional
55
- Distance measurement to use if ``asymmetry=True``:
56
-
57
- * ``"euc"`` : Euclidean
58
-
59
- (default "euc").
60
- use_cholmod : bool, optional
61
- If True, attempts to use the Cholesky decomposition for improved
62
- execution speed. Requires the ``scikit-sparse`` library. If it cannot
63
- be found, an error will be thrown. If False, will use slower LU
64
- decomposition (default False).
65
- name : str, optional
66
- The name of the marker. If None, will use the class name (default
67
- None).
68
-
69
- """
70
-
71
- _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [
72
- {
73
- "name": "freesurfer",
74
- "commands": [
75
- "mri_binarize",
76
- "mri_pretess",
77
- "mri_mc",
78
- "mris_convert",
79
- ],
80
- },
81
- ]
82
-
83
- _DEPENDENCIES: ClassVar[Set[str]] = {"lapy", "numpy"}
84
-
85
- _MARKER_INOUT_MAPPINGS: ClassVar[Dict[str, Dict[str, str]]] = {
86
- "FreeSurfer": {
87
- "eigenvalues": "scalar_table",
88
- "areas": "vector",
89
- "volumes": "vector",
90
- "distances": "vector",
91
- }
92
- }
93
-
94
- def __init__(
95
- self,
96
- num: int = 50,
97
- skip_cortex=False,
98
- keep_eigenvectors: bool = False,
99
- norm: str = "none",
100
- reweight: bool = False,
101
- asymmetry: bool = False,
102
- asymmetry_distance: str = "euc",
103
- use_cholmod: bool = False,
104
- name: Optional[str] = None,
105
- ) -> None:
106
- self.num = num
107
- self.skip_cortex = skip_cortex
108
- self.keep_eigenvectors = keep_eigenvectors
109
- self.norm = norm
110
- self.reweight = reweight
111
- self.asymmetry = asymmetry
112
- self.asymmetry_distance = asymmetry_distance
113
- self.use_cholmod = use_cholmod
114
- super().__init__(name=name, on="FreeSurfer")
115
-
116
- def _create_aseg_surface(
117
- self,
118
- aseg_path: Path,
119
- norm_path: Path,
120
- indices: List,
121
- ) -> Path:
122
- """Generate a surface from the aseg and label files.
123
-
124
- Parameters
125
- ----------
126
- aseg_path : pathlib.Path
127
- The FreeSurfer aseg path.
128
- norm_path : pathlib.Path
129
- The FreeSurfer norm path.
130
- indices : list
131
- List of label indices to include in the surface generation.
132
-
133
- Returns
134
- -------
135
- pathlib.Path
136
- Path to the generated surface in VTK format.
137
-
138
- """
139
- tempfile_prefix = f"aseg.{uuid.uuid4()}"
140
-
141
- # Set mri_binarize command
142
- mri_binarize_output_path = self._tempdir / f"{tempfile_prefix}.mgz"
143
- mri_binarize_cmd = [
144
- "mri_binarize",
145
- f"--i {aseg_path.resolve()}",
146
- f"--match {''.join(indices)}",
147
- f"--o {mri_binarize_output_path.resolve()}",
148
- ]
149
- # Call mri_binarize command
150
- run_ext_cmd(name="mri_binarize", cmd=mri_binarize_cmd)
151
-
152
- label_value = "1"
153
- # Fix label (pretess)
154
- # Set mri_pretess command
155
- mri_pretess_cmd = [
156
- "mri_pretess",
157
- f"{mri_binarize_output_path.resolve()}",
158
- f"{label_value}",
159
- f"{norm_path.resolve()}",
160
- f"{mri_binarize_output_path.resolve()}",
161
- ]
162
- # Call mri_pretess command
163
- run_ext_cmd(name="mri_pretess", cmd=mri_pretess_cmd)
164
-
165
- # Run marching cube to extract surface
166
- # Set mri_mc command
167
- mri_mc_output_path = self._tempdir / f"{tempfile_prefix}.surf"
168
- mri_mc_cmd = [
169
- "mri_mc",
170
- f"{mri_binarize_output_path.resolve()}",
171
- f"{label_value}",
172
- f"{mri_mc_output_path.resolve()}",
173
- ]
174
- # Run mri_mc command
175
- run_ext_cmd(name="mri_mc", cmd=mri_mc_cmd)
176
-
177
- # Convert to vtk
178
- # Set mris_convert command
179
- surface_path = (
180
- self._element_tempdir / f"aseg.final.{'_'.join(indices)}.vtk"
181
- )
182
- mris_convert_cmd = [
183
- "mris_convert",
184
- f"{mri_mc_output_path.resolve()}",
185
- f"{surface_path.resolve()}",
186
- ]
187
- # Run mris_convert command
188
- run_ext_cmd(name="mris_convert", cmd=mris_convert_cmd)
189
-
190
- return surface_path
191
-
192
- def _create_aseg_surfaces(
193
- self,
194
- aseg_path: Path,
195
- norm_path: Path,
196
- ) -> Dict[str, Path]:
197
- """Create surfaces from FreeSurfer aseg labels.
198
-
199
- Parameters
200
- ----------
201
- aseg_path : pathlib.Path
202
- The FreeSurfer aseg path.
203
- norm_path : pathlib.Path
204
- The FreeSurfer norm path.
205
-
206
- Returns
207
- -------
208
- dict
209
- Dictionary of label names mapped to corresponding surface paths.
210
-
211
- """
212
- # Define aseg labels
213
-
214
- # combined and individual aseg labels:
215
- # - Left Striatum: left Caudate + Putamen + Accumbens
216
- # - Right Striatum: right Caudate + Putamen + Accumbens
217
- # - CorpusCallosum: 5 subregions combined
218
- # - Cerebellum: brainstem + (left+right) cerebellum WM and GM
219
- # - Ventricles: (left+right) lat.vent + inf.lat.vent + choroidplexus +
220
- # 3rdVent + CSF
221
- # - Lateral-Ventricle: lat.vent + inf.lat.vent + choroidplexus
222
- # - 3rd-Ventricle: 3rd-Ventricle + CSF
223
-
224
- aseg_labels = {
225
- "CorpusCallosum": ["251", "252", "253", "254", "255"],
226
- "Cerebellum": ["7", "8", "16", "46", "47"],
227
- "Ventricles": ["4", "5", "14", "24", "31", "43", "44", "63"],
228
- "3rd-Ventricle": ["14", "24"],
229
- "4th-Ventricle": ["15"],
230
- "Brain-Stem": ["16"],
231
- "Left-Striatum": ["11", "12", "26"],
232
- "Left-Lateral-Ventricle": ["4", "5", "31"],
233
- "Left-Cerebellum-White-Matter": ["7"],
234
- "Left-Cerebellum-Cortex": ["8"],
235
- "Left-Thalamus-Proper": ["10"],
236
- "Left-Caudate": ["11"],
237
- "Left-Putamen": ["12"],
238
- "Left-Pallidum": ["13"],
239
- "Left-Hippocampus": ["17"],
240
- "Left-Amygdala": ["18"],
241
- "Left-Accumbens-area": ["26"],
242
- "Left-VentralDC": ["28"],
243
- "Right-Striatum": ["50", "51", "58"],
244
- "Right-Lateral-Ventricle": ["43", "44", "63"],
245
- "Right-Cerebellum-White-Matter": ["46"],
246
- "Right-Cerebellum-Cortex": ["47"],
247
- "Right-Thalamus-Proper": ["49"],
248
- "Right-Caudate": ["50"],
249
- "Right-Putamen": ["51"],
250
- "Right-Pallidum": ["52"],
251
- "Right-Hippocampus": ["53"],
252
- "Right-Amygdala": ["54"],
253
- "Right-Accumbens-area": ["58"],
254
- "Right-VentralDC": ["60"],
255
- }
256
- return {
257
- label: self._create_aseg_surface(
258
- aseg_path=aseg_path,
259
- norm_path=norm_path,
260
- indices=indices,
261
- )
262
- for label, indices in aseg_labels.items()
263
- }
264
-
265
- def _create_cortical_surfaces(
266
- self,
267
- lh_white_path: Path,
268
- rh_white_path: Path,
269
- lh_pial_path: Path,
270
- rh_pial_path: Path,
271
- ) -> Dict[str, Path]:
272
- """Create cortical surfaces from FreeSurfer labels.
273
-
274
- Parameters
275
- ----------
276
- lh_white_path : pathlib.Path
277
- The FreeSurfer lh.white path.
278
- rh_white_path : pathlib.Path
279
- The FreeSurfer rh.white path.
280
- lh_pial_path : pathlib.Path
281
- The FreeSurfer lh.pial path.
282
- rh_pial_path : pathlib.Path
283
- The FreeSurfer rh.pial path.
284
-
285
- Returns
286
- -------
287
- dict
288
- Cortical surface label names with their paths as dictionary.
289
-
290
- """
291
- return {
292
- "lh-white-2d": surf_to_vtk(
293
- lh_white_path.resolve(),
294
- (self._element_tempdir / "lh.white.vtk").resolve(),
295
- ),
296
- "rh-white-2d": surf_to_vtk(
297
- rh_white_path.resolve(),
298
- (self._element_tempdir / "rh.white.vtk").resolve(),
299
- ),
300
- "lh-pial-2d": surf_to_vtk(
301
- lh_pial_path.resolve(),
302
- (self._element_tempdir / "lh.pial.vtk").resolve(),
303
- ),
304
- "rh-pial-2d": surf_to_vtk(
305
- rh_pial_path.resolve(),
306
- (self._element_tempdir / "rh.pial.vtk").resolve(),
307
- ),
308
- }
309
-
310
- def _fix_nan(
311
- self,
312
- input_data: List[Union[float, str, npt.ArrayLike]],
313
- ) -> np.ndarray:
314
- """Convert BrainPrint output with string NaN to ``numpy.nan``.
315
-
316
- Parameters
317
- ----------
318
- input_data : list of str, float or numpy.ndarray-like
319
- The data to convert.
320
-
321
- Returns
322
- -------
323
- np.ndarray
324
- The converted data as ``numpy.ndarray``.
325
-
326
- """
327
- arr = np.asarray(input_data)
328
- arr[arr == "NaN"] = np.nan
329
- return arr.astype(np.float64)
330
-
331
- def compute(
332
- self,
333
- input: Dict[str, Any],
334
- extra_input: Optional[Dict] = None,
335
- ) -> Dict:
336
- """Compute.
337
-
338
- Parameters
339
- ----------
340
- input : dict
341
- The FreeSurfer data as dictionary.
342
- extra_input : dict, optional
343
- The other fields in the pipeline data object (default None).
344
-
345
- Returns
346
- -------
347
- dict
348
- The computed result as dictionary. This will be either returned
349
- to the user or stored in the storage by calling the store method
350
- with this as a parameter. The dictionary has the following keys:
351
-
352
- * ``eigenvalues`` : dictionary with the following keys:
353
-
354
- - ``data`` : eigenvalues as ``np.ndarray``
355
- - ``col_names`` : surface labels as list of str
356
- - ``row_names`` : eigenvalue count labels as list of str
357
- - ``row_header_col_name`` : "eigenvalue"
358
- ()
359
- * ``areas`` : dictionary with the following keys:
360
-
361
- - ``data`` : areas as ``np.ndarray``
362
- - ``col_names`` : surface labels as list of str
363
-
364
- * ``volumes`` : dictionary with the following keys:
365
-
366
- - ``data`` : volumes as ``np.ndarray``
367
- - ``col_names`` : surface labels as list of str
368
-
369
- * ``distances`` : dictionary with the following keys
370
- if ``asymmetry = True``:
371
-
372
- - ``data`` : distances as ``np.ndarray``
373
- - ``col_names`` : surface labels as list of str
374
-
375
- References
376
- ----------
377
- .. [1] Wachinger, C., Golland, P., Kremen, W. et al. (2015)
378
- BrainPrint: A discriminative characterization of brain
379
- morphology.
380
- NeuroImage, Volume 109, Pages 232-248.
381
- https://doi.org/10.1016/j.neuroimage.2015.01.032.
382
- .. [2] Reuter, M., Wolter, F.E., Peinecke, N. (2006)
383
- Laplace-Beltrami spectra as 'Shape-DNA' of surfaces and solids.
384
- Computer-Aided Design, Volume 38, Issue 4, Pages 342-366.
385
- https://doi.org/10.1016/j.cad.2005.10.011.
386
-
387
- """
388
- logger.debug("Computing BrainPrint")
389
-
390
- # Create component-scoped tempdir
391
- self._tempdir = WorkDirManager().get_tempdir(prefix="brainprint")
392
- # Create element-scoped tempdir so that the files are
393
- # available later as nibabel stores file path reference for
394
- # loading on computation
395
- self._element_tempdir = WorkDirManager().get_element_tempdir(
396
- prefix="brainprint"
397
- )
398
- # Generate surfaces
399
- surfaces = self._create_aseg_surfaces(
400
- aseg_path=input["aseg"]["path"],
401
- norm_path=input["norm"]["path"],
402
- )
403
- if not self.skip_cortex:
404
- cortical_surfaces = self._create_cortical_surfaces(
405
- lh_white_path=input["lh_white"]["path"],
406
- rh_white_path=input["rh_white"]["path"],
407
- lh_pial_path=input["lh_pial"]["path"],
408
- rh_pial_path=input["rh_pial"]["path"],
409
- )
410
- surfaces.update(cortical_surfaces)
411
- # Compute brainprint
412
- eigenvalues, _ = compute_brainprint(
413
- surfaces=surfaces,
414
- keep_eigenvectors=self.keep_eigenvectors,
415
- num=self.num,
416
- norm=self.norm,
417
- reweight=self.reweight,
418
- use_cholmod=self.use_cholmod,
419
- )
420
- # Calculate distances (if required)
421
- distances = None
422
- if self.asymmetry:
423
- distances = compute_asymmetry(
424
- eigenvalues=eigenvalues,
425
- distance=self.asymmetry_distance,
426
- skip_cortex=self.skip_cortex,
427
- )
428
-
429
- # Delete tempdir
430
- WorkDirManager().delete_tempdir(self._tempdir)
431
-
432
- output = {
433
- "eigenvalues": {
434
- "data": self._fix_nan(
435
- [val[2:] for val in eigenvalues.values()]
436
- ).T,
437
- "col_names": list(eigenvalues.keys()),
438
- "row_names": [f"ev{i}" for i in range(self.num)],
439
- "row_header_col_name": "eigenvalue",
440
- },
441
- "areas": {
442
- "data": self._fix_nan(
443
- [val[0] for val in eigenvalues.values()]
444
- ),
445
- "col_names": list(eigenvalues.keys()),
446
- },
447
- "volumes": {
448
- "data": self._fix_nan(
449
- [val[1] for val in eigenvalues.values()]
450
- ),
451
- "col_names": list(eigenvalues.keys()),
452
- },
453
- }
454
- if self.asymmetry:
455
- output["distances"] = {
456
- "data": self._fix_nan(list(distances.values())),
457
- "col_names": list(distances.keys()),
458
- }
459
- return output
@@ -1,58 +0,0 @@
1
- """Provide tests for BrainPrint."""
2
-
3
- # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
- # License: AGPL
5
-
6
- import socket
7
-
8
- import pytest
9
-
10
- from junifer.datagrabber import DataladAOMICID1000
11
- from junifer.datareader import DefaultDataReader
12
- from junifer.markers import BrainPrint
13
- from junifer.pipeline.utils import _check_freesurfer
14
-
15
-
16
- @pytest.mark.parametrize(
17
- "feature, storage_type",
18
- [
19
- ("eigenvalues", "scalar_table"),
20
- ("areas", "vector"),
21
- ("volumes", "vector"),
22
- ("distances", "vector"),
23
- ],
24
- )
25
- def test_get_output_type(feature: str, storage_type: str) -> None:
26
- """Test BrainPrint get_output_type().
27
-
28
- Parameters
29
- ----------
30
- feature : str
31
- The parametrized feature name.
32
- storage_type : str
33
- The parametrized storage type.
34
-
35
- """
36
- assert storage_type == BrainPrint().get_output_type(
37
- input_type="FreeSurfer", output_feature=feature
38
- )
39
-
40
-
41
- @pytest.mark.skipif(
42
- _check_freesurfer() is False, reason="requires FreeSurfer to be in PATH"
43
- )
44
- @pytest.mark.skipif(
45
- socket.gethostname() != "juseless",
46
- reason="only for juseless",
47
- )
48
- def test_compute() -> None:
49
- """Test BrainPrint compute()."""
50
- with DataladAOMICID1000(types="FreeSurfer") as dg:
51
- # Fetch element
52
- element = dg["sub-0001"]
53
- # Fetch element data
54
- element_data = DefaultDataReader().fit_transform(element)
55
- # Compute marker
56
- feature_map = BrainPrint().fit_transform(element_data)
57
- # Assert the output keys
58
- assert {"eigenvalues", "areas", "volumes"} == set(feature_map.keys())