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
@@ -3,20 +3,36 @@
3
3
  # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
4
  # License: AGPL
5
5
 
6
- from typing import Any, ClassVar, Optional, Union
6
+ from typing import Annotated, Any, ClassVar, Literal
7
7
 
8
+ import numpy as np
8
9
  from nilearn.maskers import NiftiMapsMasker
10
+ from pydantic import BeforeValidator
9
11
 
10
12
  from ..api.decorators import register_marker
11
13
  from ..data import get_data
14
+ from ..datagrabber import DataType
12
15
  from ..stats import get_aggfunc_by_name
16
+ from ..storage import StorageType
13
17
  from ..typing import Dependencies, MarkerInOutMappings
14
- from ..utils import logger, raise_error, warn_with_log
15
- from .base import BaseMarker
18
+ from ..utils import ensure_list_or_none, raise_error, warn_with_log
19
+ from .base import BaseMarker, logger
16
20
 
17
21
 
18
22
  __all__ = ["MapsAggregation"]
19
23
 
24
+ _on = Literal[
25
+ DataType.T1w,
26
+ DataType.T2w,
27
+ DataType.BOLD,
28
+ DataType.VBM_GM,
29
+ DataType.VBM_WM,
30
+ DataType.VBM_CSF,
31
+ DataType.FALFF,
32
+ DataType.GCOR,
33
+ DataType.LCOR,
34
+ ]
35
+
20
36
 
21
37
  @register_marker
22
38
  class MapsAggregation(BaseMarker):
@@ -27,23 +43,26 @@ class MapsAggregation(BaseMarker):
27
43
  maps : str
28
44
  The name of the map(s) to use.
29
45
  See :func:`.list_data` for options.
30
- time_method : str, optional
31
- The method to use to aggregate the time series over the time points,
32
- after aggregation (only applicable to BOLD data). If None,
46
+ time_method : str or None, optional
47
+ The aggregation function to use for time series after applying
48
+ :term:`method` (only applicable to BOLD data). If None,
33
49
  it will not operate on the time dimension (default None).
34
- time_method_params : dict, optional
50
+ time_method_params : dict or None, optional
35
51
  The parameters to pass to the time aggregation method (default None).
36
- masks : str, dict or list of dict or str, optional
52
+ on : {``DataType.T1w``, ``DataType.T2w``, ``DataType.BOLD``, \
53
+ ``DataType.VBM_GM``, ``DataType.VBM_WM``, ``DataType.VBM_CSF``, \
54
+ ``DataType.FALFF``, ``DataType.GCOR``, ``DataType.LCOR``} or \
55
+ list of them or None, optional
56
+ The data type(s) to apply the marker on.
57
+ If None, will work on all available data.
58
+ Check :enum:`.DataType` for valid values (default None).
59
+ masks : str, dict, list of them or None, optional
37
60
  The specification of the masks to apply to regions before extracting
38
61
  signals. Check :ref:`Using Masks <using_masks>` for more details.
39
62
  If None, will not apply any mask (default None).
40
- on : {"T1w", "T2w", "BOLD", "VBM_GM", "VBM_WM", "VBM_CSF", "fALFF", \
41
- "GCOR", "LCOR"} or list of the options, optional
42
- The data types to apply the marker to. If None, will work on all
43
- available data (default None).
44
- name : str, optional
45
- The name of the marker. If None, will use the class name (default
46
- None).
63
+ name : str or None, optional
64
+ The name of the marker.
65
+ If None, will use the class name (default None).
47
66
 
48
67
  Raises
49
68
  ------
@@ -56,64 +75,62 @@ class MapsAggregation(BaseMarker):
56
75
  _DEPENDENCIES: ClassVar[Dependencies] = {"nilearn", "numpy"}
57
76
 
58
77
  _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = {
59
- "T1w": {
60
- "aggregation": "vector",
78
+ DataType.T1w: {
79
+ "aggregation": StorageType.Vector,
61
80
  },
62
- "T2w": {
63
- "aggregation": "vector",
81
+ DataType.T2w: {
82
+ "aggregation": StorageType.Vector,
64
83
  },
65
- "BOLD": {
66
- "aggregation": "timeseries",
84
+ DataType.BOLD: {
85
+ "aggregation": StorageType.Timeseries,
67
86
  },
68
- "VBM_GM": {
69
- "aggregation": "vector",
87
+ DataType.VBM_GM: {
88
+ "aggregation": StorageType.Vector,
70
89
  },
71
- "VBM_WM": {
72
- "aggregation": "vector",
90
+ DataType.VBM_WM: {
91
+ "aggregation": StorageType.Vector,
73
92
  },
74
- "VBM_CSF": {
75
- "aggregation": "vector",
93
+ DataType.VBM_CSF: {
94
+ "aggregation": StorageType.Vector,
76
95
  },
77
- "fALFF": {
78
- "aggregation": "vector",
96
+ DataType.FALFF: {
97
+ "aggregation": StorageType.Vector,
79
98
  },
80
- "GCOR": {
81
- "aggregation": "vector",
99
+ DataType.GCOR: {
100
+ "aggregation": StorageType.Vector,
82
101
  },
83
- "LCOR": {
84
- "aggregation": "vector",
102
+ DataType.LCOR: {
103
+ "aggregation": StorageType.Vector,
85
104
  },
86
105
  }
87
106
 
88
- def __init__(
89
- self,
90
- maps: str,
91
- time_method: Optional[str] = None,
92
- time_method_params: Optional[dict[str, Any]] = None,
93
- masks: Union[str, dict, list[Union[dict, str]], None] = None,
94
- on: Union[list[str], str, None] = None,
95
- name: Optional[str] = None,
96
- ) -> None:
97
- self.maps = maps
98
- self.masks = masks
99
- super().__init__(on=on, name=name)
100
-
101
- # Verify after super init so self._on is set
102
- if "BOLD" not in self._on and time_method is not None:
107
+ maps: str
108
+ time_method: str | None = None
109
+ time_method_params: dict[str, Any] | None = None
110
+ masks: Annotated[
111
+ dict | str | list[dict | str] | None,
112
+ BeforeValidator(ensure_list_or_none),
113
+ ] = None
114
+ on: Annotated[
115
+ _on | list[_on] | None, BeforeValidator(ensure_list_or_none)
116
+ ] = None
117
+
118
+ def validate_marker_params(self) -> None:
119
+ """Run extra logical validation for marker."""
120
+ # self.on is set already
121
+ if "BOLD" not in self.on and self.time_method is not None:
103
122
  raise_error(
104
123
  "`time_method` can only be used with BOLD data. "
105
124
  "Please remove `time_method` parameter."
106
125
  )
107
- if time_method is None and time_method_params is not None:
126
+ if self.time_method is None and self.time_method_params is not None:
108
127
  raise_error(
109
128
  "`time_method_params` can only be used with `time_method`. "
110
129
  "Please remove `time_method_params` parameter."
111
130
  )
112
- self.time_method = time_method
113
- self.time_method_params = time_method_params or {}
114
131
 
115
132
  def compute(
116
- self, input: dict[str, Any], extra_input: Optional[dict] = None
133
+ self, input: dict[str, Any], extra_input: dict | None = None
117
134
  ) -> dict:
118
135
  """Compute.
119
136
 
@@ -169,15 +186,20 @@ class MapsAggregation(BaseMarker):
169
186
  extra_input=extra_input,
170
187
  )
171
188
 
172
- # Initialize masker
189
+ # Initialize masker; the maps (and mask) are already tailored to the
190
+ # input image, so no resampling is needed
173
191
  logger.debug("Masking")
174
192
  masker = NiftiMapsMasker(
175
193
  maps_img=maps_img,
176
194
  mask_img=mask_img,
177
- target_affine=t_input_img.affine,
195
+ resampling_target=None,
196
+ standardize=None,
197
+ # Not used, and computing their data at fit time reads the data
198
+ reports=False,
178
199
  )
179
200
  # Mask the input data and extract data
180
- data = masker.fit_transform(t_input_img)
201
+ # nilearn maskers return 1D arrays for 3D images, keep 2D
202
+ data = np.atleast_2d(masker.fit_transform(t_input_img))
181
203
 
182
204
  # Apply time dimension aggregation if required
183
205
  if self.time_method is not None:
@@ -4,22 +4,42 @@
4
4
  # Synchon Mandal <s.mandal@fz-juelich.de>
5
5
  # License: AGPL
6
6
 
7
- from typing import Any, ClassVar, Optional, Union
7
+ from typing import Annotated, Any, ClassVar, Literal
8
8
 
9
9
  import numpy as np
10
10
  from nilearn.image import math_img
11
11
  from nilearn.maskers import NiftiMasker
12
+ from pydantic import BeforeValidator
12
13
 
13
14
  from ..api.decorators import register_marker
14
15
  from ..data import get_data
16
+ from ..datagrabber import DataType
15
17
  from ..stats import get_aggfunc_by_name
18
+ from ..storage import StorageType
16
19
  from ..typing import Dependencies, MarkerInOutMappings
17
- from ..utils import logger, raise_error, warn_with_log
18
- from .base import BaseMarker
20
+ from ..utils import (
21
+ ensure_list,
22
+ ensure_list_or_none,
23
+ raise_error,
24
+ warn_with_log,
25
+ )
26
+ from .base import BaseMarker, logger
19
27
 
20
28
 
21
29
  __all__ = ["ParcelAggregation"]
22
30
 
31
+ _on = Literal[
32
+ DataType.T1w,
33
+ DataType.T2w,
34
+ DataType.BOLD,
35
+ DataType.VBM_GM,
36
+ DataType.VBM_WM,
37
+ DataType.VBM_CSF,
38
+ DataType.FALFF,
39
+ DataType.GCOR,
40
+ DataType.LCOR,
41
+ ]
42
+
23
43
 
24
44
  @register_marker
25
45
  class ParcelAggregation(BaseMarker):
@@ -30,29 +50,33 @@ class ParcelAggregation(BaseMarker):
30
50
  parcellation : str or list of str
31
51
  The name(s) of the parcellation(s) to use.
32
52
  See :func:`.list_data` for options.
33
- method : str
34
- The method to perform aggregation using. Check valid options in
35
- :func:`.get_aggfunc_by_name`.
36
- method_params : dict, optional
37
- Parameters to pass to the aggregation function. Check valid options in
38
- :func:`.get_aggfunc_by_name`.
39
- time_method : str, optional
40
- The method to use to aggregate the time series over the time points,
41
- after applying :term:`method` (only applicable to BOLD data). If None,
53
+ method : str, optional
54
+ The aggregation function to use.
55
+ See :func:`.get_aggfunc_by_name` for options
56
+ (default "mean").
57
+ method_params : dict or None, optional
58
+ The parameters to pass to the aggregation function.
59
+ See :func:`.get_aggfunc_by_name` for options (default None).
60
+ time_method : str or None, optional
61
+ The aggregation function to use for time series after applying
62
+ :term:`method` (only applicable to BOLD data). If None,
42
63
  it will not operate on the time dimension (default None).
43
- time_method_params : dict, optional
44
- The parameters to pass to the time aggregation method (default None).
45
- masks : str, dict or list of dict or str, optional
64
+ time_method_params : dict or None, optional
65
+ The parameters to pass to the time aggregation function (default None).
66
+ on : {``DataType.T1w``, ``DataType.T2w``, ``DataType.BOLD``, \
67
+ ``DataType.VBM_GM``, ``DataType.VBM_WM``, ``DataType.VBM_CSF``, \
68
+ ``DataType.FALFF``, ``DataType.GCOR``, ``DataType.LCOR``} or \
69
+ list of them or None, optional
70
+ The data type(s) to apply the marker on.
71
+ If None, will work on all available data.
72
+ Check :enum:`.DataType` for valid values (default None).
73
+ masks : str, dict, list of them or None, optional
46
74
  The specification of the masks to apply to regions before extracting
47
75
  signals. Check :ref:`Using Masks <using_masks>` for more details.
48
76
  If None, will not apply any mask (default None).
49
- on : {"T1w", "T2w", "BOLD", "VBM_GM", "VBM_WM", "VBM_CSF", "fALFF", \
50
- "GCOR", "LCOR"} or list of the options, optional
51
- The data types to apply the marker to. If None, will work on all
52
- available data (default None).
53
- name : str, optional
54
- The name of the marker. If None, will use the class name (default
55
- None).
77
+ name : str or None, optional
78
+ The name of the marker.
79
+ If None, will use the class name (default None).
56
80
 
57
81
  Raises
58
82
  ------
@@ -65,70 +89,64 @@ class ParcelAggregation(BaseMarker):
65
89
  _DEPENDENCIES: ClassVar[Dependencies] = {"nilearn", "numpy"}
66
90
 
67
91
  _MARKER_INOUT_MAPPINGS: ClassVar[MarkerInOutMappings] = {
68
- "T1w": {
69
- "aggregation": "vector",
92
+ DataType.T1w: {
93
+ "aggregation": StorageType.Vector,
70
94
  },
71
- "T2w": {
72
- "aggregation": "vector",
95
+ DataType.T2w: {
96
+ "aggregation": StorageType.Vector,
73
97
  },
74
- "BOLD": {
75
- "aggregation": "timeseries",
98
+ DataType.BOLD: {
99
+ "aggregation": StorageType.Timeseries,
76
100
  },
77
- "VBM_GM": {
78
- "aggregation": "vector",
101
+ DataType.VBM_GM: {
102
+ "aggregation": StorageType.Vector,
79
103
  },
80
- "VBM_WM": {
81
- "aggregation": "vector",
104
+ DataType.VBM_WM: {
105
+ "aggregation": StorageType.Vector,
82
106
  },
83
- "VBM_CSF": {
84
- "aggregation": "vector",
107
+ DataType.VBM_CSF: {
108
+ "aggregation": StorageType.Vector,
85
109
  },
86
- "fALFF": {
87
- "aggregation": "vector",
110
+ DataType.FALFF: {
111
+ "aggregation": StorageType.Vector,
88
112
  },
89
- "GCOR": {
90
- "aggregation": "vector",
113
+ DataType.GCOR: {
114
+ "aggregation": StorageType.Vector,
91
115
  },
92
- "LCOR": {
93
- "aggregation": "vector",
116
+ DataType.LCOR: {
117
+ "aggregation": StorageType.Vector,
94
118
  },
95
119
  }
96
120
 
97
- def __init__(
98
- self,
99
- parcellation: Union[str, list[str]],
100
- method: str,
101
- method_params: Optional[dict[str, Any]] = None,
102
- time_method: Optional[str] = None,
103
- time_method_params: Optional[dict[str, Any]] = None,
104
- masks: Union[str, dict, list[Union[dict, str]], None] = None,
105
- on: Union[list[str], str, None] = None,
106
- name: Optional[str] = None,
107
- ) -> None:
108
- if not isinstance(parcellation, list):
109
- parcellation = [parcellation]
110
- self.parcellation = parcellation
111
- self.method = method
112
- self.method_params = method_params or {}
113
- self.masks = masks
114
- super().__init__(on=on, name=name)
115
-
116
- # Verify after super init so self._on is set
117
- if "BOLD" not in self._on and time_method is not None:
121
+ parcellation: Annotated[str | list[str], BeforeValidator(ensure_list)]
122
+ method: str = "mean"
123
+ method_params: dict[str, Any] | None = None
124
+ time_method: str | None = None
125
+ time_method_params: dict[str, Any] | None = None
126
+ masks: Annotated[
127
+ dict | str | list[dict | str] | None,
128
+ BeforeValidator(ensure_list_or_none),
129
+ ] = None
130
+ on: Annotated[
131
+ _on | list[_on] | None, BeforeValidator(ensure_list_or_none)
132
+ ] = None
133
+
134
+ def validate_marker_params(self) -> None:
135
+ """Run extra logical validation for marker."""
136
+ # self.on is set already
137
+ if "BOLD" not in self.on and self.time_method is not None:
118
138
  raise_error(
119
139
  "`time_method` can only be used with BOLD data. "
120
140
  "Please remove `time_method` parameter."
121
141
  )
122
- if time_method is None and time_method_params is not None:
142
+ if self.time_method is None and self.time_method_params is not None:
123
143
  raise_error(
124
144
  "`time_method_params` can only be used with `time_method`. "
125
145
  "Please remove `time_method_params` parameter."
126
146
  )
127
- self.time_method = time_method
128
- self.time_method_params = time_method_params or {}
129
147
 
130
148
  def compute(
131
- self, input: dict[str, Any], extra_input: Optional[dict] = None
149
+ self, input: dict[str, Any], extra_input: dict | None = None
132
150
  ) -> dict:
133
151
  """Compute.
134
152
 
@@ -198,13 +216,16 @@ class ParcelAggregation(BaseMarker):
198
216
  mask=mask_img,
199
217
  )
200
218
 
201
- # Initialize masker
219
+ # Initialize masker; the parcellation (and mask) are already
220
+ # tailored to the input image, so no target affine is needed (it
221
+ # would make nilearn crop and copy the input image)
202
222
  logger.debug("Masking")
203
- masker = NiftiMasker(
204
- parcellation_bin, target_affine=t_input_img.affine
205
- )
223
+ # No reports, as they are not used and computing their data at fit
224
+ # time reads the data
225
+ masker = NiftiMasker(parcellation_bin, standardize=None, reports=False)
206
226
  # Mask the input data and the parcellation
207
- data = masker.fit_transform(t_input_img)
227
+ # nilearn maskers return 1D arrays for 3D images, keep 2D
228
+ data = np.atleast_2d(masker.fit_transform(t_input_img))
208
229
  parcellation_values = np.squeeze(
209
230
  masker.transform(parcellation_img)
210
231
  ).astype(int)
@@ -1,5 +1,11 @@
1
- __all__ = ["ReHoMaps", "ReHoParcels", "ReHoSpheres"]
1
+ __all__ = [
2
+ "ReHoImpl",
3
+ "ReHoMaps",
4
+ "ReHoParcels",
5
+ "ReHoSpheres",
6
+ ]
2
7
 
8
+ from .reho_base import ReHoImpl
3
9
  from .reho_maps import ReHoMaps
4
10
  from .reho_parcels import ReHoParcels
5
11
  from .reho_spheres import ReHoSpheres
@@ -3,20 +3,21 @@
3
3
  # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
4
  # License: AGPL
5
5
 
6
+ import atexit
6
7
  from functools import lru_cache
7
8
  from pathlib import Path
8
9
  from typing import (
9
10
  TYPE_CHECKING,
10
11
  ClassVar,
11
- Optional,
12
12
  )
13
13
 
14
14
  import nibabel as nib
15
15
 
16
- from ...pipeline import WorkDirManager
16
+ from ...pipeline import ExtDep, WorkDirManager
17
17
  from ...typing import ExternalDependencies
18
- from ...utils import logger, run_ext_cmd
18
+ from ...utils import run_ext_cmd
19
19
  from ...utils.singleton import Singleton
20
+ from ..base import logger
20
21
 
21
22
 
22
23
  if TYPE_CHECKING:
@@ -36,13 +37,15 @@ class AFNIReHo(metaclass=Singleton):
36
37
 
37
38
  _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [
38
39
  {
39
- "name": "afni",
40
+ "name": ExtDep.AFNI,
40
41
  "commands": ["3dReHo", "3dAFNItoNIFTI"],
41
42
  },
42
43
  ]
43
44
 
44
- def __del__(self) -> None: # pragma: no cover
45
- """Terminate the class."""
45
+ def __init__(self) -> None:
46
+ atexit.register(self._del)
47
+
48
+ def _del(self) -> None:
46
49
  # Clear the computation cache
47
50
  logger.debug("Clearing cache for ReHo computation via AFNI")
48
51
  self.compute.cache_clear()
@@ -52,14 +55,15 @@ class AFNIReHo(metaclass=Singleton):
52
55
  self,
53
56
  input_path: Path,
54
57
  nneigh: int = 27,
55
- neigh_rad: Optional[float] = None,
56
- neigh_x: Optional[float] = None,
57
- neigh_y: Optional[float] = None,
58
- neigh_z: Optional[float] = None,
59
- box_rad: Optional[int] = None,
60
- box_x: Optional[int] = None,
61
- box_y: Optional[int] = None,
62
- box_z: Optional[int] = None,
58
+ mask_path: Path | None = None,
59
+ neigh_rad: float | None = None,
60
+ neigh_x: float | None = None,
61
+ neigh_y: float | None = None,
62
+ neigh_z: float | None = None,
63
+ box_rad: int | None = None,
64
+ box_x: int | None = None,
65
+ box_y: int | None = None,
66
+ box_z: int | None = None,
63
67
  ) -> tuple["Nifti1Image", Path]:
64
68
  """Compute ReHo map.
65
69
 
@@ -75,6 +79,9 @@ class AFNIReHo(metaclass=Singleton):
75
79
  * 27 : for face-, edge-, and node-wise neighbors
76
80
 
77
81
  (default 27).
82
+ mask_path : pathlib.Path or None, optional
83
+ Path to the mask to restrict the computation to, passed to
84
+ ``3dReHo`` as ``-mask``. If None, no mask is used (default None).
78
85
  neigh_rad : positive float, optional
79
86
  The radius of a desired neighbourhood (default None).
80
87
  neigh_x : positive float, optional
@@ -140,6 +147,8 @@ class AFNIReHo(metaclass=Singleton):
140
147
  f"-prefix {reho_out_path_prefix.resolve()}",
141
148
  f"-inset {input_path.resolve()}",
142
149
  ]
150
+ if mask_path is not None:
151
+ reho_cmd.append(f"-mask {mask_path.resolve()}")
143
152
  # Check ellipsoidal / cuboidal volume arguments
144
153
  if neigh_rad:
145
154
  reho_cmd.append(f"-neigh_RAD {neigh_rad}")