junifer 0.0.5.dev242__py3-none-any.whl → 0.0.6__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 (279) hide show
  1. junifer/__init__.py +2 -31
  2. junifer/__init__.pyi +37 -0
  3. junifer/_version.py +9 -4
  4. junifer/api/__init__.py +3 -5
  5. junifer/api/__init__.pyi +4 -0
  6. junifer/api/decorators.py +14 -19
  7. junifer/api/functions.py +165 -109
  8. junifer/api/py.typed +0 -0
  9. junifer/api/queue_context/__init__.py +2 -4
  10. junifer/api/queue_context/__init__.pyi +5 -0
  11. junifer/api/queue_context/gnu_parallel_local_adapter.py +22 -6
  12. junifer/api/queue_context/htcondor_adapter.py +23 -6
  13. junifer/api/queue_context/py.typed +0 -0
  14. junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +3 -3
  15. junifer/api/queue_context/tests/test_htcondor_adapter.py +3 -3
  16. junifer/api/tests/test_functions.py +168 -74
  17. junifer/cli/__init__.py +24 -0
  18. junifer/cli/__init__.pyi +3 -0
  19. junifer/{api → cli}/cli.py +141 -125
  20. junifer/cli/parser.py +235 -0
  21. junifer/cli/py.typed +0 -0
  22. junifer/{api → cli}/tests/test_cli.py +8 -8
  23. junifer/{api/tests/test_api_utils.py → cli/tests/test_cli_utils.py} +5 -4
  24. junifer/{api → cli}/tests/test_parser.py +2 -2
  25. junifer/{api → cli}/utils.py +6 -16
  26. junifer/configs/juseless/__init__.py +2 -2
  27. junifer/configs/juseless/__init__.pyi +3 -0
  28. junifer/configs/juseless/datagrabbers/__init__.py +2 -12
  29. junifer/configs/juseless/datagrabbers/__init__.pyi +13 -0
  30. junifer/configs/juseless/datagrabbers/ixi_vbm.py +2 -2
  31. junifer/configs/juseless/datagrabbers/py.typed +0 -0
  32. junifer/configs/juseless/datagrabbers/tests/test_ucla.py +2 -2
  33. junifer/configs/juseless/datagrabbers/ucla.py +4 -4
  34. junifer/configs/juseless/py.typed +0 -0
  35. junifer/conftest.py +25 -0
  36. junifer/data/__init__.py +2 -42
  37. junifer/data/__init__.pyi +29 -0
  38. junifer/data/_dispatch.py +248 -0
  39. junifer/data/coordinates/__init__.py +9 -0
  40. junifer/data/coordinates/__init__.pyi +5 -0
  41. junifer/data/coordinates/_ants_coordinates_warper.py +104 -0
  42. junifer/data/coordinates/_coordinates.py +385 -0
  43. junifer/data/coordinates/_fsl_coordinates_warper.py +81 -0
  44. junifer/data/{tests → coordinates/tests}/test_coordinates.py +26 -33
  45. junifer/data/masks/__init__.py +9 -0
  46. junifer/data/masks/__init__.pyi +6 -0
  47. junifer/data/masks/_ants_mask_warper.py +177 -0
  48. junifer/data/masks/_fsl_mask_warper.py +106 -0
  49. junifer/data/masks/_masks.py +802 -0
  50. junifer/data/{tests → masks/tests}/test_masks.py +67 -63
  51. junifer/data/parcellations/__init__.py +9 -0
  52. junifer/data/parcellations/__init__.pyi +6 -0
  53. junifer/data/parcellations/_ants_parcellation_warper.py +166 -0
  54. junifer/data/parcellations/_fsl_parcellation_warper.py +89 -0
  55. junifer/data/parcellations/_parcellations.py +1388 -0
  56. junifer/data/{tests → parcellations/tests}/test_parcellations.py +165 -295
  57. junifer/data/pipeline_data_registry_base.py +76 -0
  58. junifer/data/py.typed +0 -0
  59. junifer/data/template_spaces.py +44 -79
  60. junifer/data/tests/test_data_utils.py +1 -2
  61. junifer/data/tests/test_template_spaces.py +8 -4
  62. junifer/data/utils.py +109 -4
  63. junifer/datagrabber/__init__.py +2 -26
  64. junifer/datagrabber/__init__.pyi +27 -0
  65. junifer/datagrabber/aomic/__init__.py +2 -4
  66. junifer/datagrabber/aomic/__init__.pyi +5 -0
  67. junifer/datagrabber/aomic/id1000.py +81 -52
  68. junifer/datagrabber/aomic/piop1.py +83 -55
  69. junifer/datagrabber/aomic/piop2.py +85 -56
  70. junifer/datagrabber/aomic/py.typed +0 -0
  71. junifer/datagrabber/aomic/tests/test_id1000.py +19 -12
  72. junifer/datagrabber/aomic/tests/test_piop1.py +52 -18
  73. junifer/datagrabber/aomic/tests/test_piop2.py +50 -17
  74. junifer/datagrabber/base.py +22 -18
  75. junifer/datagrabber/datalad_base.py +71 -34
  76. junifer/datagrabber/dmcc13_benchmark.py +31 -18
  77. junifer/datagrabber/hcp1200/__init__.py +2 -3
  78. junifer/datagrabber/hcp1200/__init__.pyi +4 -0
  79. junifer/datagrabber/hcp1200/datalad_hcp1200.py +3 -3
  80. junifer/datagrabber/hcp1200/hcp1200.py +26 -15
  81. junifer/datagrabber/hcp1200/py.typed +0 -0
  82. junifer/datagrabber/hcp1200/tests/test_hcp1200.py +8 -2
  83. junifer/datagrabber/multiple.py +14 -9
  84. junifer/datagrabber/pattern.py +132 -96
  85. junifer/datagrabber/pattern_validation_mixin.py +206 -94
  86. junifer/datagrabber/py.typed +0 -0
  87. junifer/datagrabber/tests/test_datalad_base.py +27 -12
  88. junifer/datagrabber/tests/test_dmcc13_benchmark.py +28 -11
  89. junifer/datagrabber/tests/test_multiple.py +48 -2
  90. junifer/datagrabber/tests/test_pattern_datalad.py +1 -1
  91. junifer/datagrabber/tests/test_pattern_validation_mixin.py +6 -6
  92. junifer/datareader/__init__.py +2 -2
  93. junifer/datareader/__init__.pyi +3 -0
  94. junifer/datareader/default.py +6 -6
  95. junifer/datareader/py.typed +0 -0
  96. junifer/external/nilearn/__init__.py +2 -3
  97. junifer/external/nilearn/__init__.pyi +4 -0
  98. junifer/external/nilearn/junifer_connectivity_measure.py +25 -17
  99. junifer/external/nilearn/junifer_nifti_spheres_masker.py +4 -4
  100. junifer/external/nilearn/py.typed +0 -0
  101. junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +17 -16
  102. junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +2 -3
  103. junifer/markers/__init__.py +2 -38
  104. junifer/markers/__init__.pyi +37 -0
  105. junifer/markers/base.py +11 -14
  106. junifer/markers/brainprint.py +12 -14
  107. junifer/markers/complexity/__init__.py +2 -18
  108. junifer/markers/complexity/__init__.pyi +17 -0
  109. junifer/markers/complexity/complexity_base.py +9 -11
  110. junifer/markers/complexity/hurst_exponent.py +7 -7
  111. junifer/markers/complexity/multiscale_entropy_auc.py +7 -7
  112. junifer/markers/complexity/perm_entropy.py +7 -7
  113. junifer/markers/complexity/py.typed +0 -0
  114. junifer/markers/complexity/range_entropy.py +7 -7
  115. junifer/markers/complexity/range_entropy_auc.py +7 -7
  116. junifer/markers/complexity/sample_entropy.py +7 -7
  117. junifer/markers/complexity/tests/test_complexity_base.py +1 -1
  118. junifer/markers/complexity/tests/test_hurst_exponent.py +5 -5
  119. junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +5 -5
  120. junifer/markers/complexity/tests/test_perm_entropy.py +5 -5
  121. junifer/markers/complexity/tests/test_range_entropy.py +5 -5
  122. junifer/markers/complexity/tests/test_range_entropy_auc.py +5 -5
  123. junifer/markers/complexity/tests/test_sample_entropy.py +5 -5
  124. junifer/markers/complexity/tests/test_weighted_perm_entropy.py +5 -5
  125. junifer/markers/complexity/weighted_perm_entropy.py +7 -7
  126. junifer/markers/ets_rss.py +12 -11
  127. junifer/markers/falff/__init__.py +2 -3
  128. junifer/markers/falff/__init__.pyi +4 -0
  129. junifer/markers/falff/_afni_falff.py +38 -45
  130. junifer/markers/falff/_junifer_falff.py +16 -19
  131. junifer/markers/falff/falff_base.py +7 -11
  132. junifer/markers/falff/falff_parcels.py +9 -9
  133. junifer/markers/falff/falff_spheres.py +8 -8
  134. junifer/markers/falff/py.typed +0 -0
  135. junifer/markers/falff/tests/test_falff_spheres.py +3 -1
  136. junifer/markers/functional_connectivity/__init__.py +2 -12
  137. junifer/markers/functional_connectivity/__init__.pyi +13 -0
  138. junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +9 -8
  139. junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +8 -8
  140. junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +7 -7
  141. junifer/markers/functional_connectivity/functional_connectivity_base.py +13 -12
  142. junifer/markers/functional_connectivity/functional_connectivity_parcels.py +8 -8
  143. junifer/markers/functional_connectivity/functional_connectivity_spheres.py +7 -7
  144. junifer/markers/functional_connectivity/py.typed +0 -0
  145. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +1 -2
  146. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +1 -2
  147. junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +6 -6
  148. junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +5 -5
  149. junifer/markers/parcel_aggregation.py +22 -17
  150. junifer/markers/py.typed +0 -0
  151. junifer/markers/reho/__init__.py +2 -3
  152. junifer/markers/reho/__init__.pyi +4 -0
  153. junifer/markers/reho/_afni_reho.py +29 -35
  154. junifer/markers/reho/_junifer_reho.py +13 -14
  155. junifer/markers/reho/py.typed +0 -0
  156. junifer/markers/reho/reho_base.py +7 -11
  157. junifer/markers/reho/reho_parcels.py +10 -10
  158. junifer/markers/reho/reho_spheres.py +9 -9
  159. junifer/markers/sphere_aggregation.py +22 -17
  160. junifer/markers/temporal_snr/__init__.py +2 -3
  161. junifer/markers/temporal_snr/__init__.pyi +4 -0
  162. junifer/markers/temporal_snr/py.typed +0 -0
  163. junifer/markers/temporal_snr/temporal_snr_base.py +11 -10
  164. junifer/markers/temporal_snr/temporal_snr_parcels.py +8 -8
  165. junifer/markers/temporal_snr/temporal_snr_spheres.py +7 -7
  166. junifer/markers/tests/test_ets_rss.py +3 -3
  167. junifer/markers/tests/test_parcel_aggregation.py +24 -24
  168. junifer/markers/tests/test_sphere_aggregation.py +6 -6
  169. junifer/markers/utils.py +3 -3
  170. junifer/onthefly/__init__.py +2 -1
  171. junifer/onthefly/_brainprint.py +138 -0
  172. junifer/onthefly/read_transform.py +5 -8
  173. junifer/pipeline/__init__.py +2 -10
  174. junifer/pipeline/__init__.pyi +13 -0
  175. junifer/{markers/collection.py → pipeline/marker_collection.py} +8 -14
  176. junifer/pipeline/pipeline_component_registry.py +294 -0
  177. junifer/pipeline/pipeline_step_mixin.py +15 -11
  178. junifer/pipeline/py.typed +0 -0
  179. junifer/{markers/tests/test_collection.py → pipeline/tests/test_marker_collection.py} +2 -3
  180. junifer/pipeline/tests/test_pipeline_component_registry.py +200 -0
  181. junifer/pipeline/tests/test_pipeline_step_mixin.py +36 -37
  182. junifer/pipeline/tests/test_update_meta_mixin.py +4 -4
  183. junifer/pipeline/tests/test_workdir_manager.py +43 -0
  184. junifer/pipeline/update_meta_mixin.py +21 -17
  185. junifer/pipeline/utils.py +6 -6
  186. junifer/pipeline/workdir_manager.py +19 -5
  187. junifer/preprocess/__init__.py +2 -10
  188. junifer/preprocess/__init__.pyi +11 -0
  189. junifer/preprocess/base.py +10 -10
  190. junifer/preprocess/confounds/__init__.py +2 -2
  191. junifer/preprocess/confounds/__init__.pyi +3 -0
  192. junifer/preprocess/confounds/fmriprep_confound_remover.py +243 -64
  193. junifer/preprocess/confounds/py.typed +0 -0
  194. junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +121 -14
  195. junifer/preprocess/py.typed +0 -0
  196. junifer/preprocess/smoothing/__init__.py +2 -2
  197. junifer/preprocess/smoothing/__init__.pyi +3 -0
  198. junifer/preprocess/smoothing/_afni_smoothing.py +40 -40
  199. junifer/preprocess/smoothing/_fsl_smoothing.py +22 -32
  200. junifer/preprocess/smoothing/_nilearn_smoothing.py +35 -14
  201. junifer/preprocess/smoothing/py.typed +0 -0
  202. junifer/preprocess/smoothing/smoothing.py +11 -13
  203. junifer/preprocess/warping/__init__.py +2 -2
  204. junifer/preprocess/warping/__init__.pyi +3 -0
  205. junifer/preprocess/warping/_ants_warper.py +136 -32
  206. junifer/preprocess/warping/_fsl_warper.py +73 -22
  207. junifer/preprocess/warping/py.typed +0 -0
  208. junifer/preprocess/warping/space_warper.py +39 -11
  209. junifer/preprocess/warping/tests/test_space_warper.py +5 -9
  210. junifer/py.typed +0 -0
  211. junifer/stats.py +5 -5
  212. junifer/storage/__init__.py +2 -10
  213. junifer/storage/__init__.pyi +11 -0
  214. junifer/storage/base.py +47 -13
  215. junifer/storage/hdf5.py +95 -33
  216. junifer/storage/pandas_base.py +12 -11
  217. junifer/storage/py.typed +0 -0
  218. junifer/storage/sqlite.py +11 -11
  219. junifer/storage/tests/test_hdf5.py +86 -4
  220. junifer/storage/tests/test_sqlite.py +2 -2
  221. junifer/storage/tests/test_storage_base.py +5 -2
  222. junifer/storage/tests/test_utils.py +33 -7
  223. junifer/storage/utils.py +95 -9
  224. junifer/testing/__init__.py +2 -3
  225. junifer/testing/__init__.pyi +4 -0
  226. junifer/testing/datagrabbers.py +10 -11
  227. junifer/testing/py.typed +0 -0
  228. junifer/testing/registry.py +4 -7
  229. junifer/testing/tests/test_testing_registry.py +9 -17
  230. junifer/tests/test_stats.py +2 -2
  231. junifer/typing/__init__.py +9 -0
  232. junifer/typing/__init__.pyi +31 -0
  233. junifer/typing/_typing.py +68 -0
  234. junifer/utils/__init__.py +2 -12
  235. junifer/utils/__init__.pyi +18 -0
  236. junifer/utils/_config.py +110 -0
  237. junifer/utils/_yaml.py +16 -0
  238. junifer/utils/helpers.py +6 -6
  239. junifer/utils/logging.py +117 -8
  240. junifer/utils/py.typed +0 -0
  241. junifer/{pipeline → utils}/singleton.py +19 -14
  242. junifer/utils/tests/test_config.py +59 -0
  243. {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info}/METADATA +43 -38
  244. junifer-0.0.6.dist-info/RECORD +350 -0
  245. {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info}/WHEEL +1 -1
  246. junifer-0.0.6.dist-info/entry_points.txt +2 -0
  247. junifer/api/parser.py +0 -118
  248. junifer/data/coordinates.py +0 -408
  249. junifer/data/masks.py +0 -670
  250. junifer/data/parcellations.py +0 -1828
  251. junifer/pipeline/registry.py +0 -177
  252. junifer/pipeline/tests/test_registry.py +0 -150
  253. junifer-0.0.5.dev242.dist-info/RECORD +0 -275
  254. junifer-0.0.5.dev242.dist-info/entry_points.txt +0 -2
  255. /junifer/{api → cli}/tests/data/gmd_mean.yaml +0 -0
  256. /junifer/{api → cli}/tests/data/gmd_mean_htcondor.yaml +0 -0
  257. /junifer/{api → cli}/tests/data/partly_cloudy_agg_mean_tian.yml +0 -0
  258. /junifer/data/{VOIs → coordinates/VOIs}/meta/AutobiographicalMemory_VOIs.txt +0 -0
  259. /junifer/data/{VOIs → coordinates/VOIs}/meta/CogAC_VOIs.txt +0 -0
  260. /junifer/data/{VOIs → coordinates/VOIs}/meta/CogAR_VOIs.txt +0 -0
  261. /junifer/data/{VOIs → coordinates/VOIs}/meta/DMNBuckner_VOIs.txt +0 -0
  262. /junifer/data/{VOIs → coordinates/VOIs}/meta/Dosenbach2010_MNI_VOIs.txt +0 -0
  263. /junifer/data/{VOIs → coordinates/VOIs}/meta/Empathy_VOIs.txt +0 -0
  264. /junifer/data/{VOIs → coordinates/VOIs}/meta/Motor_VOIs.txt +0 -0
  265. /junifer/data/{VOIs → coordinates/VOIs}/meta/MultiTask_VOIs.txt +0 -0
  266. /junifer/data/{VOIs → coordinates/VOIs}/meta/PhysioStress_VOIs.txt +0 -0
  267. /junifer/data/{VOIs → coordinates/VOIs}/meta/Power2011_MNI_VOIs.txt +0 -0
  268. /junifer/data/{VOIs → coordinates/VOIs}/meta/Power2013_MNI_VOIs.tsv +0 -0
  269. /junifer/data/{VOIs → coordinates/VOIs}/meta/Rew_VOIs.txt +0 -0
  270. /junifer/data/{VOIs → coordinates/VOIs}/meta/Somatosensory_VOIs.txt +0 -0
  271. /junifer/data/{VOIs → coordinates/VOIs}/meta/ToM_VOIs.txt +0 -0
  272. /junifer/data/{VOIs → coordinates/VOIs}/meta/VigAtt_VOIs.txt +0 -0
  273. /junifer/data/{VOIs → coordinates/VOIs}/meta/WM_VOIs.txt +0 -0
  274. /junifer/data/{VOIs → coordinates/VOIs}/meta/eMDN_VOIs.txt +0 -0
  275. /junifer/data/{VOIs → coordinates/VOIs}/meta/eSAD_VOIs.txt +0 -0
  276. /junifer/data/{VOIs → coordinates/VOIs}/meta/extDMN_VOIs.txt +0 -0
  277. {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info/licenses}/AUTHORS.rst +0 -0
  278. {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info/licenses}/LICENSE.md +0 -0
  279. {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info}/top_level.txt +0 -0
@@ -6,10 +6,6 @@
6
6
  from typing import (
7
7
  Any,
8
8
  ClassVar,
9
- Dict,
10
- List,
11
- Set,
12
- Union,
13
9
  )
14
10
 
15
11
  import nibabel as nib
@@ -17,7 +13,8 @@ import numpy as np
17
13
 
18
14
  from ...data import get_template, get_xfm
19
15
  from ...pipeline import WorkDirManager
20
- from ...utils import logger, run_ext_cmd
16
+ from ...typing import Dependencies, ExternalDependencies
17
+ from ...utils import logger, raise_error, run_ext_cmd
21
18
 
22
19
 
23
20
  __all__ = ["ANTsWarper"]
@@ -31,21 +28,21 @@ class ANTsWarper:
31
28
 
32
29
  """
33
30
 
34
- _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [
31
+ _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [
35
32
  {
36
33
  "name": "ants",
37
34
  "commands": ["ResampleImage", "antsApplyTransforms"],
38
35
  },
39
36
  ]
40
37
 
41
- _DEPENDENCIES: ClassVar[Set[str]] = {"numpy", "nibabel"}
38
+ _DEPENDENCIES: ClassVar[Dependencies] = {"numpy", "nibabel"}
42
39
 
43
40
  def preprocess(
44
41
  self,
45
- input: Dict[str, Any],
46
- extra_input: Dict[str, Any],
42
+ input: dict[str, Any],
43
+ extra_input: dict[str, Any],
47
44
  reference: str,
48
- ) -> Dict[str, Any]:
45
+ ) -> dict[str, Any]:
49
46
  """Preprocess using ANTs.
50
47
 
51
48
  Parameters
@@ -61,9 +58,12 @@ class ANTsWarper:
61
58
  Returns
62
59
  -------
63
60
  dict
64
- The ``input`` dictionary with modified ``data`` and ``space`` key
65
- values and new ``reference_path`` key whose value points to the
66
- reference file used for warping.
61
+ The ``input`` dictionary with updated values.
62
+
63
+ Raises
64
+ ------
65
+ RuntimeError
66
+ If warp file path could not be found in ``extra_input``.
67
67
 
68
68
  """
69
69
  # Create element-specific tempdir for storing post-warping assets
@@ -79,6 +79,17 @@ class ANTsWarper:
79
79
  # resolution
80
80
  resolution = np.min(input["data"].header.get_zooms()[:3])
81
81
 
82
+ # Get warp file path
83
+ warp_file_path = None
84
+ for entry in extra_input["Warp"]:
85
+ if entry["dst"] == "native":
86
+ warp_file_path = entry["path"]
87
+ if warp_file_path is None:
88
+ raise_error(
89
+ klass=RuntimeError,
90
+ msg="Could not find correct warp file path",
91
+ )
92
+
82
93
  # Create a tempfile for resampled reference output
83
94
  resample_image_out_path = (
84
95
  element_tempdir / "resampled_reference.nii.gz"
@@ -97,7 +108,7 @@ class ANTsWarper:
97
108
  run_ext_cmd(name="ResampleImage", cmd=resample_image_cmd)
98
109
 
99
110
  # Create a tempfile for warped output
100
- apply_transforms_out_path = element_tempdir / "output.nii.gz"
111
+ apply_transforms_out_path = element_tempdir / "warped_data.nii.gz"
101
112
  # Set antsApplyTransforms command
102
113
  apply_transforms_cmd = [
103
114
  "antsApplyTransforms",
@@ -107,18 +118,65 @@ class ANTsWarper:
107
118
  f"-i {input['path'].resolve()}",
108
119
  # use resampled reference
109
120
  f"-r {resample_image_out_path.resolve()}",
110
- f"-t {extra_input['Warp']['path'].resolve()}",
121
+ f"-t {warp_file_path.resolve()}",
111
122
  f"-o {apply_transforms_out_path.resolve()}",
112
123
  ]
113
124
  # Call antsApplyTransforms
114
125
  run_ext_cmd(name="antsApplyTransforms", cmd=apply_transforms_cmd)
115
126
 
116
- # Load nifti
117
- input["data"] = nib.load(apply_transforms_out_path)
118
- # Save resampled reference path
119
- input["reference_path"] = resample_image_out_path
120
- # Use reference input's space as warped input's space
121
- input["space"] = extra_input["T1w"]["space"]
127
+ logger.debug("Updating warped data")
128
+ input.update(
129
+ {
130
+ # Update path to sync with "data"
131
+ "path": apply_transforms_out_path,
132
+ # Load nifti
133
+ "data": nib.load(apply_transforms_out_path),
134
+ # Use reference input's space as warped input's space
135
+ "space": extra_input["T1w"]["space"],
136
+ # Save resampled reference path
137
+ "reference": {"path": resample_image_out_path},
138
+ # Keep pre-warp space for further operations
139
+ "prewarp_space": input["space"],
140
+ }
141
+ )
142
+
143
+ # Check for data type's mask and warp if found
144
+ if input.get("mask") is not None:
145
+ # Create a tempfile for warped mask output
146
+ apply_transforms_mask_out_path = (
147
+ element_tempdir / "warped_mask.nii.gz"
148
+ )
149
+ # Set antsApplyTransforms command
150
+ apply_transforms_mask_cmd = [
151
+ "antsApplyTransforms",
152
+ "-d 3",
153
+ "-e 3",
154
+ "-n 'GenericLabel[NearestNeighbor]'",
155
+ f"-i {input['mask']['path'].resolve()}",
156
+ # use resampled reference
157
+ f"-r {input['reference']['path'].resolve()}",
158
+ f"-t {warp_file_path.resolve()}",
159
+ f"-o {apply_transforms_mask_out_path.resolve()}",
160
+ ]
161
+ # Call antsApplyTransforms
162
+ run_ext_cmd(
163
+ name="antsApplyTransforms", cmd=apply_transforms_mask_cmd
164
+ )
165
+
166
+ logger.debug("Updating warped mask data")
167
+ input.update(
168
+ {
169
+ "mask": {
170
+ # Update path to sync with "data"
171
+ "path": apply_transforms_mask_out_path,
172
+ # Load nifti
173
+ "data": nib.load(apply_transforms_mask_out_path),
174
+ # Use reference input's space as warped input
175
+ # mask's space
176
+ "space": extra_input["T1w"]["space"],
177
+ }
178
+ }
179
+ )
122
180
 
123
181
  # Template space warping
124
182
  else:
@@ -131,19 +189,18 @@ class ANTsWarper:
131
189
  # Get template space image
132
190
  template_space_img = get_template(
133
191
  space=reference,
134
- target_data=input,
192
+ target_img=input["data"],
135
193
  extra_input=None,
136
194
  )
137
-
138
- # Create component-scoped tempdir
139
- tempdir = WorkDirManager().get_tempdir(prefix="ants_warper")
140
195
  # Save template
141
- template_space_img_path = tempdir / f"{reference}_T1w.nii.gz"
196
+ template_space_img_path = (
197
+ element_tempdir / f"{reference}_T1w.nii.gz"
198
+ )
142
199
  nib.save(template_space_img, template_space_img_path)
143
200
 
144
201
  # Create a tempfile for warped output
145
202
  warped_output_path = element_tempdir / (
146
- f"data_warped_from_{input['space']}_to_" f"{reference}.nii.gz"
203
+ f"warped_data_from_{input['space']}_to_{reference}.nii.gz"
147
204
  )
148
205
 
149
206
  # Set antsApplyTransforms command
@@ -160,11 +217,58 @@ class ANTsWarper:
160
217
  # Call antsApplyTransforms
161
218
  run_ext_cmd(name="antsApplyTransforms", cmd=apply_transforms_cmd)
162
219
 
163
- # Delete tempdir
164
- WorkDirManager().delete_tempdir(tempdir)
220
+ logger.debug("Updating warped data")
221
+ input.update(
222
+ {
223
+ # Update path to sync with "data"
224
+ "path": warped_output_path,
225
+ # Load nifti
226
+ "data": nib.load(warped_output_path),
227
+ # Update warped input's space
228
+ "space": reference,
229
+ # Save reference path
230
+ "reference": {"path": template_space_img_path},
231
+ # Keep pre-warp space for further operations
232
+ "prewarp_space": input["space"],
233
+ }
234
+ )
235
+
236
+ # Check for data type's mask and warp if found
237
+ if input.get("mask") is not None:
238
+ # Create a tempfile for warped mask output
239
+ apply_transforms_mask_out_path = element_tempdir / (
240
+ f"warped_mask_from_{input['space']}_to_"
241
+ f"{reference}.nii.gz"
242
+ )
243
+ # Set antsApplyTransforms command
244
+ apply_transforms_mask_cmd = [
245
+ "antsApplyTransforms",
246
+ "-d 3",
247
+ "-e 3",
248
+ "-n 'GenericLabel[NearestNeighbor]'",
249
+ f"-i {input['mask']['path'].resolve()}",
250
+ # use resampled reference
251
+ f"-r {input['reference']['path'].resolve()}",
252
+ f"-t {xfm_file_path.resolve()}",
253
+ f"-o {apply_transforms_mask_out_path.resolve()}",
254
+ ]
255
+ # Call antsApplyTransforms
256
+ run_ext_cmd(
257
+ name="antsApplyTransforms", cmd=apply_transforms_mask_cmd
258
+ )
165
259
 
166
- # Modify target data
167
- input["data"] = nib.load(warped_output_path)
168
- input["space"] = reference
260
+ logger.debug("Updating warped mask data")
261
+ input.update(
262
+ {
263
+ "mask": {
264
+ # Update path to sync with "data"
265
+ "path": apply_transforms_mask_out_path,
266
+ # Load nifti
267
+ "data": nib.load(apply_transforms_mask_out_path),
268
+ # Update warped input mask's space
269
+ "space": reference,
270
+ }
271
+ }
272
+ )
169
273
 
170
274
  return input
@@ -6,17 +6,14 @@
6
6
  from typing import (
7
7
  Any,
8
8
  ClassVar,
9
- Dict,
10
- List,
11
- Set,
12
- Union,
13
9
  )
14
10
 
15
11
  import nibabel as nib
16
12
  import numpy as np
17
13
 
18
14
  from ...pipeline import WorkDirManager
19
- from ...utils import logger, run_ext_cmd
15
+ from ...typing import Dependencies, ExternalDependencies
16
+ from ...utils import logger, raise_error, run_ext_cmd
20
17
 
21
18
 
22
19
  __all__ = ["FSLWarper"]
@@ -30,20 +27,20 @@ class FSLWarper:
30
27
 
31
28
  """
32
29
 
33
- _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [
30
+ _EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [
34
31
  {
35
32
  "name": "fsl",
36
33
  "commands": ["flirt", "applywarp"],
37
34
  },
38
35
  ]
39
36
 
40
- _DEPENDENCIES: ClassVar[Set[str]] = {"numpy", "nibabel"}
37
+ _DEPENDENCIES: ClassVar[Dependencies] = {"numpy", "nibabel"}
41
38
 
42
39
  def preprocess(
43
40
  self,
44
- input: Dict[str, Any],
45
- extra_input: Dict[str, Any],
46
- ) -> Dict[str, Any]:
41
+ input: dict[str, Any],
42
+ extra_input: dict[str, Any],
43
+ ) -> dict[str, Any]:
47
44
  """Preprocess using FSL.
48
45
 
49
46
  Parameters
@@ -57,9 +54,12 @@ class FSLWarper:
57
54
  Returns
58
55
  -------
59
56
  dict
60
- The ``input`` dictionary with modified ``data`` and ``space`` key
61
- values and new ``reference_path`` key whose value points to the
62
- reference file used for warping.
57
+ The ``input`` dictionary with updated values.
58
+
59
+ Raises
60
+ ------
61
+ RuntimeError
62
+ If warp file path could not be found in ``extra_input``.
63
63
 
64
64
  """
65
65
  logger.debug("Using FSL for space warping")
@@ -68,6 +68,16 @@ class FSLWarper:
68
68
  # resolution
69
69
  resolution = np.min(input["data"].header.get_zooms()[:3])
70
70
 
71
+ # Get warp file path
72
+ warp_file_path = None
73
+ for entry in extra_input["Warp"]:
74
+ if entry["dst"] == "native":
75
+ warp_file_path = entry["path"]
76
+ if warp_file_path is None:
77
+ raise_error(
78
+ klass=RuntimeError, msg="Could not find correct warp file path"
79
+ )
80
+
71
81
  # Create element-specific tempdir for storing post-warping assets
72
82
  element_tempdir = WorkDirManager().get_element_tempdir(
73
83
  prefix="fsl_warper"
@@ -88,25 +98,66 @@ class FSLWarper:
88
98
  run_ext_cmd(name="flirt", cmd=flirt_cmd)
89
99
 
90
100
  # Create a tempfile for warped output
91
- applywarp_out_path = element_tempdir / "output.nii.gz"
101
+ applywarp_out_path = element_tempdir / "warped_data.nii.gz"
92
102
  # Set applywarp command
93
103
  applywarp_cmd = [
94
104
  "applywarp",
95
105
  "--interp=spline",
96
106
  f"-i {input['path'].resolve()}",
97
- f"-r {flirt_out_path.resolve()}", # use resampled reference
98
- f"-w {extra_input['Warp']['path'].resolve()}",
107
+ # use resampled reference
108
+ f"-r {flirt_out_path.resolve()}",
109
+ f"-w {warp_file_path.resolve()}",
99
110
  f"-o {applywarp_out_path.resolve()}",
100
111
  ]
101
112
  # Call applywarp
102
113
  run_ext_cmd(name="applywarp", cmd=applywarp_cmd)
103
114
 
104
- # Load nifti
105
- input["data"] = nib.load(applywarp_out_path)
106
- # Save resampled reference path
107
- input["reference_path"] = flirt_out_path
115
+ logger.debug("Updating warped data")
116
+ input.update(
117
+ {
118
+ # Update path to sync with "data"
119
+ "path": applywarp_out_path,
120
+ # Load nifti
121
+ "data": nib.load(applywarp_out_path),
122
+ # Use reference input's space as warped input's space
123
+ "space": extra_input["T1w"]["space"],
124
+ # Save resampled reference path
125
+ "reference": {"path": flirt_out_path},
126
+ # Keep pre-warp space for further operations
127
+ "prewarp_space": input["space"],
128
+ }
129
+ )
108
130
 
109
- # Use reference input's space as warped input's space
110
- input["space"] = extra_input["T1w"]["space"]
131
+ # Check for data type's mask and warp if found
132
+ if input.get("mask") is not None:
133
+ # Create a tempfile for warped mask output
134
+ applywarp_mask_out_path = element_tempdir / "warped_mask.nii.gz"
135
+ # Set applywarp command
136
+ applywarp_mask_cmd = [
137
+ "applywarp",
138
+ "--interp=nn",
139
+ f"-i {input['mask']['path'].resolve()}",
140
+ # use resampled reference
141
+ f"-r {input['reference']['path'].resolve()}",
142
+ f"-w {warp_file_path.resolve()}",
143
+ f"-o {applywarp_mask_out_path.resolve()}",
144
+ ]
145
+ # Call applywarp
146
+ run_ext_cmd(name="applywarp", cmd=applywarp_mask_cmd)
147
+
148
+ logger.debug("Updating warped mask data")
149
+ input.update(
150
+ {
151
+ "mask": {
152
+ # Update path to sync with "data"
153
+ "path": applywarp_mask_out_path,
154
+ # Load nifti
155
+ "data": nib.load(applywarp_mask_out_path),
156
+ # Use reference input's space as warped input mask's
157
+ # space
158
+ "space": extra_input["T1w"]["space"],
159
+ }
160
+ }
161
+ )
111
162
 
112
163
  return input
File without changes
@@ -3,11 +3,12 @@
3
3
  # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
4
  # License: AGPL
5
5
 
6
- from typing import Any, ClassVar, Dict, List, Optional, Tuple, Type, Union
6
+ from typing import Any, ClassVar, Optional, Union
7
7
 
8
8
  from templateflow import api as tflow
9
9
 
10
10
  from ...api.decorators import register_preprocessor
11
+ from ...typing import ConditionalDependencies
11
12
  from ...utils import logger, raise_error
12
13
  from ..base import BasePreprocessor
13
14
  from ._ants_warper import ANTsWarper
@@ -23,11 +24,12 @@ class SpaceWarper(BasePreprocessor):
23
24
 
24
25
  Parameters
25
26
  ----------
26
- using : {"fsl", "ants"}
27
+ using : {"fsl", "ants", "auto"}
27
28
  Implementation to use for warping:
28
29
 
29
30
  * "fsl" : Use FSL's ``applywarp``
30
31
  * "ants" : Use ANTs' ``antsApplyTransforms``
32
+ * "auto" : Auto-select tool when ``reference="T1w"``
31
33
 
32
34
  reference : str
33
35
  The data type to use as reference for warping, can be either a data
@@ -46,7 +48,7 @@ class SpaceWarper(BasePreprocessor):
46
48
 
47
49
  """
48
50
 
49
- _CONDITIONAL_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, Type]]]] = [
51
+ _CONDITIONAL_DEPENDENCIES: ClassVar[ConditionalDependencies] = [
50
52
  {
51
53
  "using": "fsl",
52
54
  "depends_on": FSLWarper,
@@ -55,10 +57,14 @@ class SpaceWarper(BasePreprocessor):
55
57
  "using": "ants",
56
58
  "depends_on": ANTsWarper,
57
59
  },
60
+ {
61
+ "using": "auto",
62
+ "depends_on": [FSLWarper, ANTsWarper],
63
+ },
58
64
  ]
59
65
 
60
66
  def __init__(
61
- self, using: str, reference: str, on: Union[List[str], str]
67
+ self, using: str, reference: str, on: Union[list[str], str]
62
68
  ) -> None:
63
69
  """Initialize the class."""
64
70
  # Validate `using` parameter
@@ -88,7 +94,7 @@ class SpaceWarper(BasePreprocessor):
88
94
  else:
89
95
  raise_error(f"Unknown reference: {self.reference}")
90
96
 
91
- def get_valid_inputs(self) -> List[str]:
97
+ def get_valid_inputs(self) -> list[str]:
92
98
  """Get valid data types for input.
93
99
 
94
100
  Returns
@@ -129,9 +135,9 @@ class SpaceWarper(BasePreprocessor):
129
135
 
130
136
  def preprocess(
131
137
  self,
132
- input: Dict[str, Any],
133
- extra_input: Optional[Dict[str, Any]] = None,
134
- ) -> Tuple[Dict[str, Any], Optional[Dict[str, Dict[str, Any]]]]:
138
+ input: dict[str, Any],
139
+ extra_input: Optional[dict[str, Any]] = None,
140
+ ) -> tuple[dict[str, Any], Optional[dict[str, dict[str, Any]]]]:
135
141
  """Preprocess.
136
142
 
137
143
  Parameters
@@ -155,14 +161,16 @@ class SpaceWarper(BasePreprocessor):
155
161
  If ``extra_input`` is None when transforming to native space
156
162
  i.e., using ``"T1w"`` as reference.
157
163
  RuntimeError
158
- If the data is in the correct space and does not require
164
+ If warper could not be found in ``extra_input`` when
165
+ ``using="auto"`` or
166
+ if the data is in the correct space and does not require
159
167
  warping or
160
- if FSL is used for template space warping.
168
+ if FSL is used when ``reference="T1w"``.
161
169
 
162
170
  """
163
171
  logger.info(f"Warping to {self.reference} space using SpaceWarper")
164
172
  # Transform to native space
165
- if self.using in ["fsl", "ants"] and self.reference == "T1w":
173
+ if self.using in ["fsl", "ants", "auto"] and self.reference == "T1w":
166
174
  # Check for extra inputs
167
175
  if extra_input is None:
168
176
  raise_error(
@@ -181,6 +189,26 @@ class SpaceWarper(BasePreprocessor):
181
189
  extra_input=extra_input,
182
190
  reference=self.reference,
183
191
  )
192
+ elif self.using == "auto":
193
+ warper = None
194
+ for entry in extra_input["Warp"]:
195
+ if entry["dst"] == "native":
196
+ warper = entry["warper"]
197
+ if warper is None:
198
+ raise_error(
199
+ klass=RuntimeError, msg="Could not find correct warper"
200
+ )
201
+ if warper == "fsl":
202
+ input = FSLWarper().preprocess(
203
+ input=input,
204
+ extra_input=extra_input,
205
+ )
206
+ elif warper == "ants":
207
+ input = ANTsWarper().preprocess(
208
+ input=input,
209
+ extra_input=extra_input,
210
+ reference=self.reference,
211
+ )
184
212
  # Transform to template space with ANTs possible
185
213
  elif self.using == "ants" and self.reference != "T1w":
186
214
  # Check pre-requirements for space manipulation
@@ -4,7 +4,6 @@
4
4
  # License: AGPL
5
5
 
6
6
  import socket
7
- from typing import TYPE_CHECKING, Tuple, Type
8
7
 
9
8
  import pytest
10
9
  from numpy.testing import assert_array_equal, assert_raises
@@ -14,10 +13,7 @@ from junifer.datareader import DefaultDataReader
14
13
  from junifer.pipeline.utils import _check_ants, _check_fsl
15
14
  from junifer.preprocess import SpaceWarper
16
15
  from junifer.testing.datagrabbers import PartlyCloudyTestingDataGrabber
17
-
18
-
19
- if TYPE_CHECKING:
20
- from junifer.datagrabber import BaseDataGrabber
16
+ from junifer.typing import DataGrabberLike
21
17
 
22
18
 
23
19
  @pytest.mark.parametrize(
@@ -32,7 +28,7 @@ if TYPE_CHECKING:
32
28
  def test_SpaceWarper_errors(
33
29
  using: str,
34
30
  reference: str,
35
- error_type: Type[Exception],
31
+ error_type: type[Exception],
36
32
  error_msg: str,
37
33
  ) -> None:
38
34
  """Test SpaceWarper errors.
@@ -99,7 +95,7 @@ def test_SpaceWarper_errors(
99
95
  reason="only for juseless",
100
96
  )
101
97
  def test_SpaceWarper_native(
102
- datagrabber: "BaseDataGrabber", element: Tuple[str, ...], using: str
98
+ datagrabber: DataGrabberLike, element: tuple[str, ...], using: str
103
99
  ) -> None:
104
100
  """Test SpaceWarper for native space warping.
105
101
 
@@ -162,8 +158,8 @@ def test_SpaceWarper_native(
162
158
  _check_ants() is False, reason="requires ANTs to be in PATH"
163
159
  )
164
160
  def test_SpaceWarper_multi_mni(
165
- datagrabber: "BaseDataGrabber",
166
- element: Tuple[str, ...],
161
+ datagrabber: DataGrabberLike,
162
+ element: tuple[str, ...],
167
163
  space: str,
168
164
  ) -> None:
169
165
  """Test SpaceWarper for MNI space warping.
junifer/py.typed ADDED
File without changes
junifer/stats.py CHANGED
@@ -4,7 +4,7 @@
4
4
  # Synchon Mandal <s.mandal@fz-juelich.de>
5
5
  # License: AGPL
6
6
 
7
- from typing import Any, Callable, Dict, List, Optional
7
+ from typing import Any, Callable, Optional
8
8
 
9
9
  import numpy as np
10
10
  from scipy.stats import mode, trim_mean
@@ -13,11 +13,11 @@ from scipy.stats.mstats import winsorize
13
13
  from .utils import logger, raise_error
14
14
 
15
15
 
16
- __all__ = ["get_aggfunc_by_name", "count", "winsorized_mean", "select"]
16
+ __all__ = ["count", "get_aggfunc_by_name", "select", "winsorized_mean"]
17
17
 
18
18
 
19
19
  def get_aggfunc_by_name(
20
- name: str, func_params: Optional[Dict[str, Any]] = None
20
+ name: str, func_params: Optional[dict[str, Any]] = None
21
21
  ) -> Callable:
22
22
  """Get an aggregation function by its name.
23
23
 
@@ -169,8 +169,8 @@ def winsorized_mean(
169
169
  def select(
170
170
  data: np.ndarray,
171
171
  axis: int = 0,
172
- pick: Optional[List[int]] = None,
173
- drop: Optional[List[int]] = None,
172
+ pick: Optional[list[int]] = None,
173
+ drop: Optional[list[int]] = None,
174
174
  ) -> np.ndarray:
175
175
  """Select a subset of the data.
176
176
 
@@ -4,15 +4,7 @@
4
4
  # Synchon Mandal <s.mandal@fz-juelich.de>
5
5
  # License: AGPL
6
6
 
7
- from .base import BaseFeatureStorage
8
- from .pandas_base import PandasBaseFeatureStorage
9
- from .sqlite import SQLiteFeatureStorage
10
- from .hdf5 import HDF5FeatureStorage
7
+ import lazy_loader as lazy
11
8
 
12
9
 
13
- __all__ = [
14
- "BaseFeatureStorage",
15
- "PandasBaseFeatureStorage",
16
- "SQLiteFeatureStorage",
17
- "HDF5FeatureStorage",
18
- ]
10
+ __getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
@@ -0,0 +1,11 @@
1
+ __all__ = [
2
+ "BaseFeatureStorage",
3
+ "PandasBaseFeatureStorage",
4
+ "SQLiteFeatureStorage",
5
+ "HDF5FeatureStorage",
6
+ ]
7
+
8
+ from .base import BaseFeatureStorage
9
+ from .pandas_base import PandasBaseFeatureStorage
10
+ from .sqlite import SQLiteFeatureStorage
11
+ from .hdf5 import HDF5FeatureStorage