junifer 0.0.6.dev219__py3-none-any.whl → 0.0.6.dev248__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 (67) hide show
  1. junifer/__init__.pyi +2 -0
  2. junifer/_version.py +2 -2
  3. junifer/api/decorators.py +5 -4
  4. junifer/api/functions.py +9 -8
  5. junifer/data/coordinates/_ants_coordinates_warper.py +4 -6
  6. junifer/data/coordinates/_coordinates.py +28 -15
  7. junifer/data/coordinates/_fsl_coordinates_warper.py +4 -6
  8. junifer/data/masks/_ants_mask_warper.py +16 -9
  9. junifer/data/masks/_fsl_mask_warper.py +4 -6
  10. junifer/data/masks/_masks.py +21 -25
  11. junifer/data/parcellations/_ants_parcellation_warper.py +16 -9
  12. junifer/data/parcellations/_fsl_parcellation_warper.py +4 -6
  13. junifer/data/parcellations/_parcellations.py +20 -24
  14. junifer/data/utils.py +67 -3
  15. junifer/datagrabber/aomic/id1000.py +22 -9
  16. junifer/datagrabber/aomic/piop1.py +22 -9
  17. junifer/datagrabber/aomic/piop2.py +22 -9
  18. junifer/datagrabber/base.py +6 -1
  19. junifer/datagrabber/datalad_base.py +15 -8
  20. junifer/datagrabber/dmcc13_benchmark.py +23 -10
  21. junifer/datagrabber/hcp1200/hcp1200.py +18 -7
  22. junifer/datagrabber/multiple.py +2 -1
  23. junifer/datagrabber/pattern.py +65 -35
  24. junifer/datagrabber/pattern_validation_mixin.py +197 -87
  25. junifer/datagrabber/tests/test_dmcc13_benchmark.py +26 -9
  26. junifer/markers/base.py +4 -7
  27. junifer/markers/brainprint.py +4 -4
  28. junifer/markers/complexity/complexity_base.py +3 -3
  29. junifer/markers/ets_rss.py +4 -3
  30. junifer/markers/falff/_afni_falff.py +3 -5
  31. junifer/markers/falff/_junifer_falff.py +3 -3
  32. junifer/markers/falff/falff_base.py +4 -6
  33. junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +4 -3
  34. junifer/markers/functional_connectivity/functional_connectivity_base.py +4 -3
  35. junifer/markers/parcel_aggregation.py +4 -3
  36. junifer/markers/reho/_afni_reho.py +3 -5
  37. junifer/markers/reho/_junifer_reho.py +3 -3
  38. junifer/markers/reho/reho_base.py +4 -6
  39. junifer/markers/sphere_aggregation.py +4 -3
  40. junifer/markers/temporal_snr/temporal_snr_base.py +4 -3
  41. junifer/onthefly/_brainprint.py +4 -7
  42. junifer/onthefly/read_transform.py +3 -6
  43. junifer/pipeline/marker_collection.py +6 -12
  44. junifer/pipeline/pipeline_component_registry.py +3 -8
  45. junifer/pipeline/pipeline_step_mixin.py +8 -4
  46. junifer/pipeline/tests/test_pipeline_step_mixin.py +18 -19
  47. junifer/pipeline/tests/test_workdir_manager.py +1 -0
  48. junifer/pipeline/update_meta_mixin.py +21 -17
  49. junifer/preprocess/confounds/fmriprep_confound_remover.py +2 -2
  50. junifer/preprocess/smoothing/_afni_smoothing.py +4 -6
  51. junifer/preprocess/smoothing/_fsl_smoothing.py +4 -7
  52. junifer/preprocess/smoothing/_nilearn_smoothing.py +3 -3
  53. junifer/preprocess/smoothing/smoothing.py +3 -2
  54. junifer/preprocess/warping/_ants_warper.py +26 -7
  55. junifer/preprocess/warping/_fsl_warper.py +22 -8
  56. junifer/preprocess/warping/space_warper.py +34 -6
  57. junifer/preprocess/warping/tests/test_space_warper.py +4 -7
  58. junifer/typing/__init__.py +9 -0
  59. junifer/typing/__init__.pyi +23 -0
  60. junifer/typing/_typing.py +61 -0
  61. {junifer-0.0.6.dev219.dist-info → junifer-0.0.6.dev248.dist-info}/METADATA +2 -1
  62. {junifer-0.0.6.dev219.dist-info → junifer-0.0.6.dev248.dist-info}/RECORD +67 -64
  63. {junifer-0.0.6.dev219.dist-info → junifer-0.0.6.dev248.dist-info}/WHEEL +1 -1
  64. {junifer-0.0.6.dev219.dist-info → junifer-0.0.6.dev248.dist-info}/AUTHORS.rst +0 -0
  65. {junifer-0.0.6.dev219.dist-info → junifer-0.0.6.dev248.dist-info}/LICENSE.md +0 -0
  66. {junifer-0.0.6.dev219.dist-info → junifer-0.0.6.dev248.dist-info}/entry_points.txt +0 -0
  67. {junifer-0.0.6.dev219.dist-info → junifer-0.0.6.dev248.dist-info}/top_level.txt +0 -0
junifer/data/utils.py CHANGED
@@ -4,14 +4,14 @@
4
4
  # Synchon Mandal <s.mandal@fz-juelich.de>
5
5
  # License: AGPL
6
6
 
7
- from typing import List, Optional, Union
7
+ from typing import Dict, List, MutableMapping, Optional, Union
8
8
 
9
9
  import numpy as np
10
10
 
11
- from ..utils.logging import logger
11
+ from ..utils import logger, raise_error
12
12
 
13
13
 
14
- __all__ = ["closest_resolution"]
14
+ __all__ = ["closest_resolution", "get_native_warper"]
15
15
 
16
16
 
17
17
  def closest_resolution(
@@ -49,3 +49,67 @@ def closest_resolution(
49
49
  closest = np.min(valid_resolution)
50
50
 
51
51
  return closest
52
+
53
+
54
+ def get_native_warper(
55
+ target_data: MutableMapping,
56
+ other_data: MutableMapping,
57
+ inverse: bool = False,
58
+ ) -> Dict:
59
+ """Get correct warping specification for native space.
60
+
61
+ Parameters
62
+ ----------
63
+ target_data : dict
64
+ The target data from the pipeline data object.
65
+ other_data : dict
66
+ The other data in the pipeline data object.
67
+ inverse : bool, optional
68
+ Whether to get the inverse warping specification (default False).
69
+
70
+ Returns
71
+ -------
72
+ dict
73
+ The correct warping specification.
74
+
75
+ Raises
76
+ ------
77
+ RuntimeError
78
+ If no warper or multiple possible warpers are found.
79
+
80
+ """
81
+ # Get possible warpers
82
+ possible_warpers = []
83
+ for entry in other_data["Warp"]:
84
+ if not inverse:
85
+ if (
86
+ entry["src"] == target_data["prewarp_space"]
87
+ and entry["dst"] == "native"
88
+ ):
89
+ possible_warpers.append(entry)
90
+ else:
91
+ if (
92
+ entry["dst"] == target_data["prewarp_space"]
93
+ and entry["src"] == "native"
94
+ ):
95
+ possible_warpers.append(entry)
96
+
97
+ # Check for no warper
98
+ if not possible_warpers:
99
+ raise_error(
100
+ klass=RuntimeError,
101
+ msg="Could not find correct warping specification",
102
+ )
103
+
104
+ # Check for multiple possible warpers
105
+ if len(possible_warpers) > 1:
106
+ raise_error(
107
+ klass=RuntimeError,
108
+ msg=(
109
+ "Cannot proceed as multiple warping specification found, "
110
+ "adjust either the DataGrabber or the working space: "
111
+ f"{possible_warpers}"
112
+ ),
113
+ )
114
+
115
+ return possible_warpers[0]
@@ -169,15 +169,28 @@ class DataladAOMICID1000(PatternDataladDataGrabber):
169
169
  "space": "native",
170
170
  },
171
171
  },
172
- "Warp": {
173
- "pattern": (
174
- "derivatives/fmriprep/{subject}/anat/"
175
- "{subject}_from-MNI152NLin2009cAsym_to-T1w_"
176
- "mode-image_xfm.h5"
177
- ),
178
- "src": "MNI152NLin2009cAsym",
179
- "dst": "native",
180
- },
172
+ "Warp": [
173
+ {
174
+ "pattern": (
175
+ "derivatives/fmriprep/{subject}/anat/"
176
+ "{subject}_from-MNI152NLin2009cAsym_to-T1w_"
177
+ "mode-image_xfm.h5"
178
+ ),
179
+ "src": "MNI152NLin2009cAsym",
180
+ "dst": "native",
181
+ "warper": "ants",
182
+ },
183
+ {
184
+ "pattern": (
185
+ "derivatives/fmriprep/{subject}/anat/"
186
+ "{subject}_from-T1w_to-MNI152NLin2009cAsym_"
187
+ "mode-image_xfm.h5"
188
+ ),
189
+ "src": "native",
190
+ "dst": "MNI152NLin2009cAsym",
191
+ "warper": "ants",
192
+ },
193
+ ],
181
194
  }
182
195
  )
183
196
  # Set default types
@@ -204,15 +204,28 @@ class DataladAOMICPIOP1(PatternDataladDataGrabber):
204
204
  "space": "native",
205
205
  },
206
206
  },
207
- "Warp": {
208
- "pattern": (
209
- "derivatives/fmriprep/{subject}/anat/"
210
- "{subject}_from-MNI152NLin2009cAsym_to-T1w_"
211
- "mode-image_xfm.h5"
212
- ),
213
- "src": "MNI152NLin2009cAsym",
214
- "dst": "native",
215
- },
207
+ "Warp": [
208
+ {
209
+ "pattern": (
210
+ "derivatives/fmriprep/{subject}/anat/"
211
+ "{subject}_from-MNI152NLin2009cAsym_to-T1w_"
212
+ "mode-image_xfm.h5"
213
+ ),
214
+ "src": "MNI152NLin2009cAsym",
215
+ "dst": "native",
216
+ "warper": "ants",
217
+ },
218
+ {
219
+ "pattern": (
220
+ "derivatives/fmriprep/{subject}/anat/"
221
+ "{subject}_from-T1w_to-MNI152NLin2009cAsym_"
222
+ "mode-image_xfm.h5"
223
+ ),
224
+ "src": "native",
225
+ "dst": "MNI152NLin2009cAsym",
226
+ "warper": "ants",
227
+ },
228
+ ],
216
229
  }
217
230
  )
218
231
  # Set default types
@@ -202,15 +202,28 @@ class DataladAOMICPIOP2(PatternDataladDataGrabber):
202
202
  "space": "native",
203
203
  },
204
204
  },
205
- "Warp": {
206
- "pattern": (
207
- "derivatives/fmriprep/{subject}/anat/"
208
- "{subject}_from-MNI152NLin2009cAsym_to-T1w_"
209
- "mode-image_xfm.h5"
210
- ),
211
- "src": "MNI152NLin2009cAsym",
212
- "dst": "native",
213
- },
205
+ "Warp": [
206
+ {
207
+ "pattern": (
208
+ "derivatives/fmriprep/{subject}/anat/"
209
+ "{subject}_from-MNI152NLin2009cAsym_to-T1w_"
210
+ "mode-image_xfm.h5"
211
+ ),
212
+ "src": "MNI152NLin2009cAsym",
213
+ "dst": "native",
214
+ "warper": "ants",
215
+ },
216
+ {
217
+ "pattern": (
218
+ "derivatives/fmriprep/{subject}/anat/"
219
+ "{subject}_from-T1w_to-MNI152NLin2009cAsym_"
220
+ "mode-image_xfm.h5"
221
+ ),
222
+ "src": "native",
223
+ "dst": "MNI152NLin2009cAsym",
224
+ "warper": "ants",
225
+ },
226
+ ],
214
227
  }
215
228
  )
216
229
  # Set default types
@@ -96,7 +96,12 @@ class BaseDataGrabber(ABC, UpdateMetaMixin):
96
96
  # Update metadata
97
97
  for _, t_val in out.items():
98
98
  self.update_meta(t_val, "datagrabber")
99
- t_val["meta"]["element"] = named_element
99
+ # Conditional for list dtype vals like Warp
100
+ if isinstance(t_val, list):
101
+ for entry in t_val:
102
+ entry["meta"]["element"] = named_element
103
+ else:
104
+ t_val["meta"]["element"] = named_element
100
105
 
101
106
  return out
102
107
 
@@ -181,14 +181,21 @@ class DataladDataGrabber(BaseDataGrabber):
181
181
  """
182
182
  to_get = []
183
183
  for type_val in out.values():
184
- # Iterate to check for nested "types" like mask
185
- for k, v in type_val.items():
186
- # Add base data type path
187
- if k == "path":
188
- to_get.append(v)
189
- # Add nested data type path
190
- if isinstance(v, dict) and "path" in v:
191
- to_get.append(v["path"])
184
+ # Conditional for list dtype vals like Warp
185
+ if isinstance(type_val, list):
186
+ for entry in type_val:
187
+ for k, v in entry.items():
188
+ if k == "path":
189
+ to_get.append(v)
190
+ else:
191
+ # Iterate to check for nested "types" like mask
192
+ for k, v in type_val.items():
193
+ # Add base data type path
194
+ if k == "path":
195
+ to_get.append(v)
196
+ # Add nested data type path
197
+ if isinstance(v, dict) and "path" in v:
198
+ to_get.append(v["path"])
192
199
 
193
200
  if len(to_get) > 0:
194
201
  logger.debug(f"Getting {len(to_get)} files using datalad:")
@@ -150,7 +150,7 @@ class DMCC13Benchmark(PatternDataladDataGrabber):
150
150
  "mask": {
151
151
  "pattern": (
152
152
  "derivatives/fmriprep-1.3.2/{subject}/{session}/"
153
- "/func/{subject}_{session}_task-{task}_acq-mb4"
153
+ "func/{subject}_{session}_task-{task}_acq-mb4"
154
154
  "{phase_encoding}_run-{run}_"
155
155
  "space-MNI152NLin2009cAsym_desc-brain_mask.nii.gz"
156
156
  ),
@@ -221,15 +221,28 @@ class DMCC13Benchmark(PatternDataladDataGrabber):
221
221
  "space": "native",
222
222
  },
223
223
  },
224
- "Warp": {
225
- "pattern": (
226
- "derivatives/fmriprep-1.3.2/{subject}/anat/"
227
- "{subject}_from-MNI152NLin2009cAsym_to-T1w_"
228
- "mode-image_xfm.h5"
229
- ),
230
- "src": "MNI152NLin2009cAsym",
231
- "dst": "native",
232
- },
224
+ "Warp": [
225
+ {
226
+ "pattern": (
227
+ "derivatives/fmriprep-1.3.2/{subject}/anat/"
228
+ "{subject}_from-MNI152NLin2009cAsym_to-T1w_"
229
+ "mode-image_xfm.h5"
230
+ ),
231
+ "src": "MNI152NLin2009cAsym",
232
+ "dst": "native",
233
+ "warper": "ants",
234
+ },
235
+ {
236
+ "pattern": (
237
+ "derivatives/fmriprep-1.3.2/{subject}/anat/"
238
+ "{subject}_from-T1w_to-MNI152NLin2009cAsym_"
239
+ "mode-image_xfm.h5"
240
+ ),
241
+ "src": "native",
242
+ "dst": "MNI152NLin2009cAsym",
243
+ "warper": "ants",
244
+ },
245
+ ],
233
246
  }
234
247
  )
235
248
  # Set default types
@@ -122,13 +122,24 @@ class HCP1200(PatternDataGrabber):
122
122
  "pattern": "{subject}/T1w/T1w_acpc_dc_restore.nii.gz",
123
123
  "space": "native",
124
124
  },
125
- "Warp": {
126
- "pattern": (
127
- "{subject}/MNINonLinear/xfms/standard2acpc_dc.nii.gz"
128
- ),
129
- "src": "MNI152NLin6Asym",
130
- "dst": "native",
131
- },
125
+ "Warp": [
126
+ {
127
+ "pattern": (
128
+ "{subject}/MNINonLinear/xfms/standard2acpc_dc.nii.gz"
129
+ ),
130
+ "src": "MNI152NLin6Asym",
131
+ "dst": "native",
132
+ "warper": "fsl",
133
+ },
134
+ {
135
+ "pattern": (
136
+ "{subject}/MNINonLinear/xfms/acpc_dc2standard.nii.gz"
137
+ ),
138
+ "src": "native",
139
+ "dst": "MNI152NLin6Asym",
140
+ "warper": "fsl",
141
+ },
142
+ ],
132
143
  }
133
144
  # The replacements
134
145
  replacements = ["subject", "task", "phase_encoding"]
@@ -8,6 +8,7 @@
8
8
  from typing import Dict, List, Tuple, Union
9
9
 
10
10
  from ..api.decorators import register_datagrabber
11
+ from ..typing import DataGrabberLike
11
12
  from ..utils import deep_update, raise_error
12
13
  from .base import BaseDataGrabber
13
14
 
@@ -37,7 +38,7 @@ class MultipleDataGrabber(BaseDataGrabber):
37
38
 
38
39
  """
39
40
 
40
- def __init__(self, datagrabbers: List[BaseDataGrabber], **kwargs) -> None:
41
+ def __init__(self, datagrabbers: List[DataGrabberLike], **kwargs) -> None:
41
42
  # Check datagrabbers consistency
42
43
  # Check for same element keys
43
44
  first_keys = datagrabbers[0].get_element_keys()
@@ -89,7 +89,7 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
89
89
  .. code-block:: none
90
90
 
91
91
  {
92
- "mandatory": ["pattern", "src", "dst"],
92
+ "mandatory": ["pattern", "src", "dst", "warper"],
93
93
  "optional": []
94
94
  }
95
95
 
@@ -127,11 +127,22 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
127
127
  "pattern": "...",
128
128
  "space": "...",
129
129
  },
130
- "Warp": {
131
- "pattern": "...",
132
- "src": "...",
133
- "dst": "...",
134
- }
130
+ }
131
+
132
+ except ``Warp``, which needs to be a list of dictionaries as there can
133
+ be multiple spaces to warp (for example, with fMRIPrep):
134
+
135
+ .. code-block:: none
136
+
137
+ {
138
+ "Warp": [
139
+ {
140
+ "pattern": "...",
141
+ "src": "...",
142
+ "dst": "...",
143
+ "warper": "...",
144
+ },
145
+ ],
135
146
  }
136
147
 
137
148
  taken from :class:`.HCP1200`.
@@ -380,42 +391,61 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
380
391
  t_pattern = self.patterns[t_type]
381
392
  # Copy data type dictionary in output
382
393
  out[t_type] = deepcopy(t_pattern)
383
- # Iterate to check for nested "types" like mask
384
- for k, v in t_pattern.items():
385
- # Resolve pattern for base data type
386
- if k == "pattern":
387
- logger.info(f"Resolving path from pattern for {t_type}")
394
+ # Conditional for list dtype vals like Warp
395
+ if isinstance(t_pattern, list):
396
+ for idx, entry in enumerate(t_pattern):
397
+ logger.info(
398
+ f"Resolving path from pattern for {t_type}.{idx}"
399
+ )
388
400
  # Resolve pattern
389
- base_data_type_pattern_path = self._get_path_from_patterns(
401
+ dtype_pattern_path = self._get_path_from_patterns(
390
402
  element=element,
391
- pattern=v,
392
- data_type=t_type,
403
+ pattern=entry["pattern"],
404
+ data_type=f"{t_type}.{idx}",
393
405
  )
394
406
  # Remove pattern key
395
- out[t_type].pop("pattern")
407
+ out[t_type][idx].pop("pattern")
396
408
  # Add path key
397
- out[t_type].update({"path": base_data_type_pattern_path})
398
- # Resolve pattern for nested data type
399
- if isinstance(v, dict) and "pattern" in v:
400
- # Set nested type key for easier access
401
- t_nested_type = f"{t_type}.{k}"
402
- logger.info(
403
- f"Resolving path from pattern for {t_nested_type}"
404
- )
405
- # Resolve pattern
406
- nested_data_type_pattern_path = (
407
- self._get_path_from_patterns(
409
+ out[t_type][idx].update({"path": dtype_pattern_path})
410
+ else:
411
+ # Iterate to check for nested "types" like mask
412
+ for k, v in t_pattern.items():
413
+ # Resolve pattern for base data type
414
+ if k == "pattern":
415
+ logger.info(
416
+ f"Resolving path from pattern for {t_type}"
417
+ )
418
+ # Resolve pattern
419
+ base_dtype_pattern_path = self._get_path_from_patterns(
408
420
  element=element,
409
- pattern=v["pattern"],
410
- data_type=t_nested_type,
421
+ pattern=v,
422
+ data_type=t_type,
423
+ )
424
+ # Remove pattern key
425
+ out[t_type].pop("pattern")
426
+ # Add path key
427
+ out[t_type].update({"path": base_dtype_pattern_path})
428
+ # Resolve pattern for nested data type
429
+ if isinstance(v, dict) and "pattern" in v:
430
+ # Set nested type key for easier access
431
+ t_nested_type = f"{t_type}.{k}"
432
+ logger.info(
433
+ f"Resolving path from pattern for {t_nested_type}"
434
+ )
435
+ # Resolve pattern
436
+ nested_dtype_pattern_path = (
437
+ self._get_path_from_patterns(
438
+ element=element,
439
+ pattern=v["pattern"],
440
+ data_type=t_nested_type,
441
+ )
442
+ )
443
+ # Remove pattern key
444
+ out[t_type][k].pop("pattern")
445
+ # Add path key
446
+ out[t_type][k].update(
447
+ {"path": nested_dtype_pattern_path}
411
448
  )
412
- )
413
- # Remove pattern key
414
- out[t_type][k].pop("pattern")
415
- # Add path key
416
- out[t_type][k].update(
417
- {"path": nested_data_type_pattern_path}
418
- )
419
449
 
420
450
  return out
421
451