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.
Files changed (293) hide show
  1. junifer/_version.py +9 -19
  2. junifer/api/__init__.pyi +17 -2
  3. junifer/api/functions.py +222 -39
  4. junifer/api/queue_context/__init__.pyi +11 -3
  5. junifer/api/queue_context/gnu_parallel_local_adapter.py +81 -120
  6. junifer/api/queue_context/htcondor_adapter.py +118 -181
  7. junifer/api/queue_context/queue_context_adapter.py +51 -7
  8. junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +10 -35
  9. junifer/api/queue_context/tests/test_htcondor_adapter.py +13 -50
  10. junifer/api/res/fsl/run_fsl_docker.sh +4 -0
  11. junifer/api/tests/test_functions.py +863 -36
  12. junifer/cli/__init__.py +1 -7
  13. junifer/cli/cli.py +41 -22
  14. junifer/cli/parser.py +23 -147
  15. junifer/cli/tests/data/gmd_mean.yaml +6 -6
  16. junifer/cli/tests/data/gmd_mean_htcondor.yaml +6 -5
  17. junifer/cli/tests/data/partly_cloudy_agg_mean_tian.yml +1 -0
  18. junifer/cli/tests/test_cli.py +120 -4
  19. junifer/cli/tests/test_cli_utils.py +23 -6
  20. junifer/cli/utils.py +14 -9
  21. junifer/configs/__init__.py +5 -0
  22. junifer/configs/__init__.pyi +0 -0
  23. junifer/configs/juseless/datagrabbers/__init__.pyi +4 -2
  24. junifer/configs/juseless/datagrabbers/aomic_id1000_vbm.py +18 -24
  25. junifer/configs/juseless/datagrabbers/camcan_vbm.py +20 -27
  26. junifer/configs/juseless/datagrabbers/ixi_vbm.py +44 -52
  27. junifer/configs/juseless/datagrabbers/tests/test_ixi_vbm.py +0 -7
  28. junifer/configs/juseless/datagrabbers/tests/test_ucla.py +2 -19
  29. junifer/configs/juseless/datagrabbers/ucla.py +111 -104
  30. junifer/configs/juseless/datagrabbers/ukb_vbm.py +19 -25
  31. junifer/configs/py.typed +0 -0
  32. junifer/conftest.py +63 -24
  33. junifer/data/_dispatch.py +9 -19
  34. junifer/data/coordinates/_ants_coordinates_warper.py +4 -1
  35. junifer/data/coordinates/_coordinates.py +51 -6
  36. junifer/data/coordinates/_fsl_coordinates_warper.py +4 -1
  37. junifer/data/coordinates/tests/test_coordinates.py +15 -3
  38. junifer/data/coordinates/tests/test_coordinates_names.py +37 -0
  39. junifer/data/maps/_ants_maps_warper.py +18 -12
  40. junifer/data/maps/_fsl_maps_warper.py +7 -3
  41. junifer/data/maps/_maps.py +12 -8
  42. junifer/data/maps/tests/test_maps.py +13 -21
  43. junifer/data/masks/_ants_mask_warper.py +18 -12
  44. junifer/data/masks/_fsl_mask_warper.py +7 -3
  45. junifer/data/masks/_masks.py +15 -12
  46. junifer/data/masks/tests/test_masks.py +20 -17
  47. junifer/data/parcellations/_ants_parcellation_warper.py +18 -12
  48. junifer/data/parcellations/_fsl_parcellation_warper.py +7 -5
  49. junifer/data/parcellations/_parcellations.py +125 -91
  50. junifer/data/parcellations/tests/test_parcellations.py +122 -1
  51. junifer/data/template_spaces.py +117 -50
  52. junifer/data/tests/test_template_spaces.py +10 -7
  53. junifer/data/utils.py +10 -8
  54. junifer/datagrabber/__init__.pyi +38 -5
  55. junifer/datagrabber/aomic/__init__.pyi +8 -1
  56. junifer/datagrabber/aomic/_types.py +22 -0
  57. junifer/datagrabber/aomic/id1000.py +193 -183
  58. junifer/datagrabber/aomic/piop1.py +215 -259
  59. junifer/datagrabber/aomic/piop2.py +211 -244
  60. junifer/datagrabber/aomic/tests/test_id1000.py +70 -53
  61. junifer/datagrabber/aomic/tests/test_piop1.py +98 -102
  62. junifer/datagrabber/aomic/tests/test_piop2.py +88 -85
  63. junifer/datagrabber/base.py +253 -79
  64. junifer/datagrabber/datalad_base.py +127 -76
  65. junifer/datagrabber/dmcc13_benchmark.py +204 -289
  66. junifer/datagrabber/hcp1200/__init__.pyi +7 -2
  67. junifer/datagrabber/hcp1200/datalad_hcp1200.py +61 -40
  68. junifer/datagrabber/hcp1200/hcp1200.py +151 -164
  69. junifer/datagrabber/hcp1200/tests/test_hcp1200.py +116 -128
  70. junifer/datagrabber/multiple.py +183 -63
  71. junifer/datagrabber/pattern.py +358 -227
  72. junifer/datagrabber/pattern_datalad.py +84 -124
  73. junifer/datagrabber/pattern_validation_mixin.py +22 -50
  74. junifer/datagrabber/tests/test_base.py +17 -4
  75. junifer/datagrabber/tests/test_datalad_base.py +20 -27
  76. junifer/datagrabber/tests/test_dmcc13_benchmark.py +110 -122
  77. junifer/datagrabber/tests/test_multiple.py +293 -31
  78. junifer/datagrabber/tests/test_pattern.py +577 -18
  79. junifer/datagrabber/tests/test_pattern_datalad.py +177 -107
  80. junifer/datagrabber/tests/test_pattern_validation_mixin.py +9 -51
  81. junifer/datareader/default.py +8 -5
  82. junifer/datareader/tests/test_default_reader.py +1 -1
  83. junifer/external/BrainPrint/.codecov.yml +2 -0
  84. junifer/external/BrainPrint/.codespellignore +2 -0
  85. junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/bug-report.md +45 -0
  86. junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/documentation.md +12 -0
  87. junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/feature-request.md +24 -0
  88. junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/questions-help-support.md +28 -0
  89. junifer/external/BrainPrint/.github/dependabot.yml +6 -0
  90. junifer/external/BrainPrint/.github/workflows/build.yml +53 -0
  91. junifer/external/BrainPrint/.github/workflows/code-style.yml +44 -0
  92. junifer/external/BrainPrint/.github/workflows/doc.yml +65 -0
  93. junifer/external/BrainPrint/.github/workflows/publish.yml +31 -0
  94. junifer/external/BrainPrint/.github/workflows/pytest.yml +54 -0
  95. junifer/external/BrainPrint/.gitignore +123 -0
  96. junifer/external/BrainPrint/LICENSE +21 -0
  97. junifer/external/BrainPrint/README.md +108 -0
  98. junifer/external/BrainPrint/brainprint/cli/__init__.py +11 -0
  99. junifer/external/BrainPrint/brainprint/cli/help_text.py +169 -0
  100. junifer/external/BrainPrint/brainprint/cli/parser.py +150 -0
  101. junifer/external/BrainPrint/brainprint/cli/utils.py +14 -0
  102. junifer/external/BrainPrint/brainprint/commands/__init__.py +0 -0
  103. junifer/external/BrainPrint/brainprint/commands/sys_info.py +18 -0
  104. junifer/external/BrainPrint/brainprint/utils/tests/__init__.py +0 -0
  105. junifer/external/BrainPrint/brainprint/utils/tests/test_config.py +33 -0
  106. junifer/external/BrainPrint/doc/Makefile +20 -0
  107. junifer/external/BrainPrint/doc/_static/.gitkeep +0 -0
  108. junifer/external/BrainPrint/doc/_templates/autosummary/class.rst +10 -0
  109. junifer/external/BrainPrint/doc/_templates/autosummary/function.rst +8 -0
  110. junifer/external/BrainPrint/doc/_templates/autosummary/module.rst +6 -0
  111. junifer/external/BrainPrint/doc/api/index.rst +11 -0
  112. junifer/external/BrainPrint/doc/conf.py +272 -0
  113. junifer/external/BrainPrint/doc/index.rst +140 -0
  114. junifer/external/BrainPrint/doc/links.inc +36 -0
  115. junifer/external/BrainPrint/doc/make.bat +35 -0
  116. junifer/external/BrainPrint/doc/references.bib +23 -0
  117. junifer/external/BrainPrint/pyproject.toml +170 -0
  118. junifer/external/BrainPrint/setup.py +3 -0
  119. junifer/external/__init__.py +5 -0
  120. junifer/external/__init__.pyi +0 -0
  121. junifer/external/nilearn/junifer_connectivity_measure.py +95 -39
  122. junifer/external/nilearn/junifer_nifti_spheres_masker.py +226 -67
  123. junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +39 -27
  124. junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +231 -21
  125. junifer/external/py.typed +0 -0
  126. junifer/markers/__init__.pyi +6 -3
  127. junifer/markers/base.py +126 -76
  128. junifer/markers/brainprint.py +30 -39
  129. junifer/markers/complexity/__init__.py +20 -3
  130. junifer/markers/complexity/complexity_base.py +40 -41
  131. junifer/markers/complexity/hurst_exponent.py +22 -35
  132. junifer/markers/complexity/multiscale_entropy_auc.py +53 -41
  133. junifer/markers/complexity/perm_entropy.py +22 -36
  134. junifer/markers/complexity/range_entropy.py +22 -35
  135. junifer/markers/complexity/range_entropy_auc.py +27 -36
  136. junifer/markers/complexity/sample_entropy.py +22 -36
  137. junifer/markers/complexity/tests/test_complexity_registry.py +48 -0
  138. junifer/markers/complexity/tests/test_hurst_exponent.py +47 -36
  139. junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +50 -36
  140. junifer/markers/complexity/tests/test_perm_entropy.py +48 -36
  141. junifer/markers/complexity/tests/test_range_entropy.py +47 -36
  142. junifer/markers/complexity/tests/test_range_entropy_auc.py +47 -36
  143. junifer/markers/complexity/tests/test_sample_entropy.py +48 -36
  144. junifer/markers/complexity/tests/test_weighted_perm_entropy.py +50 -36
  145. junifer/markers/complexity/weighted_perm_entropy.py +22 -36
  146. junifer/markers/ets_rss.py +35 -31
  147. junifer/markers/falff/__init__.pyi +7 -1
  148. junifer/markers/falff/_afni_falff.py +22 -9
  149. junifer/markers/falff/_junifer_falff.py +47 -31
  150. junifer/markers/falff/falff_base.py +80 -60
  151. junifer/markers/falff/falff_maps.py +17 -41
  152. junifer/markers/falff/falff_parcels.py +26 -51
  153. junifer/markers/falff/falff_spheres.py +34 -61
  154. junifer/markers/falff/tests/test_falff_maps.py +20 -23
  155. junifer/markers/falff/tests/test_falff_mask.py +99 -0
  156. junifer/markers/falff/tests/test_falff_parcels.py +14 -10
  157. junifer/markers/falff/tests/test_falff_spheres.py +14 -10
  158. junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +32 -34
  159. junifer/markers/functional_connectivity/edge_functional_connectivity_maps.py +12 -25
  160. junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +19 -34
  161. junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +24 -44
  162. junifer/markers/functional_connectivity/functional_connectivity_base.py +50 -40
  163. junifer/markers/functional_connectivity/functional_connectivity_maps.py +12 -25
  164. junifer/markers/functional_connectivity/functional_connectivity_parcels.py +19 -34
  165. junifer/markers/functional_connectivity/functional_connectivity_spheres.py +24 -45
  166. junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +21 -22
  167. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_maps.py +8 -7
  168. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +8 -4
  169. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +8 -4
  170. junifer/markers/functional_connectivity/tests/test_functional_connectivity_maps.py +8 -7
  171. junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +9 -5
  172. junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +8 -12
  173. junifer/markers/maps_aggregation.py +77 -55
  174. junifer/markers/parcel_aggregation.py +91 -70
  175. junifer/markers/reho/__init__.pyi +7 -1
  176. junifer/markers/reho/_afni_reho.py +23 -14
  177. junifer/markers/reho/_junifer_reho.py +112 -123
  178. junifer/markers/reho/reho_base.py +115 -37
  179. junifer/markers/reho/reho_maps.py +18 -32
  180. junifer/markers/reho/reho_parcels.py +26 -41
  181. junifer/markers/reho/reho_spheres.py +33 -54
  182. junifer/markers/reho/tests/test_junifer_reho.py +178 -0
  183. junifer/markers/reho/tests/test_reho_maps.py +27 -25
  184. junifer/markers/reho/tests/test_reho_parcels.py +28 -22
  185. junifer/markers/reho/tests/test_reho_spheres.py +16 -12
  186. junifer/markers/sphere_aggregation.py +88 -72
  187. junifer/markers/temporal_snr/temporal_snr_base.py +32 -30
  188. junifer/markers/temporal_snr/temporal_snr_maps.py +9 -18
  189. junifer/markers/temporal_snr/temporal_snr_parcels.py +19 -27
  190. junifer/markers/temporal_snr/temporal_snr_spheres.py +27 -41
  191. junifer/markers/temporal_snr/tests/test_temporal_snr_base.py +2 -2
  192. junifer/markers/temporal_snr/tests/test_temporal_snr_maps.py +17 -22
  193. junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +11 -3
  194. junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +9 -9
  195. junifer/markers/tests/test_brainprint.py +10 -9
  196. junifer/markers/tests/test_ets_rss.py +7 -3
  197. junifer/markers/tests/test_lost_regions.py +279 -0
  198. junifer/markers/tests/test_maps_aggregation.py +67 -114
  199. junifer/markers/tests/test_marker_utils.py +40 -1
  200. junifer/markers/tests/test_markers_base.py +275 -6
  201. junifer/markers/tests/test_parcel_aggregation.py +91 -53
  202. junifer/markers/tests/test_sphere_aggregation.py +53 -47
  203. junifer/markers/utils.py +267 -5
  204. junifer/onthefly/__init__.py +2 -3
  205. junifer/onthefly/__init__.pyi +4 -0
  206. junifer/onthefly/_brainprint.py +3 -5
  207. junifer/onthefly/py.typed +0 -0
  208. junifer/onthefly/read_transform.py +11 -9
  209. junifer/onthefly/tests/test_read_transform.py +7 -7
  210. junifer/pipeline/__init__.pyi +4 -2
  211. junifer/pipeline/marker_collection.py +14 -10
  212. junifer/pipeline/pipeline_component_registry.py +25 -6
  213. junifer/pipeline/pipeline_step_mixin.py +5 -12
  214. junifer/pipeline/tests/test_data_object_dumper.py +10 -10
  215. junifer/pipeline/tests/test_marker_collection.py +145 -168
  216. junifer/pipeline/tests/test_pipeline_component_registry.py +52 -8
  217. junifer/pipeline/tests/test_pipeline_step_mixin.py +12 -26
  218. junifer/pipeline/tests/test_update_meta_mixin.py +4 -5
  219. junifer/pipeline/tests/test_workdir_manager.py +39 -0
  220. junifer/pipeline/update_meta_mixin.py +13 -10
  221. junifer/pipeline/utils.py +22 -17
  222. junifer/pipeline/workdir_manager.py +41 -32
  223. junifer/preprocess/__init__.pyi +9 -4
  224. junifer/preprocess/_temporal_filter.py +34 -33
  225. junifer/preprocess/_temporal_slicer.py +17 -30
  226. junifer/preprocess/base.py +99 -55
  227. junifer/preprocess/confounds/__init__.pyi +10 -2
  228. junifer/preprocess/confounds/fmriprep_confound_remover.py +87 -109
  229. junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +64 -45
  230. junifer/preprocess/smoothing/__init__.pyi +2 -2
  231. junifer/preprocess/smoothing/_afni_smoothing.py +8 -7
  232. junifer/preprocess/smoothing/_fsl_smoothing.py +6 -4
  233. junifer/preprocess/smoothing/_nilearn_smoothing.py +7 -5
  234. junifer/preprocess/smoothing/smoothing.py +59 -40
  235. junifer/preprocess/smoothing/tests/test_smoothing.py +28 -8
  236. junifer/preprocess/tests/test_preprocess_base.py +17 -9
  237. junifer/preprocess/tests/test_temporal_filter.py +37 -16
  238. junifer/preprocess/tests/test_temporal_slicer.py +12 -12
  239. junifer/preprocess/warping/__init__.pyi +2 -2
  240. junifer/preprocess/warping/_ants_warper.py +56 -40
  241. junifer/preprocess/warping/_fsl_warper.py +49 -36
  242. junifer/preprocess/warping/_utils.py +106 -0
  243. junifer/preprocess/warping/space_warper.py +99 -98
  244. junifer/preprocess/warping/tests/test_space_warper.py +46 -41
  245. junifer/preprocess/warping/tests/test_warping_utils.py +163 -0
  246. junifer/stats.py +46 -34
  247. junifer/storage/__init__.pyi +8 -4
  248. junifer/storage/base.py +129 -64
  249. junifer/storage/hdf5.py +307 -199
  250. junifer/storage/pandas_base.py +46 -24
  251. junifer/storage/sqlite.py +99 -62
  252. junifer/storage/tests/data/collected_h5io_fork.hdf5 +0 -0
  253. junifer/storage/tests/test_hdf5.py +147 -12
  254. junifer/storage/tests/test_repeated_storage.py +293 -0
  255. junifer/storage/tests/test_sqlite.py +9 -20
  256. junifer/storage/tests/test_storage_base.py +18 -21
  257. junifer/storage/tests/test_utils.py +83 -22
  258. junifer/storage/utils.py +58 -38
  259. junifer/testing/__init__.pyi +2 -2
  260. junifer/testing/datagrabbers.py +480 -44
  261. junifer/testing/registry.py +12 -0
  262. junifer/testing/tests/test_adhdtesting_datagrabber.py +24 -0
  263. junifer/testing/tests/test_oasisvmbtesting_datagrabber.py +5 -0
  264. junifer/testing/tests/test_partlycloudytesting_datagrabber.py +52 -0
  265. junifer/testing/tests/test_spmauditory_datagrabber.py +16 -0
  266. junifer/testing/tests/test_testing_registry.py +31 -0
  267. junifer/testing/tests/test_testing_utils.py +35 -0
  268. junifer/testing/tests/test_uclacnpvbmtesting_datagrabber.py +81 -0
  269. junifer/testing/utils.py +33 -1
  270. junifer/tests/test_stats.py +1 -5
  271. junifer/typing/__init__.pyi +2 -0
  272. junifer/typing/_typing.py +34 -19
  273. junifer/typing/py.typed +0 -0
  274. junifer/utils/__init__.pyi +10 -1
  275. junifer/utils/_config.py +1 -2
  276. junifer/utils/helpers.py +68 -2
  277. junifer/utils/logging.py +31 -7
  278. junifer/utils/tests/test_helpers.py +36 -1
  279. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/METADATA +43 -35
  280. junifer-0.0.8.dist-info/RECORD +402 -0
  281. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/WHEEL +1 -1
  282. junifer/cli/tests/test_parser.py +0 -280
  283. junifer/external/h5io/h5io/__init__.py +0 -15
  284. junifer/external/h5io/h5io/_h5io.py +0 -767
  285. junifer/external/h5io/h5io/_version.py +0 -1
  286. junifer/external/h5io/h5io/chunked_array.py +0 -94
  287. junifer/external/h5io/h5io/chunked_list.py +0 -65
  288. junifer/markers/complexity/__init__.pyi +0 -17
  289. junifer-0.0.7.dev332.dist-info/RECORD +0 -353
  290. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/entry_points.txt +0 -0
  291. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/licenses/AUTHORS.rst +0 -0
  292. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/licenses/LICENSE.md +0 -0
  293. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/top_level.txt +0 -0
@@ -8,23 +8,24 @@ from pathlib import Path
8
8
  from typing import (
9
9
  Any,
10
10
  ClassVar,
11
- Optional,
12
- Union,
13
11
  )
14
12
 
15
13
  import numpy as np
16
14
  import numpy.typing as npt
15
+ from pydantic import PositiveInt
17
16
 
18
17
  from ..api.decorators import register_marker
18
+ from ..datagrabber import DataType
19
19
  from ..external.BrainPrint.brainprint.brainprint import (
20
20
  compute_asymmetry,
21
21
  compute_brainprint,
22
22
  )
23
23
  from ..external.BrainPrint.brainprint.surfaces import surf_to_vtk
24
- from ..pipeline import WorkDirManager
24
+ from ..pipeline import ExtDep, WorkDirManager
25
+ from ..storage import StorageType
25
26
  from ..typing import Dependencies, ExternalDependencies, MarkerInOutMappings
26
- from ..utils import logger, run_ext_cmd
27
- from .base import BaseMarker
27
+ from ..utils import run_ext_cmd
28
+ from .base import BaseMarker, logger
28
29
 
29
30
 
30
31
  __all__ = ["BrainPrint"]
@@ -60,15 +61,15 @@ class BrainPrint(BaseMarker):
60
61
  execution speed. Requires the ``scikit-sparse`` library. If it cannot
61
62
  be found, an error will be thrown. If False, will use slower LU
62
63
  decomposition (default False).
63
- name : str, optional
64
- The name of the marker. If None, will use the class name (default
65
- None).
64
+ name : str or None, optional
65
+ The name of the marker.
66
+ If None, will use the class name (default None).
66
67
 
67
68
  """
68
69
 
69
70
  _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [
70
71
  {
71
- "name": "freesurfer",
72
+ "name": ExtDep.FreeSurfer,
72
73
  "commands": [
73
74
  "mri_binarize",
74
75
  "mri_pretess",
@@ -81,35 +82,25 @@ class BrainPrint(BaseMarker):
81
82
  _DEPENDENCIES: ClassVar[Dependencies] = {"lapy", "numpy"}
82
83
 
83
84
  _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = {
84
- "FreeSurfer": {
85
- "eigenvalues": "scalar_table",
86
- "areas": "vector",
87
- "volumes": "vector",
88
- "distances": "vector",
85
+ DataType.FreeSurfer: {
86
+ "eigenvalues": StorageType.ScalarTable,
87
+ "areas": StorageType.Vector,
88
+ "volumes": StorageType.Vector,
89
+ "distances": StorageType.Vector,
89
90
  }
90
91
  }
91
92
 
92
- def __init__(
93
- self,
94
- num: int = 50,
95
- skip_cortex=False,
96
- keep_eigenvectors: bool = False,
97
- norm: str = "none",
98
- reweight: bool = False,
99
- asymmetry: bool = False,
100
- asymmetry_distance: str = "euc",
101
- use_cholmod: bool = False,
102
- name: Optional[str] = None,
103
- ) -> None:
104
- self.num = num
105
- self.skip_cortex = skip_cortex
106
- self.keep_eigenvectors = keep_eigenvectors
107
- self.norm = norm
108
- self.reweight = reweight
109
- self.asymmetry = asymmetry
110
- self.asymmetry_distance = asymmetry_distance
111
- self.use_cholmod = use_cholmod
112
- super().__init__(name=name, on="FreeSurfer")
93
+ num: PositiveInt = 50
94
+ skip_cortex: bool = False
95
+ keep_eigenvectors: bool = False
96
+ norm: str = "none"
97
+ reweight: bool = False
98
+ asymmetry: bool = False
99
+ asymmetry_distance: str = "euc"
100
+ use_cholmod: bool = False
101
+
102
+ _tempdir = Path()
103
+ _element_tempdir = Path()
113
104
 
114
105
  def _create_aseg_surface(
115
106
  self,
@@ -307,7 +298,7 @@ class BrainPrint(BaseMarker):
307
298
 
308
299
  def _fix_nan(
309
300
  self,
310
- input_data: list[Union[float, str, npt.ArrayLike]],
301
+ input_data: list[float | str | npt.ArrayLike],
311
302
  ) -> np.ndarray: # pragma: no cover
312
303
  """Convert BrainPrint output with string NaN to ``numpy.nan``.
313
304
 
@@ -329,7 +320,7 @@ class BrainPrint(BaseMarker):
329
320
  def compute(
330
321
  self,
331
322
  input: dict[str, Any],
332
- extra_input: Optional[dict] = None,
323
+ extra_input: dict | None = None,
333
324
  ) -> dict: # pragma: no cover
334
325
  """Compute.
335
326
 
@@ -353,7 +344,7 @@ class BrainPrint(BaseMarker):
353
344
  - ``col_names`` : surface labels as list of str
354
345
  - ``row_names`` : eigenvalue count labels as list of str
355
346
  - ``row_header_col_name`` : "eigenvalue"
356
- ()
347
+
357
348
  * ``areas`` : dictionary with the following keys:
358
349
 
359
350
  - ``data`` : areas as ``np.ndarray``
@@ -364,7 +355,7 @@ class BrainPrint(BaseMarker):
364
355
  - ``data`` : volumes as ``np.ndarray``
365
356
  - ``col_names`` : surface labels as list of str
366
357
 
367
- * ``distances`` : dictionary with the following keys
358
+ * ``distances`` : dictionary with the following keys \
368
359
  if ``asymmetry = True``:
369
360
 
370
361
  - ``data`` : distances as ``np.ndarray``
@@ -15,7 +15,24 @@ if find_spec("neurokit2") is None:
15
15
  msg="Could not find `neurokit2`, make sure the package is installed.",
16
16
  klass=ImportError,
17
17
  )
18
- else:
19
- import lazy_loader as lazy
20
18
 
21
- __getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
19
+ # Not lazy: importing the sub-package (e.g., with ``with:`` in the YAML)
20
+ # registers the markers, as they are not built-in components of the registry
21
+ from .hurst_exponent import HurstExponent # noqa: E402
22
+ from .range_entropy import RangeEntropy # noqa: E402
23
+ from .range_entropy_auc import RangeEntropyAUC # noqa: E402
24
+ from .perm_entropy import PermEntropy # noqa: E402
25
+ from .weighted_perm_entropy import WeightedPermEntropy # noqa: E402
26
+ from .sample_entropy import SampleEntropy # noqa: E402
27
+ from .multiscale_entropy_auc import MultiscaleEntropyAUC # noqa: E402
28
+
29
+
30
+ __all__ = [
31
+ "HurstExponent",
32
+ "RangeEntropy",
33
+ "RangeEntropyAUC",
34
+ "PermEntropy",
35
+ "WeightedPermEntropy",
36
+ "SampleEntropy",
37
+ "MultiscaleEntropyAUC",
38
+ ]
@@ -1,75 +1,71 @@
1
1
  """Provide base class for complexity."""
2
2
 
3
3
  # Authors: Amir Omidvarnia <a.omidvarnia@fz-juelich.de>
4
+ # Synchon Mandal <s.mandal@fz-juelich.de>
4
5
  # License: AGPL
5
6
 
6
7
  from abc import abstractmethod
7
8
  from typing import (
8
- TYPE_CHECKING,
9
+ Annotated,
9
10
  Any,
10
11
  ClassVar,
11
- Optional,
12
- Union,
13
12
  )
14
13
 
14
+ import numpy as np
15
+ from pydantic import BeforeValidator
16
+
17
+ from ...datagrabber import DataType
18
+ from ...storage import StorageType
15
19
  from ...typing import Dependencies, MarkerInOutMappings
16
- from ...utils import raise_error
20
+ from ...utils import ensure_list, ensure_list_or_none, raise_error
17
21
  from ..base import BaseMarker
18
22
  from ..parcel_aggregation import ParcelAggregation
19
-
20
-
21
- if TYPE_CHECKING:
22
- import numpy as np
23
+ from ..utils import _has_data
23
24
 
24
25
 
25
26
  __all__ = ["ComplexityBase"]
26
27
 
27
28
 
28
29
  class ComplexityBase(BaseMarker):
29
- """Base class for complexity computation.
30
+ """Abstract base class for complexity computation.
30
31
 
31
32
  Parameters
32
33
  ----------
33
34
  parcellation : str or list of str
34
- The name(s) of the parcellation(s). Check valid options by calling
35
- :func:`junifer.data.parcellations.list_parcellations`.
35
+ The name(s) of the parcellation(s) to use.
36
+ See :func:`.list_data` for options.
36
37
  agg_method : str, optional
37
- The method to perform aggregation using. Check valid options in
38
- :func:`junifer.stats.get_aggfunc_by_name` (default "mean").
39
- agg_method_params : dict, optional
40
- Parameters to pass to the aggregation function. Check valid options in
41
- :func:`junifer.stats.get_aggfunc_by_name` (default None).
42
- masks : str, dict or list of dict or str, optional
38
+ The aggregation function to use.
39
+ See :func:`.get_aggfunc_by_name` for options
40
+ (default "mean").
41
+ agg_method_params : dict or None, optional
42
+ The parameters to pass to the aggregation function.
43
+ See :func:`.get_aggfunc_by_name` for options (default None).
44
+ masks : str, dict, list of them or None, optional
43
45
  The specification of the masks to apply to regions before extracting
44
46
  signals. Check :ref:`Using Masks <using_masks>` for more details.
45
47
  If None, will not apply any mask (default None).
46
- name : str, optional
47
- The name of the marker. If None, it will use the class name
48
- (default None).
48
+ name : str or None, optional
49
+ The name of the marker.
50
+ If None, will use the class name (default None).
49
51
 
50
52
  """
51
53
 
52
54
  _DEPENDENCIES: ClassVar[Dependencies] = {"nilearn", "neurokit2"}
53
55
 
54
56
  _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = {
55
- "BOLD": {
56
- "complexity": "vector",
57
+ DataType.BOLD: {
58
+ "complexity": StorageType.Vector,
57
59
  },
58
60
  }
59
61
 
60
- def __init__(
61
- self,
62
- parcellation: Union[str, list[str]],
63
- agg_method: str = "mean",
64
- agg_method_params: Optional[dict] = None,
65
- masks: Union[str, dict, list[Union[dict, str]], None] = None,
66
- name: Optional[str] = None,
67
- ) -> None:
68
- self.parcellation = parcellation
69
- self.agg_method = agg_method
70
- self.agg_method_params = agg_method_params
71
- self.masks = masks
72
- super().__init__(on="BOLD", name=name)
62
+ parcellation: Annotated[str | list[str], BeforeValidator(ensure_list)]
63
+ agg_method: str = "mean"
64
+ agg_method_params: dict | None = None
65
+ masks: Annotated[
66
+ dict | str | list[dict | str] | None,
67
+ BeforeValidator(ensure_list_or_none),
68
+ ] = None
73
69
 
74
70
  @abstractmethod
75
71
  def compute_complexity(
@@ -85,7 +81,7 @@ class ComplexityBase(BaseMarker):
85
81
  def compute(
86
82
  self,
87
83
  input: dict[str, Any],
88
- extra_input: Optional[dict[str, Any]] = None,
84
+ extra_input: dict[str, Any] | None = None,
89
85
  ) -> dict[str, Any]:
90
86
  """Compute.
91
87
 
@@ -117,14 +113,17 @@ class ComplexityBase(BaseMarker):
117
113
  method=self.agg_method,
118
114
  method_params=self.agg_method_params,
119
115
  masks=self.masks,
120
- on="BOLD",
116
+ on=DataType.BOLD,
121
117
  ).compute(input=input, extra_input=extra_input)
122
- # Compute complexity measure
118
+ # Compute complexity measure on the regions with data (e.g. regions
119
+ # lost in resampling have none) and set the others to NaN
120
+ data = parcel_aggregation["aggregation"]["data"]
121
+ has_data = _has_data(data)
122
+ complexity = np.full((1, data.shape[1]), np.nan)
123
+ complexity[:, has_data] = self.compute_complexity(data[:, has_data])
123
124
  return {
124
125
  "complexity": {
125
- "data": self.compute_complexity(
126
- parcel_aggregation["aggregation"]["data"]
127
- ),
126
+ "data": complexity,
128
127
  "col_names": parcel_aggregation["aggregation"]["col_names"],
129
128
  }
130
129
  }
@@ -2,15 +2,15 @@
2
2
 
3
3
  # Authors: Amir Omidvarnia <a.omidvarnia@fz-juelich.de>
4
4
  # Leonard Sasse <l.sasse@fz-juelich.de>
5
+ # Synchon Mandal <s.mandal@fz-juelich.de>
5
6
  # License: AGPL
6
7
 
7
- from typing import Optional, Union
8
-
9
8
  import neurokit2 as nk
10
9
  import numpy as np
11
10
 
12
11
  from ...api.decorators import register_marker
13
- from ...utils import logger, warn_with_log
12
+ from ...utils import warn_with_log
13
+ from ..base import logger
14
14
  from .complexity_base import ComplexityBase
15
15
 
16
16
 
@@ -27,22 +27,23 @@ class HurstExponent(ComplexityBase):
27
27
  The name(s) of the parcellation(s) to use.
28
28
  See :func:`.list_data` for options.
29
29
  agg_method : str, optional
30
- The method to perform aggregation using. Check valid options in
31
- :func:`junifer.stats.get_aggfunc_by_name` (default "mean").
32
- agg_method_params : dict, optional
33
- Parameters to pass to the aggregation function. Check valid options in
34
- :func:`junifer.stats.get_aggfunc_by_name` (default None).
35
- masks : str, dict or list of dict or str, optional
30
+ The aggregation function to use.
31
+ See :func:`.get_aggfunc_by_name` for options
32
+ (default "mean").
33
+ agg_method_params : dict or None, optional
34
+ The parameters to pass to the aggregation function.
35
+ See :func:`.get_aggfunc_by_name` for options (default None).
36
+ masks : str, dict, list of them or None, optional
36
37
  The specification of the masks to apply to regions before extracting
37
38
  signals. Check :ref:`Using Masks <using_masks>` for more details.
38
39
  If None, will not apply any mask (default None).
39
- params : dict, optional
40
- Parameters to pass to the Hurst exponent calculation function. For more
41
- information, check out ``junifer.markers.utils._hurst_exponent``.
42
- If None, value is set to {"method": "dfa"} (default None).
43
- name : str, optional
44
- The name of the marker. If None, it will use the class name
45
- (default None).
40
+ params : dict or None, optional
41
+ The parameters to pass to the Hurst exponent calculation function.
42
+ See ``junifer.markers.utils._hurst_exponent`` for more information.
43
+ If None, value is set to ``{"method": "dfa"}`` (default None).
44
+ name : str or None, optional
45
+ The name of the marker.
46
+ If None, will use the class name (default None).
46
47
 
47
48
  Warnings
48
49
  --------
@@ -53,26 +54,12 @@ class HurstExponent(ComplexityBase):
53
54
 
54
55
  """
55
56
 
56
- def __init__(
57
- self,
58
- parcellation: Union[str, list[str]],
59
- agg_method: str = "mean",
60
- agg_method_params: Optional[dict] = None,
61
- masks: Union[str, dict, list[Union[dict, str]], None] = None,
62
- params: Optional[dict] = None,
63
- name: Optional[str] = None,
64
- ) -> None:
65
- super().__init__(
66
- parcellation=parcellation,
67
- agg_method=agg_method,
68
- agg_method_params=agg_method_params,
69
- masks=masks,
70
- name=name,
71
- )
72
- if params is None:
57
+ params: dict | None = None
58
+
59
+ def validate_marker_params(self) -> None:
60
+ """Run extra logical validation for marker."""
61
+ if self.params is None:
73
62
  self.params = {"method": "dfa"}
74
- else:
75
- self.params = params
76
63
 
77
64
  def compute_complexity(
78
65
  self,
@@ -2,21 +2,44 @@
2
2
 
3
3
  # Authors: Amir Omidvarnia <a.omidvarnia@fz-juelich.de>
4
4
  # Leonard Sasse <l.sasse@fz-juelich.de>
5
+ # Synchon Mandal <s.mandal@fz-juelich.de>
5
6
  # License: AGPL
6
7
 
7
- from typing import Optional, Union
8
+ from collections.abc import Generator
9
+ from contextlib import contextmanager
8
10
 
9
11
  import neurokit2 as nk
10
12
  import numpy as np
11
13
 
12
14
  from ...api.decorators import register_marker
13
- from ...utils import logger, warn_with_log
15
+ from ...utils import warn_with_log
16
+ from ..base import logger
14
17
  from .complexity_base import ComplexityBase
15
18
 
16
19
 
17
20
  __all__ = ["MultiscaleEntropyAUC"]
18
21
 
19
22
 
23
+ # TODO: remove once the neurokit2 pin (0.2.12) can be raised (0.2.13
24
+ # requires pandas < 3 and setuptools < 82)
25
+ @contextmanager
26
+ def _numpy_trapz() -> Generator[None, None, None]:
27
+ """Provide ``numpy.trapz`` for ``neurokit2.entropy_multiscale``.
28
+
29
+ ``numpy.trapz`` was removed in numpy 2.4 in favour of
30
+ ``numpy.trapezoid``, but neurokit2 <= 0.2.12 still uses it.
31
+
32
+ """
33
+ if hasattr(np, "trapz"):
34
+ yield
35
+ return
36
+ np.trapz = np.trapezoid
37
+ try:
38
+ yield
39
+ finally:
40
+ del np.trapz
41
+
42
+
20
43
  @register_marker
21
44
  class MultiscaleEntropyAUC(ComplexityBase):
22
45
  """Class for AUC of multiscale entropy of a time series.
@@ -27,23 +50,25 @@ class MultiscaleEntropyAUC(ComplexityBase):
27
50
  The name(s) of the parcellation(s) to use.
28
51
  See :func:`.list_data` for options.
29
52
  agg_method : str, optional
30
- The method to perform aggregation using. Check valid options in
31
- :func:`junifer.stats.get_aggfunc_by_name` (default "mean").
32
- agg_method_params : dict, optional
33
- Parameters to pass to the aggregation function. Check valid options in
34
- :func:`junifer.stats.get_aggfunc_by_name` (default None).
35
- masks : str, dict or list of dict or str, optional
53
+ The aggregation function to use.
54
+ See :func:`.get_aggfunc_by_name` for options
55
+ (default "mean").
56
+ agg_method_params : dict or None, optional
57
+ The parameters to pass to the aggregation function.
58
+ See :func:`.get_aggfunc_by_name` for options (default None).
59
+ masks : str, dict, list of them or None, optional
36
60
  The specification of the masks to apply to regions before extracting
37
61
  signals. Check :ref:`Using Masks <using_masks>` for more details.
38
62
  If None, will not apply any mask (default None).
39
- params : dict, optional
40
- Parameters to pass to the AUC of multiscale entropy calculation
41
- function. For more information, check out
42
- ``junifer.markers.utils._multiscale_entropy_auc``. If None, value
43
- is set to {"m": 2, "tol": 0.5, "scale": 10} (default None).
44
- name : str, optional
45
- The name of the marker. If None, it will use the class name
63
+ params : dict or None, optional
64
+ The parameters to pass to the AUC of multiscale entropy calculation
65
+ function. See
66
+ ``junifer.markers.utils._multiscale_entropy_auc`` for more information.
67
+ If None, value is set to ``{"m": 2, "tol": 0.5, "scale": 10}``
46
68
  (default None).
69
+ name : str or None, optional
70
+ The name of the marker.
71
+ If None, will use the class name (default None).
47
72
 
48
73
  Warnings
49
74
  --------
@@ -54,26 +79,12 @@ class MultiscaleEntropyAUC(ComplexityBase):
54
79
 
55
80
  """
56
81
 
57
- def __init__(
58
- self,
59
- parcellation: Union[str, list[str]],
60
- agg_method: str = "mean",
61
- agg_method_params: Optional[dict] = None,
62
- masks: Union[str, dict, list[Union[dict, str]], None] = None,
63
- params: Optional[dict] = None,
64
- name: Optional[str] = None,
65
- ) -> None:
66
- super().__init__(
67
- parcellation=parcellation,
68
- agg_method=agg_method,
69
- agg_method_params=agg_method_params,
70
- masks=masks,
71
- name=name,
72
- )
73
- if params is None:
82
+ params: dict | None = None
83
+
84
+ def validate_marker_params(self) -> None:
85
+ """Run extra logical validation for marker."""
86
+ if self.params is None:
74
87
  self.params = {"m": 2, "tol": 0.5, "scale": 10}
75
- else:
76
- self.params = params
77
88
 
78
89
  def compute_complexity(
79
90
  self,
@@ -123,13 +134,14 @@ class MultiscaleEntropyAUC(ComplexityBase):
123
134
  for idx_roi in range(n_roi):
124
135
  sig = extracted_bold_values[:, idx_roi]
125
136
  tol_corrected = tol * np.std(sig)
126
- tmp = nk.entropy_multiscale(
127
- sig,
128
- scale=scale,
129
- dimension=emb_dim,
130
- tolerance=tol_corrected,
131
- method="MSEn",
132
- )
137
+ with _numpy_trapz():
138
+ tmp = nk.entropy_multiscale(
139
+ sig,
140
+ scale=scale,
141
+ dimension=emb_dim,
142
+ tolerance=tol_corrected,
143
+ method="MSEn",
144
+ )
133
145
 
134
146
  MSEn_auc_roi[idx_roi] = tmp[0]
135
147
 
@@ -2,15 +2,15 @@
2
2
 
3
3
  # Authors: Amir Omidvarnia <a.omidvarnia@fz-juelich.de>
4
4
  # Leonard Sasse <l.sasse@fz-juelich.de>
5
+ # Synchon Mandal <s.mandal@fz-juelich.de>
5
6
  # License: AGPL
6
7
 
7
- from typing import Optional, Union
8
-
9
8
  import neurokit2 as nk
10
9
  import numpy as np
11
10
 
12
11
  from ...api.decorators import register_marker
13
- from ...utils import logger, warn_with_log
12
+ from ...utils import warn_with_log
13
+ from ..base import logger
14
14
  from .complexity_base import ComplexityBase
15
15
 
16
16
 
@@ -27,23 +27,23 @@ class PermEntropy(ComplexityBase):
27
27
  The name(s) of the parcellation(s) to use.
28
28
  See :func:`.list_data` for options.
29
29
  agg_method : str, optional
30
- The method to perform aggregation using. Check valid options in
31
- :func:`junifer.stats.get_aggfunc_by_name` (default "mean").
32
- agg_method_params : dict, optional
33
- Parameters to pass to the aggregation function. Check valid options in
34
- :func:`junifer.stats.get_aggfunc_by_name` (default None).
35
- masks : str, dict or list of dict or str, optional
30
+ The aggregation function to use.
31
+ See :func:`.get_aggfunc_by_name` for options
32
+ (default "mean").
33
+ agg_method_params : dict or None, optional
34
+ The parameters to pass to the aggregation function.
35
+ See :func:`.get_aggfunc_by_name` for options (default None).
36
+ masks : str, dict, list of them or None, optional
36
37
  The specification of the masks to apply to regions before extracting
37
38
  signals. Check :ref:`Using Masks <using_masks>` for more details.
38
39
  If None, will not apply any mask (default None).
39
- params : dict, optional
40
- Parameters to pass to the permutation entropy calculation function.
41
- For more information, check out
42
- ``junifer.markers.utils._perm_entropy``. If None, value is set to
43
- {"m": 2, "delay": 1} (default None).
44
- name : str, optional
45
- The name of the marker. If None, it will use the class name
46
- (default None).
40
+ params : dict or None, optional
41
+ The parameters to pass to the permutation entropy calculation function.
42
+ See ``junifer.markers.utils._perm_entropy`` for more information.
43
+ If None, value is set to ``{"m": 2, "delay": 1}`` (default None).
44
+ name : str or None, optional
45
+ The name of the marker.
46
+ If None, will use the class name (default None).
47
47
 
48
48
  Warnings
49
49
  --------
@@ -54,26 +54,12 @@ class PermEntropy(ComplexityBase):
54
54
 
55
55
  """
56
56
 
57
- def __init__(
58
- self,
59
- parcellation: Union[str, list[str]],
60
- agg_method: str = "mean",
61
- agg_method_params: Optional[dict] = None,
62
- masks: Union[str, dict, list[Union[dict, str]], None] = None,
63
- params: Optional[dict] = None,
64
- name: Optional[str] = None,
65
- ) -> None:
66
- super().__init__(
67
- parcellation=parcellation,
68
- agg_method=agg_method,
69
- agg_method_params=agg_method_params,
70
- masks=masks,
71
- name=name,
72
- )
73
- if params is None:
57
+ params: dict | None = None
58
+
59
+ def validate_marker_params(self) -> None:
60
+ """Run extra logical validation for marker."""
61
+ if self.params is None:
74
62
  self.params = {"m": 4, "delay": 1}
75
- else:
76
- self.params = params
77
63
 
78
64
  def compute_complexity(
79
65
  self,