junifer 0.0.6.dev227__py3-none-any.whl → 0.0.6.dev252__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 (131) hide show
  1. junifer/_version.py +2 -2
  2. junifer/api/decorators.py +1 -2
  3. junifer/api/functions.py +18 -18
  4. junifer/api/queue_context/gnu_parallel_local_adapter.py +4 -4
  5. junifer/api/queue_context/htcondor_adapter.py +4 -4
  6. junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +3 -3
  7. junifer/api/queue_context/tests/test_htcondor_adapter.py +3 -3
  8. junifer/api/tests/test_functions.py +32 -32
  9. junifer/cli/cli.py +3 -3
  10. junifer/cli/parser.py +4 -4
  11. junifer/cli/tests/test_cli.py +5 -5
  12. junifer/cli/utils.py +5 -6
  13. junifer/configs/juseless/datagrabbers/ixi_vbm.py +2 -2
  14. junifer/configs/juseless/datagrabbers/tests/test_ucla.py +2 -2
  15. junifer/configs/juseless/datagrabbers/ucla.py +4 -4
  16. junifer/data/_dispatch.py +11 -14
  17. junifer/data/coordinates/_ants_coordinates_warper.py +6 -8
  18. junifer/data/coordinates/_coordinates.py +34 -21
  19. junifer/data/coordinates/_fsl_coordinates_warper.py +6 -8
  20. junifer/data/masks/_ants_mask_warper.py +18 -11
  21. junifer/data/masks/_fsl_mask_warper.py +6 -8
  22. junifer/data/masks/_masks.py +27 -34
  23. junifer/data/masks/tests/test_masks.py +4 -4
  24. junifer/data/parcellations/_ants_parcellation_warper.py +18 -11
  25. junifer/data/parcellations/_fsl_parcellation_warper.py +6 -8
  26. junifer/data/parcellations/_parcellations.py +39 -43
  27. junifer/data/parcellations/tests/test_parcellations.py +1 -2
  28. junifer/data/pipeline_data_registry_base.py +3 -2
  29. junifer/data/template_spaces.py +3 -3
  30. junifer/data/tests/test_data_utils.py +1 -2
  31. junifer/data/utils.py +69 -4
  32. junifer/datagrabber/aomic/id1000.py +24 -11
  33. junifer/datagrabber/aomic/piop1.py +27 -14
  34. junifer/datagrabber/aomic/piop2.py +27 -14
  35. junifer/datagrabber/aomic/tests/test_id1000.py +3 -3
  36. junifer/datagrabber/aomic/tests/test_piop1.py +4 -4
  37. junifer/datagrabber/aomic/tests/test_piop2.py +4 -4
  38. junifer/datagrabber/base.py +18 -12
  39. junifer/datagrabber/datalad_base.py +18 -11
  40. junifer/datagrabber/dmcc13_benchmark.py +31 -18
  41. junifer/datagrabber/hcp1200/datalad_hcp1200.py +3 -3
  42. junifer/datagrabber/hcp1200/hcp1200.py +26 -15
  43. junifer/datagrabber/hcp1200/tests/test_hcp1200.py +2 -1
  44. junifer/datagrabber/multiple.py +7 -7
  45. junifer/datagrabber/pattern.py +75 -45
  46. junifer/datagrabber/pattern_validation_mixin.py +204 -94
  47. junifer/datagrabber/tests/test_datalad_base.py +7 -8
  48. junifer/datagrabber/tests/test_dmcc13_benchmark.py +28 -11
  49. junifer/datagrabber/tests/test_pattern_validation_mixin.py +6 -6
  50. junifer/datareader/default.py +6 -6
  51. junifer/external/nilearn/junifer_connectivity_measure.py +2 -2
  52. junifer/external/nilearn/junifer_nifti_spheres_masker.py +4 -4
  53. junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +15 -15
  54. junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +2 -3
  55. junifer/markers/base.py +8 -8
  56. junifer/markers/brainprint.py +7 -9
  57. junifer/markers/complexity/complexity_base.py +6 -8
  58. junifer/markers/complexity/hurst_exponent.py +5 -5
  59. junifer/markers/complexity/multiscale_entropy_auc.py +5 -5
  60. junifer/markers/complexity/perm_entropy.py +5 -5
  61. junifer/markers/complexity/range_entropy.py +5 -5
  62. junifer/markers/complexity/range_entropy_auc.py +5 -5
  63. junifer/markers/complexity/sample_entropy.py +5 -5
  64. junifer/markers/complexity/weighted_perm_entropy.py +5 -5
  65. junifer/markers/ets_rss.py +7 -7
  66. junifer/markers/falff/_afni_falff.py +1 -2
  67. junifer/markers/falff/_junifer_falff.py +1 -2
  68. junifer/markers/falff/falff_base.py +2 -4
  69. junifer/markers/falff/falff_parcels.py +7 -7
  70. junifer/markers/falff/falff_spheres.py +6 -6
  71. junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +6 -6
  72. junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +7 -7
  73. junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +6 -6
  74. junifer/markers/functional_connectivity/functional_connectivity_base.py +10 -10
  75. junifer/markers/functional_connectivity/functional_connectivity_parcels.py +7 -7
  76. junifer/markers/functional_connectivity/functional_connectivity_spheres.py +6 -6
  77. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +1 -2
  78. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +1 -2
  79. junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +3 -3
  80. junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +3 -3
  81. junifer/markers/parcel_aggregation.py +8 -8
  82. junifer/markers/reho/_afni_reho.py +1 -2
  83. junifer/markers/reho/_junifer_reho.py +1 -2
  84. junifer/markers/reho/reho_base.py +2 -4
  85. junifer/markers/reho/reho_parcels.py +8 -8
  86. junifer/markers/reho/reho_spheres.py +7 -7
  87. junifer/markers/sphere_aggregation.py +8 -8
  88. junifer/markers/temporal_snr/temporal_snr_base.py +8 -8
  89. junifer/markers/temporal_snr/temporal_snr_parcels.py +6 -6
  90. junifer/markers/temporal_snr/temporal_snr_spheres.py +5 -5
  91. junifer/markers/utils.py +3 -3
  92. junifer/onthefly/_brainprint.py +2 -2
  93. junifer/onthefly/read_transform.py +3 -3
  94. junifer/pipeline/marker_collection.py +4 -4
  95. junifer/pipeline/pipeline_component_registry.py +5 -4
  96. junifer/pipeline/pipeline_step_mixin.py +15 -11
  97. junifer/pipeline/tests/test_pipeline_component_registry.py +2 -3
  98. junifer/pipeline/tests/test_pipeline_step_mixin.py +19 -19
  99. junifer/pipeline/tests/test_update_meta_mixin.py +4 -4
  100. junifer/pipeline/update_meta_mixin.py +21 -17
  101. junifer/pipeline/utils.py +5 -5
  102. junifer/preprocess/base.py +10 -10
  103. junifer/preprocess/confounds/fmriprep_confound_remover.py +11 -14
  104. junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +1 -2
  105. junifer/preprocess/smoothing/smoothing.py +7 -7
  106. junifer/preprocess/warping/_ants_warper.py +26 -6
  107. junifer/preprocess/warping/_fsl_warper.py +22 -7
  108. junifer/preprocess/warping/space_warper.py +37 -10
  109. junifer/preprocess/warping/tests/test_space_warper.py +3 -4
  110. junifer/stats.py +4 -4
  111. junifer/storage/base.py +14 -13
  112. junifer/storage/hdf5.py +21 -20
  113. junifer/storage/pandas_base.py +12 -11
  114. junifer/storage/sqlite.py +11 -11
  115. junifer/storage/tests/test_hdf5.py +1 -2
  116. junifer/storage/tests/test_sqlite.py +2 -2
  117. junifer/storage/tests/test_utils.py +8 -7
  118. junifer/storage/utils.py +7 -7
  119. junifer/testing/datagrabbers.py +9 -10
  120. junifer/tests/test_stats.py +2 -2
  121. junifer/typing/_typing.py +6 -9
  122. junifer/utils/helpers.py +2 -3
  123. junifer/utils/logging.py +5 -5
  124. junifer/utils/singleton.py +3 -3
  125. {junifer-0.0.6.dev227.dist-info → junifer-0.0.6.dev252.dist-info}/METADATA +2 -2
  126. {junifer-0.0.6.dev227.dist-info → junifer-0.0.6.dev252.dist-info}/RECORD +131 -131
  127. {junifer-0.0.6.dev227.dist-info → junifer-0.0.6.dev252.dist-info}/WHEEL +1 -1
  128. {junifer-0.0.6.dev227.dist-info → junifer-0.0.6.dev252.dist-info}/AUTHORS.rst +0 -0
  129. {junifer-0.0.6.dev227.dist-info → junifer-0.0.6.dev252.dist-info}/LICENSE.md +0 -0
  130. {junifer-0.0.6.dev227.dist-info → junifer-0.0.6.dev252.dist-info}/entry_points.txt +0 -0
  131. {junifer-0.0.6.dev227.dist-info → junifer-0.0.6.dev252.dist-info}/top_level.txt +0 -0
junifer/data/_dispatch.py CHANGED
@@ -8,10 +8,7 @@ from typing import (
8
8
  TYPE_CHECKING,
9
9
  Any,
10
10
  Callable,
11
- Dict,
12
- List,
13
11
  Optional,
14
- Tuple,
15
12
  Union,
16
13
  )
17
14
 
@@ -40,15 +37,15 @@ def get_data(
40
37
  kind: str,
41
38
  names: Union[
42
39
  str, # coordinates, parcellation, mask
43
- List[str], # parcellation, mask
44
- Dict, # mask
45
- List[Dict], # mask
40
+ list[str], # parcellation, mask
41
+ dict, # mask
42
+ list[dict], # mask
46
43
  ],
47
- target_data: Dict[str, Any],
48
- extra_input: Optional[Dict[str, Any]] = None,
44
+ target_data: dict[str, Any],
45
+ extra_input: Optional[dict[str, Any]] = None,
49
46
  ) -> Union[
50
- Tuple[ArrayLike, List[str]], # coordinates
51
- Tuple["Nifti1Image", List[str]], # parcellation
47
+ tuple[ArrayLike, list[str]], # coordinates
48
+ tuple["Nifti1Image", list[str]], # parcellation
52
49
  "Nifti1Image", # mask
53
50
  ]:
54
51
  """Get tailored ``kind`` for ``target_data``.
@@ -102,7 +99,7 @@ def get_data(
102
99
  raise_error(f"Unknown data kind: {kind}")
103
100
 
104
101
 
105
- def list_data(kind: str) -> List[str]:
102
+ def list_data(kind: str) -> list[str]:
106
103
  """List available data for ``kind``.
107
104
 
108
105
  Parameters
@@ -137,9 +134,9 @@ def load_data(
137
134
  name: str,
138
135
  **kwargs,
139
136
  ) -> Union[
140
- Tuple[ArrayLike, List[str], str], # coordinates
141
- Tuple[Optional["Nifti1Image"], List[str], Path, str], # parcellation
142
- Tuple[
137
+ tuple[ArrayLike, list[str], str], # coordinates
138
+ tuple[Optional["Nifti1Image"], list[str], Path, str], # parcellation
139
+ tuple[
143
140
  Optional[Union["Nifti1Image", Callable]], Optional[Path], str
144
141
  ], # mask
145
142
  ]:
@@ -3,7 +3,7 @@
3
3
  # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
4
  # License: AGPL
5
5
 
6
- from typing import Any, Dict
6
+ from typing import Any
7
7
 
8
8
  import numpy as np
9
9
  from numpy.typing import ArrayLike
@@ -25,8 +25,8 @@ class ANTsCoordinatesWarper:
25
25
  def warp(
26
26
  self,
27
27
  seeds: ArrayLike,
28
- target_data: Dict[str, Any],
29
- extra_input: Dict[str, Any],
28
+ target_data: dict[str, Any],
29
+ warp_data: dict[str, Any],
30
30
  ) -> ArrayLike:
31
31
  """Warp ``seeds`` to correct space.
32
32
 
@@ -37,10 +37,8 @@ class ANTsCoordinatesWarper:
37
37
  target_data : dict
38
38
  The corresponding item of the data object to which the coordinates
39
39
  will be applied.
40
- extra_input : dict, optional
41
- The other fields in the data object. Useful for accessing other
42
- data kinds that needs to be used in the computation of coordinates
43
- (default None).
40
+ warp_data : dict or None
41
+ The warp data item of the data object.
44
42
 
45
43
  Returns
46
44
  -------
@@ -79,7 +77,7 @@ class ANTsCoordinatesWarper:
79
77
  "-f 0",
80
78
  f"-i {pretransform_coordinates_path.resolve()}",
81
79
  f"-o {transformed_coords_path.resolve()}",
82
- f"-t {extra_input['Warp']['path'].resolve()};",
80
+ f"-t {warp_data['path'].resolve()}",
83
81
  ]
84
82
  # Call antsApplyTransformsToPoints
85
83
  run_ext_cmd(
@@ -5,7 +5,7 @@
5
5
  # License: AGPL
6
6
 
7
7
  from pathlib import Path
8
- from typing import Any, Dict, List, Optional, Tuple
8
+ from typing import Any, Optional
9
9
 
10
10
  import numpy as np
11
11
  import pandas as pd
@@ -14,6 +14,7 @@ from numpy.typing import ArrayLike
14
14
  from ...utils import logger, raise_error
15
15
  from ...utils.singleton import Singleton
16
16
  from ..pipeline_data_registry_base import BasePipelineDataRegistry
17
+ from ..utils import get_native_warper
17
18
  from ._ants_coordinates_warper import ANTsCoordinatesWarper
18
19
  from ._fsl_coordinates_warper import FSLCoordinatesWarper
19
20
 
@@ -134,7 +135,7 @@ class CoordinatesRegistry(BasePipelineDataRegistry, metaclass=Singleton):
134
135
  self,
135
136
  name: str,
136
137
  coordinates: ArrayLike,
137
- voi_names: List[str],
138
+ voi_names: list[str],
138
139
  space: str,
139
140
  overwrite: Optional[bool] = False,
140
141
  ) -> None:
@@ -235,7 +236,7 @@ class CoordinatesRegistry(BasePipelineDataRegistry, metaclass=Singleton):
235
236
  # Update registry
236
237
  _ = self._registry.pop(name)
237
238
 
238
- def load(self, name: str) -> Tuple[ArrayLike, List[str], str]:
239
+ def load(self, name: str) -> tuple[ArrayLike, list[str], str]:
239
240
  """Load coordinates.
240
241
 
241
242
  Parameters
@@ -284,9 +285,9 @@ class CoordinatesRegistry(BasePipelineDataRegistry, metaclass=Singleton):
284
285
  def get(
285
286
  self,
286
287
  coords: str,
287
- target_data: Dict[str, Any],
288
- extra_input: Optional[Dict[str, Any]] = None,
289
- ) -> Tuple[ArrayLike, List[str]]:
288
+ target_data: dict[str, Any],
289
+ extra_input: Optional[dict[str, Any]] = None,
290
+ ) -> tuple[ArrayLike, list[str]]:
290
291
  """Get coordinates, tailored for the target data.
291
292
 
292
293
  Parameters
@@ -311,7 +312,8 @@ class CoordinatesRegistry(BasePipelineDataRegistry, metaclass=Singleton):
311
312
  Raises
312
313
  ------
313
314
  RuntimeError
314
- If warp / transformation file extension is not ".mat" or ".h5".
315
+ If warping specification required for warping using ANTs, is not
316
+ found.
315
317
  ValueError
316
318
  If ``extra_input`` is None when ``target_data``'s space is native.
317
319
 
@@ -329,27 +331,38 @@ class CoordinatesRegistry(BasePipelineDataRegistry, metaclass=Singleton):
329
331
  f"{target_data['space']} space for further computation."
330
332
  )
331
333
 
332
- # Check for warp file type to use correct tool
333
- warp_file_ext = extra_input["Warp"]["path"].suffix
334
- if warp_file_ext == ".mat":
334
+ # Get native space warper spec
335
+ warper_spec = get_native_warper(
336
+ target_data=target_data,
337
+ other_data=extra_input,
338
+ )
339
+ # Conditional for warping tool implementation
340
+ if warper_spec["warper"] == "fsl":
335
341
  seeds = FSLCoordinatesWarper().warp(
336
342
  seeds=seeds,
337
343
  target_data=target_data,
338
- extra_input=extra_input,
344
+ warp_data=warper_spec,
345
+ )
346
+ elif warper_spec["warper"] == "ants":
347
+ # Requires the inverse warp
348
+ inverse_warper_spec = get_native_warper(
349
+ target_data=target_data,
350
+ other_data=extra_input,
351
+ inverse=True,
339
352
  )
340
- elif warp_file_ext == ".h5":
353
+ # Check warper
354
+ if inverse_warper_spec["warper"] != "ants":
355
+ raise_error(
356
+ klass=RuntimeError,
357
+ msg=(
358
+ "Warping specification mismatch for native space "
359
+ "warping of coordinates using ANTs."
360
+ ),
361
+ )
341
362
  seeds = ANTsCoordinatesWarper().warp(
342
363
  seeds=seeds,
343
364
  target_data=target_data,
344
- extra_input=extra_input,
345
- )
346
- else:
347
- raise_error(
348
- msg=(
349
- "Unknown warp / transformation file extension: "
350
- f"{warp_file_ext}"
351
- ),
352
- klass=RuntimeError,
365
+ warp_data=warper_spec,
353
366
  )
354
367
 
355
368
  return seeds, labels
@@ -3,7 +3,7 @@
3
3
  # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
4
  # License: AGPL
5
5
 
6
- from typing import Any, Dict
6
+ from typing import Any
7
7
 
8
8
  import numpy as np
9
9
  from numpy.typing import ArrayLike
@@ -25,8 +25,8 @@ class FSLCoordinatesWarper:
25
25
  def warp(
26
26
  self,
27
27
  seeds: ArrayLike,
28
- target_data: Dict[str, Any],
29
- extra_input: Dict[str, Any],
28
+ target_data: dict[str, Any],
29
+ warp_data: dict[str, Any],
30
30
  ) -> ArrayLike:
31
31
  """Warp ``seeds`` to correct space.
32
32
 
@@ -37,10 +37,8 @@ class FSLCoordinatesWarper:
37
37
  target_data : dict
38
38
  The corresponding item of the data object to which the coordinates
39
39
  will be applied.
40
- extra_input : dict, optional
41
- The other fields in the data object. Useful for accessing other
42
- data kinds that needs to be used in the computation of coordinates
43
- (default None).
40
+ warp_data : dict
41
+ The warp data item of the data object.
44
42
 
45
43
  Returns
46
44
  -------
@@ -72,7 +70,7 @@ class FSLCoordinatesWarper:
72
70
  "| img2imgcoord -mm",
73
71
  f"-src {target_data['path'].resolve()}",
74
72
  f"-dest {target_data['reference_path'].resolve()}",
75
- f"-warp {extra_input['Warp']['path'].resolve()}",
73
+ f"-warp {warp_data['path'].resolve()}",
76
74
  f"> {transformed_coords_path.resolve()};",
77
75
  f"sed -i 1d {transformed_coords_path.resolve()}",
78
76
  ]
@@ -4,12 +4,12 @@
4
4
  # License: AGPL
5
5
 
6
6
  import uuid
7
- from typing import TYPE_CHECKING, Any, Dict, Optional
7
+ from typing import TYPE_CHECKING, Any, Optional
8
8
 
9
9
  import nibabel as nib
10
10
 
11
11
  from ...pipeline import WorkDirManager
12
- from ...utils import logger, run_ext_cmd
12
+ from ...utils import logger, raise_error, run_ext_cmd
13
13
  from ..template_spaces import get_template, get_xfm
14
14
 
15
15
 
@@ -33,8 +33,8 @@ class ANTsMaskWarper:
33
33
  mask_img: "Nifti1Image",
34
34
  src: str,
35
35
  dst: str,
36
- target_data: Dict[str, Any],
37
- extra_input: Optional[Dict[str, Any]] = None,
36
+ target_data: dict[str, Any],
37
+ warp_data: Optional[dict[str, Any]],
38
38
  ) -> "Nifti1Image":
39
39
  """Warp ``mask_img`` to correct space.
40
40
 
@@ -55,17 +55,20 @@ class ANTsMaskWarper:
55
55
  target_data : dict
56
56
  The corresponding item of the data object to which the mask
57
57
  will be applied.
58
- extra_input : dict, optional
59
- The other fields in the data object. Useful for accessing other
60
- data kinds that needs to be used in the computation of mask
61
- (default None).
62
-
58
+ warp_data : dict or None
59
+ The warp data item of the data object. The value is unused if
60
+ ``dst!="T1w"``.
63
61
 
64
62
  Returns
65
63
  -------
66
64
  nibabel.nifti1.Nifti1Image
67
65
  The transformed mask image.
68
66
 
67
+ Raises
68
+ ------
69
+ RuntimeError
70
+ If ``warp_data`` is None when ``dst="T1w"``.
71
+
69
72
  """
70
73
  # Create element-scoped tempdir so that warped mask is
71
74
  # available later as nibabel stores file path reference for
@@ -80,7 +83,11 @@ class ANTsMaskWarper:
80
83
  )
81
84
 
82
85
  # Native space warping
83
- if dst == "T1w":
86
+ if dst == "native":
87
+ # Warp data check
88
+ if warp_data is None:
89
+ raise_error("No `warp_data` provided")
90
+
84
91
  logger.debug("Using ANTs for mask transformation")
85
92
 
86
93
  # Save existing mask image to a tempfile
@@ -98,7 +105,7 @@ class ANTsMaskWarper:
98
105
  f"-i {prewarp_mask_path.resolve()}",
99
106
  # use resampled reference
100
107
  f"-r {target_data['reference_path'].resolve()}",
101
- f"-t {extra_input['Warp']['path'].resolve()}",
108
+ f"-t {warp_data['path'].resolve()}",
102
109
  f"-o {warped_mask_path.resolve()}",
103
110
  ]
104
111
  # Call antsApplyTransforms
@@ -4,7 +4,7 @@
4
4
  # License: AGPL
5
5
 
6
6
  import uuid
7
- from typing import TYPE_CHECKING, Any, Dict
7
+ from typing import TYPE_CHECKING, Any
8
8
 
9
9
  import nibabel as nib
10
10
 
@@ -30,8 +30,8 @@ class FSLMaskWarper:
30
30
  self,
31
31
  mask_name: str,
32
32
  mask_img: "Nifti1Image",
33
- target_data: Dict[str, Any],
34
- extra_input: Dict[str, Any],
33
+ target_data: dict[str, Any],
34
+ warp_data: dict[str, Any],
35
35
  ) -> "Nifti1Image":
36
36
  """Warp ``mask_img`` to correct space.
37
37
 
@@ -44,10 +44,8 @@ class FSLMaskWarper:
44
44
  target_data : dict
45
45
  The corresponding item of the data object to which the mask
46
46
  will be applied.
47
- extra_input : dict, optional
48
- The other fields in the data object. Useful for accessing other
49
- data kinds that needs to be used in the computation of mask
50
- (default None).
47
+ warp_data : dict
48
+ The warp data item of the data object.
51
49
 
52
50
  Returns
53
51
  -------
@@ -77,7 +75,7 @@ class FSLMaskWarper:
77
75
  f"-i {prewarp_mask_path.resolve()}",
78
76
  # use resampled reference
79
77
  f"-r {target_data['reference_path'].resolve()}",
80
- f"-w {extra_input['Warp']['path'].resolve()}",
78
+ f"-w {warp_data['path'].resolve()}",
81
79
  f"-o {warped_mask_path.resolve()}",
82
80
  ]
83
81
  # Call applywarp
@@ -9,10 +9,7 @@ from typing import (
9
9
  TYPE_CHECKING,
10
10
  Any,
11
11
  Callable,
12
- Dict,
13
- List,
14
12
  Optional,
15
- Tuple,
16
13
  Union,
17
14
  )
18
15
 
@@ -29,7 +26,7 @@ from ...utils import logger, raise_error
29
26
  from ...utils.singleton import Singleton
30
27
  from ..pipeline_data_registry_base import BasePipelineDataRegistry
31
28
  from ..template_spaces import get_template
32
- from ..utils import closest_resolution
29
+ from ..utils import closest_resolution, get_native_warper
33
30
  from ._ants_mask_warper import ANTsMaskWarper
34
31
  from ._fsl_mask_warper import FSLMaskWarper
35
32
 
@@ -46,8 +43,8 @@ _masks_path = Path(__file__).parent
46
43
 
47
44
 
48
45
  def compute_brain_mask(
49
- target_data: Dict[str, Any],
50
- extra_input: Optional[Dict[str, Any]] = None,
46
+ target_data: dict[str, Any],
47
+ extra_input: Optional[dict[str, Any]] = None,
51
48
  mask_type: str = "brain",
52
49
  threshold: float = 0.5,
53
50
  ) -> "Nifti1Image":
@@ -105,14 +102,16 @@ def compute_brain_mask(
105
102
  "data type to infer target template space."
106
103
  )
107
104
  # Set target standard space to warp file space source
108
- target_std_space = extra_input["Warp"]["src"]
105
+ for entry in extra_input["Warp"]:
106
+ if entry["dst"] == "native":
107
+ target_std_space = entry["src"]
109
108
 
110
109
  # Fetch template in closest resolution
111
110
  template = get_template(
112
111
  space=target_std_space,
113
112
  target_data=target_data,
114
113
  extra_input=extra_input,
115
- template_type=mask_type if mask_type in ["gm", "wm"] else "T1w",
114
+ template_type=mask_type,
116
115
  )
117
116
  # Resample template to target image
118
117
  target_img = target_data["data"]
@@ -264,7 +263,7 @@ class MaskRegistry(BasePipelineDataRegistry, metaclass=Singleton):
264
263
  name: str,
265
264
  resolution: Optional[float] = None,
266
265
  path_only: bool = False,
267
- ) -> Tuple[Optional[Union["Nifti1Image", Callable]], Optional[Path], str]:
266
+ ) -> tuple[Optional[Union["Nifti1Image", Callable]], Optional[Path], str]:
268
267
  """Load mask.
269
268
 
270
269
  Parameters
@@ -330,9 +329,9 @@ class MaskRegistry(BasePipelineDataRegistry, metaclass=Singleton):
330
329
 
331
330
  def get( # noqa: C901
332
331
  self,
333
- masks: Union[str, Dict, List[Union[Dict, str]]],
334
- target_data: Dict[str, Any],
335
- extra_input: Optional[Dict[str, Any]] = None,
332
+ masks: Union[str, dict, list[Union[dict, str]]],
333
+ target_data: dict[str, Any],
334
+ extra_input: Optional[dict[str, Any]] = None,
336
335
  ) -> "Nifti1Image":
337
336
  """Get mask, tailored for the target image.
338
337
 
@@ -357,8 +356,6 @@ class MaskRegistry(BasePipelineDataRegistry, metaclass=Singleton):
357
356
 
358
357
  Raises
359
358
  ------
360
- RuntimeError
361
- If warp / transformation file extension is not ".mat" or ".h5".
362
359
  ValueError
363
360
  If extra key is provided in addition to mask name in ``masks`` or
364
361
  if no mask is provided or
@@ -372,8 +369,6 @@ class MaskRegistry(BasePipelineDataRegistry, metaclass=Singleton):
372
369
  """
373
370
  # Check pre-requirements for space manipulation
374
371
  target_space = target_data["space"]
375
- # Set target standard space to target space
376
- target_std_space = target_space
377
372
  # Extra data type requirement check if target space is native
378
373
  if target_space == "native":
379
374
  # Check for extra inputs
@@ -383,8 +378,16 @@ class MaskRegistry(BasePipelineDataRegistry, metaclass=Singleton):
383
378
  "data types in particular for transformation to "
384
379
  f"{target_data['space']} space for further computation."
385
380
  )
381
+ # Get native space warper spec
382
+ warper_spec = get_native_warper(
383
+ target_data=target_data,
384
+ other_data=extra_input,
385
+ )
386
386
  # Set target standard space to warp file space source
387
- target_std_space = extra_input["Warp"]["src"]
387
+ target_std_space = warper_spec["src"]
388
+ else:
389
+ # Set target standard space to target space
390
+ target_std_space = target_space
388
391
 
389
392
  # Get the min of the voxels sizes and use it as the resolution
390
393
  target_img = target_data["data"]
@@ -489,7 +492,7 @@ class MaskRegistry(BasePipelineDataRegistry, metaclass=Singleton):
489
492
  src=mask_space,
490
493
  dst=target_std_space,
491
494
  target_data=target_data,
492
- extra_input=None,
495
+ warp_data=None,
493
496
  )
494
497
 
495
498
  all_masks.append(mask_img)
@@ -510,32 +513,22 @@ class MaskRegistry(BasePipelineDataRegistry, metaclass=Singleton):
510
513
 
511
514
  # Warp mask if target data is native
512
515
  if target_space == "native":
513
- # extra_input check done earlier
514
- # Check for warp file type to use correct tool
515
- warp_file_ext = extra_input["Warp"]["path"].suffix
516
- if warp_file_ext == ".mat":
516
+ # extra_input check done earlier and warper_spec exists
517
+ if warper_spec["warper"] == "fsl":
517
518
  mask_img = FSLMaskWarper().warp(
518
519
  mask_name="native",
519
520
  mask_img=mask_img,
520
521
  target_data=target_data,
521
- extra_input=extra_input,
522
+ warp_data=warper_spec,
522
523
  )
523
- elif warp_file_ext == ".h5":
524
+ elif warper_spec["warper"] == "ants":
524
525
  mask_img = ANTsMaskWarper().warp(
525
526
  mask_name="native",
526
527
  mask_img=mask_img,
527
528
  src="",
528
- dst="T1w",
529
+ dst="native",
529
530
  target_data=target_data,
530
- extra_input=extra_input,
531
- )
532
- else:
533
- raise_error(
534
- msg=(
535
- "Unknown warp / transformation file extension: "
536
- f"{warp_file_ext}"
537
- ),
538
- klass=RuntimeError,
531
+ warp_data=warper_spec,
539
532
  )
540
533
 
541
534
  return mask_img
@@ -7,7 +7,7 @@
7
7
 
8
8
  import socket
9
9
  from pathlib import Path
10
- from typing import Callable, Dict, List, Optional, Union
10
+ from typing import Callable, Optional, Union
11
11
 
12
12
  import nibabel as nib
13
13
  import numpy as np
@@ -254,7 +254,7 @@ def test_load_incorrect() -> None:
254
254
  def test_vickery_patil(
255
255
  name: str,
256
256
  resolution: Optional[float],
257
- pixdim: List[float],
257
+ pixdim: list[float],
258
258
  fname: str,
259
259
  ) -> None:
260
260
  """Test Vickery-Patil mask.
@@ -396,7 +396,7 @@ def test_get_errors() -> None:
396
396
  def test_nilearn_compute_masks(
397
397
  mask_name: str,
398
398
  function: Callable,
399
- params: Union[Dict, None],
399
+ params: Union[dict, None],
400
400
  resample: bool,
401
401
  ) -> None:
402
402
  """Test using nilearn compute mask functions.
@@ -479,7 +479,7 @@ def test_get_inherit() -> None:
479
479
  ],
480
480
  )
481
481
  def test_get_multiple(
482
- masks: Union[str, Dict, List[Union[Dict, str]]], params: Dict
482
+ masks: Union[str, dict, list[Union[dict, str]]], params: dict
483
483
  ) -> None:
484
484
  """Test getting multiple masks.
485
485
 
@@ -4,12 +4,12 @@
4
4
  # License: AGPL
5
5
 
6
6
  import uuid
7
- from typing import TYPE_CHECKING, Any, Dict, Optional
7
+ from typing import TYPE_CHECKING, Any, Optional
8
8
 
9
9
  import nibabel as nib
10
10
 
11
11
  from ...pipeline import WorkDirManager
12
- from ...utils import logger, run_ext_cmd
12
+ from ...utils import logger, raise_error, run_ext_cmd
13
13
  from ..template_spaces import get_template, get_xfm
14
14
 
15
15
 
@@ -33,8 +33,8 @@ class ANTsParcellationWarper:
33
33
  parcellation_img: "Nifti1Image",
34
34
  src: str,
35
35
  dst: str,
36
- target_data: Dict[str, Any],
37
- extra_input: Optional[Dict[str, Any]] = None,
36
+ target_data: dict[str, Any],
37
+ warp_data: Optional[dict[str, Any]],
38
38
  ) -> "Nifti1Image":
39
39
  """Warp ``parcellation_img`` to correct space.
40
40
 
@@ -55,17 +55,20 @@ class ANTsParcellationWarper:
55
55
  target_data : dict
56
56
  The corresponding item of the data object to which the parcellation
57
57
  will be applied.
58
- extra_input : dict, optional
59
- The other fields in the data object. Useful for accessing other
60
- data kinds that needs to be used in the computation of parcellation
61
- (default None).
62
-
58
+ warp_data : dict or None
59
+ The warp data item of the data object. The value is unused if
60
+ ``dst!="T1w"``.
63
61
 
64
62
  Returns
65
63
  -------
66
64
  nibabel.nifti1.Nifti1Image
67
65
  The transformed parcellation image.
68
66
 
67
+ Raises
68
+ ------
69
+ ValueError
70
+ If ``warp_data`` is None when ``dst="T1w"``.
71
+
69
72
  """
70
73
  # Create element-scoped tempdir so that warped parcellation is
71
74
  # available later as nibabel stores file path reference for
@@ -80,7 +83,11 @@ class ANTsParcellationWarper:
80
83
  )
81
84
 
82
85
  # Native space warping
83
- if dst == "T1w":
86
+ if dst == "native":
87
+ # Warp data check
88
+ if warp_data is None:
89
+ raise_error("No `warp_data` provided")
90
+
84
91
  logger.debug("Using ANTs for parcellation transformation")
85
92
 
86
93
  # Save existing parcellation image to a tempfile
@@ -102,7 +109,7 @@ class ANTsParcellationWarper:
102
109
  f"-i {prewarp_parcellation_path.resolve()}",
103
110
  # use resampled reference
104
111
  f"-r {target_data['reference_path'].resolve()}",
105
- f"-t {extra_input['Warp']['path'].resolve()}",
112
+ f"-t {warp_data['path'].resolve()}",
106
113
  f"-o {warped_parcellation_path.resolve()}",
107
114
  ]
108
115
  # Call antsApplyTransforms
@@ -4,7 +4,7 @@
4
4
  # License: AGPL
5
5
 
6
6
  import uuid
7
- from typing import TYPE_CHECKING, Any, Dict
7
+ from typing import TYPE_CHECKING, Any
8
8
 
9
9
  import nibabel as nib
10
10
 
@@ -30,8 +30,8 @@ class FSLParcellationWarper:
30
30
  self,
31
31
  parcellation_name: str,
32
32
  parcellation_img: "Nifti1Image",
33
- target_data: Dict[str, Any],
34
- extra_input: Dict[str, Any],
33
+ target_data: dict[str, Any],
34
+ warp_data: dict[str, Any],
35
35
  ) -> "Nifti1Image":
36
36
  """Warp ``parcellation_img`` to correct space.
37
37
 
@@ -44,10 +44,8 @@ class FSLParcellationWarper:
44
44
  target_data : dict
45
45
  The corresponding item of the data object to which the parcellation
46
46
  will be applied.
47
- extra_input : dict, optional
48
- The other fields in the data object. Useful for accessing other
49
- data kinds that needs to be used in the computation of parcellation
50
- (default None).
47
+ warp_data : dict
48
+ The warp data item of the data object.
51
49
 
52
50
  Returns
53
51
  -------
@@ -81,7 +79,7 @@ class FSLParcellationWarper:
81
79
  f"-i {prewarp_parcellation_path.resolve()}",
82
80
  # use resampled reference
83
81
  f"-r {target_data['reference_path'].resolve()}",
84
- f"-w {extra_input['Warp']['path'].resolve()}",
82
+ f"-w {warp_data['path'].resolve()}",
85
83
  f"-o {warped_parcellation_path.resolve()}",
86
84
  ]
87
85
  # Call applywarp