junifer 0.0.4.dev831__py3-none-any.whl → 0.0.5__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 (206) hide show
  1. junifer/__init__.py +17 -0
  2. junifer/_version.py +2 -2
  3. junifer/api/__init__.py +4 -1
  4. junifer/api/cli.py +91 -1
  5. junifer/api/decorators.py +9 -0
  6. junifer/api/functions.py +56 -10
  7. junifer/api/parser.py +3 -0
  8. junifer/api/queue_context/__init__.py +4 -1
  9. junifer/api/queue_context/gnu_parallel_local_adapter.py +16 -6
  10. junifer/api/queue_context/htcondor_adapter.py +16 -5
  11. junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +41 -12
  12. junifer/api/queue_context/tests/test_htcondor_adapter.py +48 -15
  13. junifer/api/res/afni/run_afni_docker.sh +1 -1
  14. junifer/api/res/ants/run_ants_docker.sh +1 -1
  15. junifer/api/res/freesurfer/mri_binarize +3 -0
  16. junifer/api/res/freesurfer/mri_mc +3 -0
  17. junifer/api/res/freesurfer/mri_pretess +3 -0
  18. junifer/api/res/freesurfer/mris_convert +3 -0
  19. junifer/api/res/freesurfer/run_freesurfer_docker.sh +61 -0
  20. junifer/api/res/fsl/run_fsl_docker.sh +1 -1
  21. junifer/api/res/{run_conda.sh → run_conda.bash} +1 -1
  22. junifer/api/res/run_conda.zsh +23 -0
  23. junifer/api/res/run_venv.bash +22 -0
  24. junifer/api/res/{run_venv.sh → run_venv.zsh} +1 -1
  25. junifer/api/tests/test_api_utils.py +4 -2
  26. junifer/api/tests/test_cli.py +83 -0
  27. junifer/api/tests/test_functions.py +27 -2
  28. junifer/configs/__init__.py +1 -1
  29. junifer/configs/juseless/__init__.py +4 -1
  30. junifer/configs/juseless/datagrabbers/__init__.py +10 -1
  31. junifer/configs/juseless/datagrabbers/aomic_id1000_vbm.py +4 -3
  32. junifer/configs/juseless/datagrabbers/camcan_vbm.py +3 -0
  33. junifer/configs/juseless/datagrabbers/ixi_vbm.py +4 -3
  34. junifer/configs/juseless/datagrabbers/tests/test_ucla.py +1 -3
  35. junifer/configs/juseless/datagrabbers/ucla.py +12 -9
  36. junifer/configs/juseless/datagrabbers/ukb_vbm.py +3 -0
  37. junifer/data/__init__.py +21 -1
  38. junifer/data/coordinates.py +10 -19
  39. junifer/data/masks/ukb/UKB_15K_GM_template.nii.gz +0 -0
  40. junifer/data/masks.py +58 -87
  41. junifer/data/parcellations.py +14 -3
  42. junifer/data/template_spaces.py +4 -1
  43. junifer/data/tests/test_masks.py +26 -37
  44. junifer/data/utils.py +3 -0
  45. junifer/datagrabber/__init__.py +18 -1
  46. junifer/datagrabber/aomic/__init__.py +3 -0
  47. junifer/datagrabber/aomic/id1000.py +70 -37
  48. junifer/datagrabber/aomic/piop1.py +69 -36
  49. junifer/datagrabber/aomic/piop2.py +71 -38
  50. junifer/datagrabber/aomic/tests/test_id1000.py +44 -100
  51. junifer/datagrabber/aomic/tests/test_piop1.py +65 -108
  52. junifer/datagrabber/aomic/tests/test_piop2.py +45 -102
  53. junifer/datagrabber/base.py +13 -6
  54. junifer/datagrabber/datalad_base.py +13 -1
  55. junifer/datagrabber/dmcc13_benchmark.py +36 -53
  56. junifer/datagrabber/hcp1200/__init__.py +3 -0
  57. junifer/datagrabber/hcp1200/datalad_hcp1200.py +3 -0
  58. junifer/datagrabber/hcp1200/hcp1200.py +4 -1
  59. junifer/datagrabber/multiple.py +45 -6
  60. junifer/datagrabber/pattern.py +170 -62
  61. junifer/datagrabber/pattern_datalad.py +25 -12
  62. junifer/datagrabber/pattern_validation_mixin.py +388 -0
  63. junifer/datagrabber/tests/test_datalad_base.py +4 -4
  64. junifer/datagrabber/tests/test_dmcc13_benchmark.py +46 -19
  65. junifer/datagrabber/tests/test_multiple.py +161 -84
  66. junifer/datagrabber/tests/test_pattern.py +45 -0
  67. junifer/datagrabber/tests/test_pattern_datalad.py +4 -4
  68. junifer/datagrabber/tests/test_pattern_validation_mixin.py +249 -0
  69. junifer/datareader/__init__.py +4 -1
  70. junifer/datareader/default.py +95 -43
  71. junifer/external/BrainPrint/brainprint/__init__.py +4 -0
  72. junifer/external/BrainPrint/brainprint/_version.py +3 -0
  73. junifer/external/BrainPrint/brainprint/asymmetry.py +91 -0
  74. junifer/external/BrainPrint/brainprint/brainprint.py +441 -0
  75. junifer/external/BrainPrint/brainprint/surfaces.py +258 -0
  76. junifer/external/BrainPrint/brainprint/utils/__init__.py +1 -0
  77. junifer/external/BrainPrint/brainprint/utils/_config.py +112 -0
  78. junifer/external/BrainPrint/brainprint/utils/utils.py +188 -0
  79. junifer/external/__init__.py +1 -1
  80. junifer/external/nilearn/__init__.py +5 -1
  81. junifer/external/nilearn/junifer_connectivity_measure.py +483 -0
  82. junifer/external/nilearn/junifer_nifti_spheres_masker.py +23 -9
  83. junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +1089 -0
  84. junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +76 -1
  85. junifer/markers/__init__.py +23 -1
  86. junifer/markers/base.py +68 -28
  87. junifer/markers/brainprint.py +459 -0
  88. junifer/markers/collection.py +10 -2
  89. junifer/markers/complexity/__init__.py +10 -0
  90. junifer/markers/complexity/complexity_base.py +26 -43
  91. junifer/markers/complexity/hurst_exponent.py +3 -0
  92. junifer/markers/complexity/multiscale_entropy_auc.py +3 -0
  93. junifer/markers/complexity/perm_entropy.py +3 -0
  94. junifer/markers/complexity/range_entropy.py +3 -0
  95. junifer/markers/complexity/range_entropy_auc.py +3 -0
  96. junifer/markers/complexity/sample_entropy.py +3 -0
  97. junifer/markers/complexity/tests/test_hurst_exponent.py +11 -3
  98. junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +11 -3
  99. junifer/markers/complexity/tests/test_perm_entropy.py +11 -3
  100. junifer/markers/complexity/tests/test_range_entropy.py +11 -3
  101. junifer/markers/complexity/tests/test_range_entropy_auc.py +11 -3
  102. junifer/markers/complexity/tests/test_sample_entropy.py +11 -3
  103. junifer/markers/complexity/tests/test_weighted_perm_entropy.py +11 -3
  104. junifer/markers/complexity/weighted_perm_entropy.py +3 -0
  105. junifer/markers/ets_rss.py +27 -42
  106. junifer/markers/falff/__init__.py +3 -0
  107. junifer/markers/falff/_afni_falff.py +5 -2
  108. junifer/markers/falff/_junifer_falff.py +3 -0
  109. junifer/markers/falff/falff_base.py +20 -46
  110. junifer/markers/falff/falff_parcels.py +56 -27
  111. junifer/markers/falff/falff_spheres.py +60 -29
  112. junifer/markers/falff/tests/test_falff_parcels.py +39 -23
  113. junifer/markers/falff/tests/test_falff_spheres.py +39 -23
  114. junifer/markers/functional_connectivity/__init__.py +9 -0
  115. junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +63 -60
  116. junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +45 -32
  117. junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +49 -36
  118. junifer/markers/functional_connectivity/functional_connectivity_base.py +71 -70
  119. junifer/markers/functional_connectivity/functional_connectivity_parcels.py +34 -25
  120. junifer/markers/functional_connectivity/functional_connectivity_spheres.py +40 -30
  121. junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +11 -7
  122. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +27 -7
  123. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +28 -12
  124. junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +35 -11
  125. junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +36 -62
  126. junifer/markers/parcel_aggregation.py +47 -61
  127. junifer/markers/reho/__init__.py +3 -0
  128. junifer/markers/reho/_afni_reho.py +5 -2
  129. junifer/markers/reho/_junifer_reho.py +4 -1
  130. junifer/markers/reho/reho_base.py +8 -27
  131. junifer/markers/reho/reho_parcels.py +28 -17
  132. junifer/markers/reho/reho_spheres.py +27 -18
  133. junifer/markers/reho/tests/test_reho_parcels.py +8 -3
  134. junifer/markers/reho/tests/test_reho_spheres.py +8 -3
  135. junifer/markers/sphere_aggregation.py +43 -59
  136. junifer/markers/temporal_snr/__init__.py +3 -0
  137. junifer/markers/temporal_snr/temporal_snr_base.py +23 -32
  138. junifer/markers/temporal_snr/temporal_snr_parcels.py +9 -6
  139. junifer/markers/temporal_snr/temporal_snr_spheres.py +9 -6
  140. junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +6 -3
  141. junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +6 -3
  142. junifer/markers/tests/test_brainprint.py +58 -0
  143. junifer/markers/tests/test_collection.py +9 -8
  144. junifer/markers/tests/test_ets_rss.py +15 -9
  145. junifer/markers/tests/test_markers_base.py +17 -18
  146. junifer/markers/tests/test_parcel_aggregation.py +93 -32
  147. junifer/markers/tests/test_sphere_aggregation.py +72 -19
  148. junifer/onthefly/__init__.py +4 -1
  149. junifer/onthefly/read_transform.py +3 -0
  150. junifer/pipeline/__init__.py +9 -1
  151. junifer/pipeline/pipeline_step_mixin.py +21 -4
  152. junifer/pipeline/registry.py +3 -0
  153. junifer/pipeline/singleton.py +3 -0
  154. junifer/pipeline/tests/test_registry.py +1 -1
  155. junifer/pipeline/update_meta_mixin.py +3 -0
  156. junifer/pipeline/utils.py +67 -1
  157. junifer/pipeline/workdir_manager.py +3 -0
  158. junifer/preprocess/__init__.py +10 -2
  159. junifer/preprocess/base.py +6 -3
  160. junifer/preprocess/confounds/__init__.py +3 -0
  161. junifer/preprocess/confounds/fmriprep_confound_remover.py +47 -60
  162. junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +72 -113
  163. junifer/preprocess/smoothing/__init__.py +9 -0
  164. junifer/preprocess/smoothing/_afni_smoothing.py +119 -0
  165. junifer/preprocess/smoothing/_fsl_smoothing.py +116 -0
  166. junifer/preprocess/smoothing/_nilearn_smoothing.py +69 -0
  167. junifer/preprocess/smoothing/smoothing.py +174 -0
  168. junifer/preprocess/smoothing/tests/test_smoothing.py +94 -0
  169. junifer/preprocess/warping/__init__.py +3 -0
  170. junifer/preprocess/warping/_ants_warper.py +3 -0
  171. junifer/preprocess/warping/_fsl_warper.py +3 -0
  172. junifer/stats.py +4 -1
  173. junifer/storage/__init__.py +9 -1
  174. junifer/storage/base.py +40 -1
  175. junifer/storage/hdf5.py +71 -9
  176. junifer/storage/pandas_base.py +3 -0
  177. junifer/storage/sqlite.py +3 -0
  178. junifer/storage/tests/test_hdf5.py +82 -10
  179. junifer/storage/utils.py +9 -0
  180. junifer/testing/__init__.py +4 -1
  181. junifer/testing/datagrabbers.py +13 -6
  182. junifer/testing/tests/test_partlycloudytesting_datagrabber.py +7 -7
  183. junifer/testing/utils.py +3 -0
  184. junifer/utils/__init__.py +13 -2
  185. junifer/utils/fs.py +3 -0
  186. junifer/utils/helpers.py +32 -1
  187. junifer/utils/logging.py +33 -4
  188. junifer/utils/tests/test_logging.py +8 -0
  189. {junifer-0.0.4.dev831.dist-info → junifer-0.0.5.dist-info}/METADATA +17 -16
  190. junifer-0.0.5.dist-info/RECORD +275 -0
  191. {junifer-0.0.4.dev831.dist-info → junifer-0.0.5.dist-info}/WHEEL +1 -1
  192. junifer/datagrabber/tests/test_datagrabber_utils.py +0 -218
  193. junifer/datagrabber/utils.py +0 -230
  194. junifer/preprocess/ants/__init__.py +0 -4
  195. junifer/preprocess/ants/ants_apply_transforms_warper.py +0 -185
  196. junifer/preprocess/ants/tests/test_ants_apply_transforms_warper.py +0 -56
  197. junifer/preprocess/bold_warper.py +0 -265
  198. junifer/preprocess/fsl/__init__.py +0 -4
  199. junifer/preprocess/fsl/apply_warper.py +0 -179
  200. junifer/preprocess/fsl/tests/test_apply_warper.py +0 -45
  201. junifer/preprocess/tests/test_bold_warper.py +0 -159
  202. junifer-0.0.4.dev831.dist-info/RECORD +0 -257
  203. {junifer-0.0.4.dev831.dist-info → junifer-0.0.5.dist-info}/AUTHORS.rst +0 -0
  204. {junifer-0.0.4.dev831.dist-info → junifer-0.0.5.dist-info}/LICENSE.md +0 -0
  205. {junifer-0.0.4.dev831.dist-info → junifer-0.0.5.dist-info}/entry_points.txt +0 -0
  206. {junifer-0.0.4.dev831.dist-info → junifer-0.0.5.dist-info}/top_level.txt +0 -0
junifer/data/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- """Provide imports for data sub-package."""
1
+ """Parcellations, coordinates and masks."""
2
2
 
3
3
  # Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
4
4
  # Synchon Mandal <s.mandal@fz-juelich.de>
@@ -28,3 +28,23 @@ from .masks import (
28
28
  from .template_spaces import get_template, get_xfm
29
29
 
30
30
  from . import utils
31
+
32
+
33
+ __all__ = [
34
+ "list_coordinates",
35
+ "load_coordinates",
36
+ "register_coordinates",
37
+ "get_coordinates",
38
+ "list_parcellations",
39
+ "load_parcellation",
40
+ "register_parcellation",
41
+ "merge_parcellations",
42
+ "get_parcellation",
43
+ "list_masks",
44
+ "load_mask",
45
+ "register_mask",
46
+ "get_mask",
47
+ "get_template",
48
+ "get_xfm",
49
+ "utils",
50
+ ]
@@ -1,4 +1,4 @@
1
- """Provide functions for list of coordinates."""
1
+ """Functions for coordinates manipulation."""
2
2
 
3
3
  # Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
4
4
  # Synchon Mandal <s.mandal@fz-juelich.de>
@@ -13,7 +13,15 @@ import pandas as pd
13
13
  from numpy.typing import ArrayLike
14
14
 
15
15
  from ..pipeline import WorkDirManager
16
- from ..utils import logger, raise_error, run_ext_cmd, warn_with_log
16
+ from ..utils import logger, raise_error, run_ext_cmd
17
+
18
+
19
+ __all__ = [
20
+ "register_coordinates",
21
+ "list_coordinates",
22
+ "get_coordinates",
23
+ "load_coordinates",
24
+ ]
17
25
 
18
26
 
19
27
  # Path to the VOIs
@@ -377,11 +385,6 @@ def load_coordinates(name: str) -> Tuple[ArrayLike, List[str], str]:
377
385
  ValueError
378
386
  If ``name`` is invalid.
379
387
 
380
- Warns
381
- -----
382
- DeprecationWarning
383
- If ``Power`` is provided as the ``name``.
384
-
385
388
  """
386
389
  # Check for valid coordinates name
387
390
  if name not in _available_coordinates:
@@ -389,18 +392,6 @@ def load_coordinates(name: str) -> Tuple[ArrayLike, List[str], str]:
389
392
  f"Coordinates {name} not found. "
390
393
  f"Valid options are: {list_coordinates()}"
391
394
  )
392
-
393
- # Put up deprecation notice
394
- if name == "Power":
395
- warn_with_log(
396
- msg=(
397
- "`Power` has been replaced with `Power2011` and will be "
398
- "removed in the next release. For now, it's available for "
399
- "backward compatibility."
400
- ),
401
- category=DeprecationWarning,
402
- )
403
-
404
395
  # Load coordinates
405
396
  t_coord = _available_coordinates[name]
406
397
  if isinstance(t_coord.get("path"), Path):
junifer/data/masks.py CHANGED
@@ -1,4 +1,4 @@
1
- """Provide functions for masks."""
1
+ """Functions for mask manipulation."""
2
2
 
3
3
  # Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
4
4
  # Synchon Mandal <s.mandal@fz-juelich.de>
@@ -19,7 +19,6 @@ from typing import (
19
19
 
20
20
  import nibabel as nib
21
21
  import numpy as np
22
- from nilearn.datasets import fetch_icbm152_brain_gm_mask
23
22
  from nilearn.image import get_data, new_img_like, resample_to_img
24
23
  from nilearn.masking import (
25
24
  compute_background_mask,
@@ -28,7 +27,7 @@ from nilearn.masking import (
28
27
  )
29
28
 
30
29
  from ..pipeline import WorkDirManager
31
- from ..utils import logger, raise_error, run_ext_cmd, warn_with_log
30
+ from ..utils import logger, raise_error, run_ext_cmd
32
31
  from .template_spaces import get_template, get_xfm
33
32
  from .utils import closest_resolution
34
33
 
@@ -36,6 +35,16 @@ from .utils import closest_resolution
36
35
  if TYPE_CHECKING:
37
36
  from nibabel import Nifti1Image
38
37
 
38
+
39
+ __all__ = [
40
+ "compute_brain_mask",
41
+ "register_mask",
42
+ "list_masks",
43
+ "get_mask",
44
+ "load_mask",
45
+ ]
46
+
47
+
39
48
  # Path to the masks
40
49
  _masks_path = Path(__file__).parent / "masks"
41
50
 
@@ -121,46 +130,6 @@ def compute_brain_mask(
121
130
  return new_img_like(target_img, mask) # type: ignore
122
131
 
123
132
 
124
- def _fetch_icbm152_brain_gm_mask(
125
- target_img: "Nifti1Image",
126
- **kwargs,
127
- ) -> "Nifti1Image":
128
- """Fetch ICBM152 brain mask and resample.
129
-
130
- Parameters
131
- ----------
132
- target_img : nibabel.Nifti1Image
133
- The image to which the mask will be resampled.
134
- **kwargs : dict
135
- Keyword arguments to be passed to
136
- :func:`nilearn.datasets.fetch_icbm152_brain_gm_mask`.
137
-
138
- Returns
139
- -------
140
- nibabel.Nifti1Image
141
- The resampled mask.
142
-
143
- Warns
144
- -----
145
- DeprecationWarning
146
- If this function is used.
147
-
148
- """
149
- warn_with_log(
150
- msg=(
151
- "It is recommended to use ``compute_brain_mask`` with "
152
- "``mask_type='gm'``. This function will be removed in the next "
153
- "release. For now, it's available for backward compatibility."
154
- ),
155
- category=DeprecationWarning,
156
- )
157
- mask = fetch_icbm152_brain_gm_mask(**kwargs)
158
- mask = resample_to_img(
159
- mask, target_img, interpolation="nearest", copy=True
160
- )
161
- return mask
162
-
163
-
164
133
  # A dictionary containing all supported masks and their respective file or
165
134
  # data.
166
135
 
@@ -194,10 +163,9 @@ _available_masks: Dict[str, Dict[str, Any]] = {
194
163
  "func": compute_epi_mask,
195
164
  "space": "inherit",
196
165
  },
197
- "fetch_icbm152_brain_gm_mask": {
198
- "family": "Callable",
199
- "func": _fetch_icbm152_brain_gm_mask,
200
- "space": "MNI152NLin2009aAsym",
166
+ "UKB_15K_GM": {
167
+ "family": "UKB",
168
+ "space": "MNI152NLin6Asym",
201
169
  },
202
170
  }
203
171
 
@@ -292,14 +260,12 @@ def get_mask( # noqa: C901
292
260
  Raises
293
261
  ------
294
262
  RuntimeError
295
- If warp / transformation file extension is not ".mat" or ".h5" or
296
- if fetch_icbm152_brain_gm_mask is used and requires warping to
297
- other template space.
263
+ If warp / transformation file extension is not ".mat" or ".h5".
298
264
  ValueError
299
265
  If extra key is provided in addition to mask name in ``masks`` or
300
266
  if no mask is provided or
301
- if ``masks = "inherit"`` but ``extra_input`` is None or ``mask_item``
302
- is None or ``mask_items``'s value is not in ``extra_input`` or
267
+ if ``masks = "inherit"`` and ``mask`` key for the ``target_data`` is
268
+ not found or
303
269
  if callable parameters are passed to non-callable mask or
304
270
  if parameters are passed to :func:`nilearn.masking.intersect_masks`
305
271
  when there is only one mask or
@@ -358,8 +324,8 @@ def get_mask( # noqa: C901
358
324
  if len(true_masks) == 0:
359
325
  raise_error("No mask was passed. At least one mask is required.")
360
326
 
361
- # Get the data type for the input data type's mask
362
- inherited_mask_item = target_data.get("mask_item", None)
327
+ # Get the nested mask data type for the input data type
328
+ inherited_mask_item = target_data.get("mask", None)
363
329
 
364
330
  # Create component-scoped tempdir
365
331
  tempdir = WorkDirManager().get_tempdir(prefix="masks")
@@ -378,45 +344,18 @@ def get_mask( # noqa: C901
378
344
  mask_name = t_mask
379
345
  mask_params = None
380
346
 
381
- # If mask is being inherited from previous steps like preprocessing
347
+ # If mask is being inherited from the datagrabber or a preprocessor,
348
+ # check that it's accessible
382
349
  if mask_name == "inherit":
383
- # Requires extra input to be passed
384
- if extra_input is None:
385
- raise_error(
386
- "Cannot inherit mask from another data item "
387
- "because no extra data was passed."
388
- )
389
- # Missing inherited mask item
390
350
  if inherited_mask_item is None:
391
351
  raise_error(
392
- "Cannot inherit mask from another data item "
393
- "because no mask item was specified "
394
- "(missing `mask_item` key in the data object)."
352
+ "Cannot inherit mask from the target data. Either the "
353
+ "DataGrabber or a Preprocessor does not provide `mask` "
354
+ "for the target data type."
395
355
  )
396
- # Missing inherited mask item in extra input
397
- if inherited_mask_item not in extra_input:
398
- raise_error(
399
- "Cannot inherit mask from another data item "
400
- f"because the item ({inherited_mask_item}) does not exist."
401
- )
402
- mask_img = extra_input[inherited_mask_item]["data"]
356
+ mask_img = inherited_mask_item["data"]
403
357
  # Starting with new mask
404
358
  else:
405
- # Restrict fetch_icbm152_brain_gm_mask if target std space doesn't
406
- # match
407
- if (
408
- mask_name == "fetch_icbm152_brain_gm_mask"
409
- and target_std_space != "MNI152NLin2009aAsym"
410
- ):
411
- raise_error(
412
- (
413
- "``fetch_icbm152_brain_gm_mask`` is deprecated and "
414
- "space transformation to any other template space is "
415
- "prohibited as it will lead to unforeseen errors. "
416
- "``compute_brain_mask`` is a better alternative."
417
- ),
418
- klass=RuntimeError,
419
- )
420
359
  # Load mask
421
360
  mask_object, _, mask_space = load_mask(
422
361
  mask_name, path_only=False, resolution=resolution
@@ -632,6 +571,8 @@ def load_mask(
632
571
  elif t_family == "Callable":
633
572
  mask_img = mask_definition["func"]
634
573
  mask_fname = None
574
+ elif t_family == "UKB":
575
+ mask_fname = _load_ukb_mask(name)
635
576
  else:
636
577
  raise_error(f"I don't know about the {t_family} mask family.")
637
578
 
@@ -697,3 +638,33 @@ def _load_vickery_patil_mask(
697
638
  mask_fname = _masks_path / "vickery-patil" / mask_fname
698
639
 
699
640
  return mask_fname
641
+
642
+
643
+ def _load_ukb_mask(name: str) -> Path:
644
+ """Load UKB mask.
645
+
646
+ Parameters
647
+ ----------
648
+ name : {"UKB_15K_GM"}
649
+ The name of the mask.
650
+
651
+ Returns
652
+ -------
653
+ pathlib.Path
654
+ File path to the mask image.
655
+
656
+ Raises
657
+ ------
658
+ ValueError
659
+ If ``name`` is invalid.
660
+
661
+ """
662
+ if name == "UKB_15K_GM":
663
+ mask_fname = "UKB_15K_GM_template.nii.gz"
664
+ else:
665
+ raise_error(f"Cannot find a UKB mask called {name}")
666
+
667
+ # Set path for masks
668
+ mask_fname = _masks_path / "ukb" / mask_fname
669
+
670
+ return mask_fname
@@ -1,4 +1,4 @@
1
- """Provide functions for parcellation."""
1
+ """Functions for parcellation manipulation."""
2
2
 
3
3
  # Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
4
4
  # Vera Komeyer <v.komeyer@fz-juelich.de>
@@ -30,6 +30,15 @@ if TYPE_CHECKING:
30
30
  from nibabel import Nifti1Image
31
31
 
32
32
 
33
+ __all__ = [
34
+ "register_parcellation",
35
+ "list_parcellations",
36
+ "get_parcellation",
37
+ "load_parcellation",
38
+ "merge_parcellations",
39
+ ]
40
+
41
+
33
42
  # A dictionary containing all supported parcellations and their respective
34
43
  # valid parameters.
35
44
 
@@ -326,7 +335,9 @@ def get_parcellation(
326
335
  # Call antsApplyTransforms
327
336
  run_ext_cmd(name="antsApplyTransforms", cmd=apply_transforms_cmd)
328
337
 
329
- img = nib.load(warped_parcellation_path)
338
+ raw_img = nib.load(warped_parcellation_path)
339
+ # Remove extra dimension added by ANTs
340
+ img = image.math_img("np.squeeze(img)", img=raw_img)
330
341
 
331
342
  # Resample parcellation to target image
332
343
  img_to_merge = image.resample_to_img(
@@ -887,7 +898,7 @@ def _retrieve_tian(
887
898
  )
888
899
  with open(parcellation_lname, "w") as filehandle:
889
900
  for listitem in labels:
890
- filehandle.write("%s\n" % listitem)
901
+ filehandle.write(f"{listitem}\n")
891
902
  logger.info(
892
903
  "Currently there are no labels provided for the 7T Tian "
893
904
  "parcellation. A simple numbering scheme for distinction was "
@@ -1,4 +1,4 @@
1
- """Provide functions for template spaces."""
1
+ """Functions for template space manipulation."""
2
2
 
3
3
  # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
4
  # License: AGPL
@@ -15,6 +15,9 @@ from ..utils import logger, raise_error
15
15
  from .utils import closest_resolution
16
16
 
17
17
 
18
+ __all__ = ["get_xfm", "get_template"]
19
+
20
+
18
21
  def get_xfm(
19
22
  src: str, dst: str, xfms_dir: Union[str, Path, None] = None
20
23
  ) -> Path: # pragma: no cover
@@ -22,6 +22,7 @@ from numpy.testing import assert_array_almost_equal, assert_array_equal
22
22
 
23
23
  from junifer.data.masks import (
24
24
  _available_masks,
25
+ _load_ukb_mask,
25
26
  _load_vickery_patil_mask,
26
27
  compute_brain_mask,
27
28
  get_mask,
@@ -212,6 +213,7 @@ def test_register_mask(
212
213
  [
213
214
  "GM_prob0.2",
214
215
  "GM_prob0.2_cortex",
216
+ "UKB_15K_GM",
215
217
  ],
216
218
  )
217
219
  def test_list_masks_correct(mask_name: str) -> None:
@@ -291,6 +293,21 @@ def test_vickery_patil_error() -> None:
291
293
  _load_vickery_patil_mask(name="wrong", resolution=2.0)
292
294
 
293
295
 
296
+ def test_ukb() -> None:
297
+ """Test UKB mask."""
298
+ mask, mask_fname, space = load_mask("UKB_15K_GM", resolution=2.0)
299
+ assert_array_almost_equal(mask.header["pixdim"][1:4], 2.0) # type: ignore
300
+ assert space == "MNI152NLin6Asym"
301
+ assert mask_fname is not None
302
+ assert mask_fname.name == "UKB_15K_GM_template.nii.gz"
303
+
304
+
305
+ def test_ukb_error() -> None:
306
+ """Test error for UKB mask."""
307
+ with pytest.raises(ValueError, match=r"find a UKB mask "):
308
+ _load_ukb_mask(name="wrong")
309
+
310
+
294
311
  def test_get_mask() -> None:
295
312
  """Test the get_mask function."""
296
313
  with OasisVBMTestingDataGrabber() as dg:
@@ -350,7 +367,7 @@ def test_get_mask_errors() -> None:
350
367
  with pytest.raises(ValueError, match=r"callable params"):
351
368
  get_mask(masks={"GM_prob0.2": {"param": 1}}, target_data=vbm_gm)
352
369
 
353
- # Pass only parametesr to the intersection function
370
+ # Pass only parameters to the intersection function
354
371
  with pytest.raises(
355
372
  ValueError, match=r" At least one mask is required."
356
373
  ):
@@ -365,35 +382,10 @@ def test_get_mask_errors() -> None:
365
382
  target_data=vbm_gm,
366
383
  )
367
384
 
368
- # Test "inherited" masks errors
369
-
370
- # 1) No extra_data parameter
371
- with pytest.raises(ValueError, match=r"no extra data was passed"):
385
+ # Test "inherited" masks error
386
+ with pytest.raises(ValueError, match=r"provide `mask`"):
372
387
  get_mask(masks="inherit", target_data=vbm_gm)
373
388
 
374
- extra_input = {"VBM_MASK": {}}
375
-
376
- # 2) No mask_item key in target_data
377
- with pytest.raises(ValueError, match=r"no mask item was specified"):
378
- get_mask(
379
- masks="inherit", target_data=vbm_gm, extra_input=extra_input
380
- )
381
-
382
- # 3) mask_item not in extra data
383
- with pytest.raises(ValueError, match=r"does not exist"):
384
- vbm_gm["mask_item"] = "wrong"
385
- get_mask(
386
- masks="inherit", target_data=vbm_gm, extra_input=extra_input
387
- )
388
-
389
- # Block fetch_icbm152_brain_gm_mask space transformation
390
- with pytest.raises(RuntimeError, match="prohibited"):
391
- get_mask(
392
- masks="fetch_icbm152_brain_gm_mask",
393
- target_data=vbm_gm,
394
- extra_input=extra_input,
395
- )
396
-
397
389
 
398
390
  @pytest.mark.parametrize(
399
391
  "mask_name,function,params,resample",
@@ -465,18 +457,15 @@ def test_get_mask_inherit() -> None:
465
457
  )
466
458
 
467
459
  # Now get the mask using the inherit functionality, passing the
468
- # computed mask as extra data
469
- extra_input = {
470
- "BOLD_MASK": {
471
- "data": gm_mask,
472
- "space": element_data["BOLD"]["space"],
473
- }
460
+ # computed mask as the data
461
+ bold_dict = element_data["BOLD"]
462
+ bold_dict["mask"] = {
463
+ "data": gm_mask,
464
+ "space": element_data["BOLD"]["space"],
474
465
  }
475
- element_data["BOLD"]["mask_item"] = "BOLD_MASK"
476
466
  mask2 = get_mask(
477
467
  masks="inherit",
478
- target_data=element_data["BOLD"],
479
- extra_input=extra_input,
468
+ target_data=bold_dict,
480
469
  )
481
470
 
482
471
  # Both masks should be equal
junifer/data/utils.py CHANGED
@@ -7,6 +7,9 @@ import numpy as np
7
7
  from ..utils.logging import logger
8
8
 
9
9
 
10
+ __all__ = ["closest_resolution"]
11
+
12
+
10
13
  def closest_resolution(
11
14
  resolution: Optional[Union[float, int]],
12
15
  valid_resolution: Union[List[float], List[int], np.ndarray],
@@ -1,4 +1,4 @@
1
- """Provide imports for datagrabber sub-package."""
1
+ """DataGrabbers for datasets' data description."""
2
2
 
3
3
  # Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
4
4
  # Leonard Sasse <l.sasse@fz-juelich.de>
@@ -16,3 +16,20 @@ from .aomic import DataladAOMICID1000, DataladAOMICPIOP1, DataladAOMICPIOP2
16
16
  from .hcp1200 import HCP1200, DataladHCP1200
17
17
  from .multiple import MultipleDataGrabber
18
18
  from .dmcc13_benchmark import DMCC13Benchmark
19
+
20
+ from .pattern_validation_mixin import PatternValidationMixin
21
+
22
+ __all__ = [
23
+ "BaseDataGrabber",
24
+ "DataladDataGrabber",
25
+ "PatternDataGrabber",
26
+ "PatternDataladDataGrabber",
27
+ "DataladAOMICID1000",
28
+ "DataladAOMICPIOP1",
29
+ "DataladAOMICPIOP2",
30
+ "HCP1200",
31
+ "DataladHCP1200",
32
+ "MultipleDataGrabber",
33
+ "DMCC13Benchmark",
34
+ "PatternValidationMixin",
35
+ ]
@@ -7,3 +7,6 @@
7
7
  from .id1000 import DataladAOMICID1000
8
8
  from .piop1 import DataladAOMICPIOP1
9
9
  from .piop2 import DataladAOMICPIOP2
10
+
11
+
12
+ __all__ = ["DataladAOMICID1000", "DataladAOMICPIOP1", "DataladAOMICPIOP2"]
@@ -14,6 +14,9 @@ from ...api.decorators import register_datagrabber
14
14
  from ..pattern_datalad import PatternDataladDataGrabber
15
15
 
16
16
 
17
+ __all__ = ["DataladAOMICID1000"]
18
+
19
+
17
20
  @register_datagrabber
18
21
  class DataladAOMICID1000(PatternDataladDataGrabber):
19
22
  """Concrete implementation for datalad-based data fetching of AOMIC ID1000.
@@ -24,8 +27,8 @@ class DataladAOMICID1000(PatternDataladDataGrabber):
24
27
  The directory where the datalad dataset will be cloned. If None,
25
28
  the datalad dataset will be cloned into a temporary directory
26
29
  (default None).
27
- types: {"BOLD", "BOLD_confounds", "T1w", "VBM_CSF", "VBM_GM", \
28
- "VBM_WM", "DWI"} or a list of the options, optional
30
+ types: {"BOLD", "T1w", "VBM_CSF", "VBM_GM", "VBM_WM", "DWI", \
31
+ "FreeSurfer"} or list of the options, optional
29
32
  AOMIC data types. If None, all available data types are selected.
30
33
  (default None).
31
34
  native_t1w : bool, optional
@@ -48,24 +51,23 @@ class DataladAOMICID1000(PatternDataladDataGrabber):
48
51
  "space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz"
49
52
  ),
50
53
  "space": "MNI152NLin2009cAsym",
51
- "mask_item": "BOLD_mask",
52
- },
53
- "BOLD_confounds": {
54
- "pattern": (
55
- "derivatives/fmriprep/{subject}/func/"
56
- "{subject}_task-moviewatching_"
57
- "desc-confounds_regressors.tsv"
58
- ),
59
- "format": "fmriprep",
60
- },
61
- "BOLD_mask": {
62
- "pattern": (
63
- "derivatives/fmriprep/{subject}/func/"
64
- "{subject}_task-moviewatching_"
65
- "space-MNI152NLin2009cAsym_"
66
- "desc-brain_mask.nii.gz"
67
- ),
68
- "space": "MNI152NLin2009cAsym",
54
+ "mask": {
55
+ "pattern": (
56
+ "derivatives/fmriprep/{subject}/func/"
57
+ "{subject}_task-moviewatching_"
58
+ "space-MNI152NLin2009cAsym_"
59
+ "desc-brain_mask.nii.gz"
60
+ ),
61
+ "space": "MNI152NLin2009cAsym",
62
+ },
63
+ "confounds": {
64
+ "pattern": (
65
+ "derivatives/fmriprep/{subject}/func/"
66
+ "{subject}_task-moviewatching_"
67
+ "desc-confounds_regressors.tsv"
68
+ ),
69
+ "format": "fmriprep",
70
+ },
69
71
  },
70
72
  "T1w": {
71
73
  "pattern": (
@@ -74,15 +76,14 @@ class DataladAOMICID1000(PatternDataladDataGrabber):
74
76
  "desc-preproc_T1w.nii.gz"
75
77
  ),
76
78
  "space": "MNI152NLin2009cAsym",
77
- "mask_item": "T1w_mask",
78
- },
79
- "T1w_mask": {
80
- "pattern": (
81
- "derivatives/fmriprep/{subject}/anat/"
82
- "{subject}_space-MNI152NLin2009cAsym_"
83
- "desc-brain_mask.nii.gz"
84
- ),
85
- "space": "MNI152NLin2009cAsym",
79
+ "mask": {
80
+ "pattern": (
81
+ "derivatives/fmriprep/{subject}/anat/"
82
+ "{subject}_space-MNI152NLin2009cAsym_"
83
+ "desc-brain_mask.nii.gz"
84
+ ),
85
+ "space": "MNI152NLin2009cAsym",
86
+ },
86
87
  },
87
88
  "VBM_CSF": {
88
89
  "pattern": (
@@ -114,6 +115,39 @@ class DataladAOMICID1000(PatternDataladDataGrabber):
114
115
  "{subject}_desc-preproc_dwi.nii.gz"
115
116
  ),
116
117
  },
118
+ "FreeSurfer": {
119
+ "pattern": "derivatives/freesurfer/[!f]{subject}/mri/T1.mg[z]",
120
+ "aseg": {
121
+ "pattern": (
122
+ "derivatives/freesurfer/[!f]{subject}/mri/aseg.mg[z]"
123
+ )
124
+ },
125
+ "norm": {
126
+ "pattern": (
127
+ "derivatives/freesurfer/[!f]{subject}/mri/norm.mg[z]"
128
+ )
129
+ },
130
+ "lh_white": {
131
+ "pattern": (
132
+ "derivatives/freesurfer/[!f]{subject}/surf/lh.whit[e]"
133
+ )
134
+ },
135
+ "rh_white": {
136
+ "pattern": (
137
+ "derivatives/freesurfer/[!f]{subject}/surf/rh.whit[e]"
138
+ )
139
+ },
140
+ "lh_pial": {
141
+ "pattern": (
142
+ "derivatives/freesurfer/[!f]{subject}/surf/lh.pia[l]"
143
+ )
144
+ },
145
+ "rh_pial": {
146
+ "pattern": (
147
+ "derivatives/freesurfer/[!f]{subject}/surf/rh.pia[l]"
148
+ )
149
+ },
150
+ },
117
151
  }
118
152
  # Use native T1w assets
119
153
  self.native_t1w = False
@@ -127,14 +161,13 @@ class DataladAOMICID1000(PatternDataladDataGrabber):
127
161
  "{subject}_desc-preproc_T1w.nii.gz"
128
162
  ),
129
163
  "space": "native",
130
- "mask_item": "T1w_mask",
131
- },
132
- "T1w_mask": {
133
- "pattern": (
134
- "derivatives/fmriprep/{subject}/anat/"
135
- "{subject}_desc-brain_mask.nii.gz"
136
- ),
137
- "space": "native",
164
+ "mask": {
165
+ "pattern": (
166
+ "derivatives/fmriprep/{subject}/anat/"
167
+ "{subject}_desc-brain_mask.nii.gz"
168
+ ),
169
+ "space": "native",
170
+ },
138
171
  },
139
172
  "Warp": {
140
173
  "pattern": (