junifer 0.0.7.dev132__py3-none-any.whl → 0.0.7.dev169__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 (37) hide show
  1. junifer/_version.py +2 -2
  2. junifer/conftest.py +32 -0
  3. junifer/data/__init__.pyi +2 -0
  4. junifer/data/_dispatch.py +11 -7
  5. junifer/data/maps/__init__.py +9 -0
  6. junifer/data/maps/__init__.pyi +5 -0
  7. junifer/data/maps/_ants_maps_warper.py +156 -0
  8. junifer/data/maps/_fsl_maps_warper.py +85 -0
  9. junifer/data/maps/_maps.py +446 -0
  10. junifer/data/maps/tests/test_maps.py +255 -0
  11. junifer/data/masks/_masks.py +3 -2
  12. junifer/data/parcellations/_parcellations.py +1 -1
  13. junifer/markers/__init__.pyi +12 -2
  14. junifer/markers/falff/__init__.pyi +2 -1
  15. junifer/markers/falff/falff_maps.py +151 -0
  16. junifer/markers/falff/tests/test_falff_maps.py +167 -0
  17. junifer/markers/functional_connectivity/__init__.pyi +4 -0
  18. junifer/markers/functional_connectivity/edge_functional_connectivity_maps.py +115 -0
  19. junifer/markers/functional_connectivity/functional_connectivity_maps.py +95 -0
  20. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_maps.py +74 -0
  21. junifer/markers/functional_connectivity/tests/test_functional_connectivity_maps.py +110 -0
  22. junifer/markers/maps_aggregation.py +201 -0
  23. junifer/markers/reho/__init__.pyi +2 -1
  24. junifer/markers/reho/reho_maps.py +161 -0
  25. junifer/markers/reho/tests/test_reho_maps.py +135 -0
  26. junifer/markers/temporal_snr/__init__.pyi +2 -1
  27. junifer/markers/temporal_snr/temporal_snr_maps.py +80 -0
  28. junifer/markers/temporal_snr/tests/test_temporal_snr_maps.py +67 -0
  29. junifer/markers/tests/test_maps_aggregation.py +430 -0
  30. junifer/typing/_typing.py +1 -3
  31. {junifer-0.0.7.dev132.dist-info → junifer-0.0.7.dev169.dist-info}/METADATA +2 -2
  32. {junifer-0.0.7.dev132.dist-info → junifer-0.0.7.dev169.dist-info}/RECORD +37 -19
  33. {junifer-0.0.7.dev132.dist-info → junifer-0.0.7.dev169.dist-info}/WHEEL +0 -0
  34. {junifer-0.0.7.dev132.dist-info → junifer-0.0.7.dev169.dist-info}/entry_points.txt +0 -0
  35. {junifer-0.0.7.dev132.dist-info → junifer-0.0.7.dev169.dist-info}/licenses/AUTHORS.rst +0 -0
  36. {junifer-0.0.7.dev132.dist-info → junifer-0.0.7.dev169.dist-info}/licenses/LICENSE.md +0 -0
  37. {junifer-0.0.7.dev132.dist-info → junifer-0.0.7.dev169.dist-info}/top_level.txt +0 -0
junifer/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.0.7.dev132'
32
- __version_tuple__ = version_tuple = (0, 0, 7, 'dev132')
31
+ __version__ = version = '0.0.7.dev169'
32
+ __version_tuple__ = version_tuple = (0, 0, 7, 'dev169')
33
33
 
34
34
  __commit_id__ = commit_id = None
junifer/conftest.py CHANGED
@@ -1,10 +1,14 @@
1
1
  """Provide conftest for pytest."""
2
2
 
3
3
  # Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
4
+ # Synchon Mandal <s.mandal@fz-juelich.de>
4
5
  # License: AGPL
5
6
 
7
+ from pathlib import Path
8
+
6
9
  import pytest
7
10
 
11
+ from junifer.datagrabber import PatternDataladDataGrabber
8
12
  from junifer.utils.singleton import Singleton
9
13
 
10
14
 
@@ -23,3 +27,31 @@ def reset_singletons() -> None:
23
27
  # Force deleting the singletons
24
28
  for elem in to_remove:
25
29
  del elem
30
+
31
+
32
+ @pytest.fixture
33
+ def maps_datagrabber(tmp_path: Path) -> PatternDataladDataGrabber:
34
+ """Return a PatternDataladDataGrabber for maps testing.
35
+
36
+ Parameters
37
+ ----------
38
+ tmp_path : pathlib.Path
39
+ The path to the test directory.
40
+
41
+ """
42
+ dg = PatternDataladDataGrabber(
43
+ uri="https://github.com/OpenNeuroDatasets/ds005226.git",
44
+ types=["BOLD"],
45
+ patterns={
46
+ "BOLD": {
47
+ "pattern": (
48
+ "derivatives/pre-processed_data/space-MNI/{subject}/"
49
+ "{subject-padded}_task-{task}_run-{run}_space-MNI152NLin6Asym"
50
+ "_res-2_desc-preproc_bold.nii.gz"
51
+ ),
52
+ "space": "MNI152NLin6Asym",
53
+ },
54
+ },
55
+ replacements=["subject", "subject-padded", "task", "run"],
56
+ )
57
+ return dg
junifer/data/__init__.pyi CHANGED
@@ -3,6 +3,7 @@ __all__ = [
3
3
  "CoordinatesRegistry",
4
4
  "DataDispatcher",
5
5
  "ParcellationRegistry",
6
+ "MapsRegistry",
6
7
  "MaskRegistry",
7
8
  "get_data",
8
9
  "list_data",
@@ -17,6 +18,7 @@ __all__ = [
17
18
  from .pipeline_data_registry_base import BasePipelineDataRegistry
18
19
  from .coordinates import CoordinatesRegistry
19
20
  from .parcellations import ParcellationRegistry
21
+ from .maps import MapsRegistry
20
22
  from .masks import MaskRegistry
21
23
 
22
24
  from ._dispatch import (
junifer/data/_dispatch.py CHANGED
@@ -17,6 +17,7 @@ from numpy.typing import ArrayLike
17
17
 
18
18
  from ..utils import raise_error
19
19
  from .coordinates import CoordinatesRegistry
20
+ from .maps import MapsRegistry
20
21
  from .masks import MaskRegistry
21
22
  from .parcellations import ParcellationRegistry
22
23
  from .pipeline_data_registry_base import BasePipelineDataRegistry
@@ -52,6 +53,7 @@ class DataDispatcher(MutableMapping):
52
53
  {
53
54
  "coordinates": CoordinatesRegistry,
54
55
  "parcellation": ParcellationRegistry,
56
+ "maps": MapsRegistry,
55
57
  "mask": MaskRegistry,
56
58
  }
57
59
  )
@@ -118,14 +120,14 @@ def get_data(
118
120
  extra_input: Optional[dict[str, Any]] = None,
119
121
  ) -> Union[
120
122
  tuple[ArrayLike, list[str]], # coordinates
121
- tuple["Nifti1Image", list[str]], # parcellation
123
+ tuple["Nifti1Image", list[str]], # parcellation / maps
122
124
  "Nifti1Image", # mask
123
125
  ]:
124
126
  """Get tailored ``kind`` for ``target_data``.
125
127
 
126
128
  Parameters
127
129
  ----------
128
- kind : {"coordinates", "parcellation", "mask"}
130
+ kind : {"coordinates", "parcellation", "mask", "maps"}
129
131
  Kind of data to fetch and apply.
130
132
  names : str or dict or list of str / dict
131
133
  The registered name(s) of the data.
@@ -166,7 +168,7 @@ def list_data(kind: str) -> list[str]:
166
168
 
167
169
  Parameters
168
170
  ----------
169
- kind : {"coordinates", "parcellation", "mask"}
171
+ kind : {"coordinates", "parcellation", "mask", "maps"}
170
172
  Kind of data registry to list.
171
173
 
172
174
  Returns
@@ -195,7 +197,9 @@ def load_data(
195
197
  **kwargs,
196
198
  ) -> Union[
197
199
  tuple[ArrayLike, list[str], str], # coordinates
198
- tuple[Optional["Nifti1Image"], list[str], Path, str], # parcellation
200
+ tuple[
201
+ Optional["Nifti1Image"], list[str], Path, str
202
+ ], # parcellation / maps
199
203
  tuple[
200
204
  Optional[Union["Nifti1Image", Callable]], Optional[Path], str
201
205
  ], # mask
@@ -204,7 +208,7 @@ def load_data(
204
208
 
205
209
  Parameters
206
210
  ----------
207
- kind : {"coordinates", "parcellation", "mask"}
211
+ kind : {"coordinates", "parcellation", "mask", "maps"}
208
212
  Kind of data to load.
209
213
  name : str
210
214
  The registered name of the data.
@@ -244,7 +248,7 @@ def register_data(
244
248
 
245
249
  Parameters
246
250
  ----------
247
- kind : {"coordinates", "parcellation", "mask"}
251
+ kind : {"coordinates", "parcellation", "mask", "maps"}
248
252
  Kind of data to register.
249
253
  name : str
250
254
  The name to register.
@@ -277,7 +281,7 @@ def deregister_data(kind: str, name: str) -> None:
277
281
 
278
282
  Parameters
279
283
  ----------
280
- kind : {"coordinates", "parcellation", "mask"}
284
+ kind : {"coordinates", "parcellation", "mask", "maps"}
281
285
  Kind of data to register.
282
286
  name : str
283
287
  The name to de-register.
@@ -0,0 +1,9 @@
1
+ """Maps."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ import lazy_loader as lazy
7
+
8
+
9
+ __getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
@@ -0,0 +1,5 @@
1
+ __all__ = [
2
+ "MapsRegistry",
3
+ ]
4
+
5
+ from ._maps import MapsRegistry
@@ -0,0 +1,156 @@
1
+ """Provide class for maps space warping via ANTs."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ import uuid
7
+ from typing import TYPE_CHECKING, Any, Optional
8
+
9
+ import nibabel as nib
10
+
11
+ from ...pipeline import WorkDirManager
12
+ from ...utils import logger, raise_error, run_ext_cmd
13
+ from ..template_spaces import get_template, get_xfm
14
+
15
+
16
+ if TYPE_CHECKING:
17
+ from nibabel.nifti1 import Nifti1Image
18
+
19
+
20
+ __all__ = ["ANTsMapsWarper"]
21
+
22
+
23
+ class ANTsMapsWarper:
24
+ """Class for maps space warping via ANTs.
25
+
26
+ This class uses ANTs ``antsApplyTransforms`` for transformation.
27
+
28
+ """
29
+
30
+ def warp(
31
+ self,
32
+ maps_name: str,
33
+ maps_img: "Nifti1Image",
34
+ src: str,
35
+ dst: str,
36
+ target_data: dict[str, Any],
37
+ warp_data: Optional[dict[str, Any]],
38
+ ) -> "Nifti1Image":
39
+ """Warp ``maps_img`` to correct space.
40
+
41
+ Parameters
42
+ ----------
43
+ maps_name : str
44
+ The name of the maps.
45
+ maps_img : nibabel.nifti1.Nifti1Image
46
+ The maps image to transform.
47
+ src : str
48
+ The data type or template space to warp from.
49
+ It should be empty string if ``dst="T1w"``.
50
+ dst : str
51
+ The data type or template space to warp to.
52
+ `"T1w"` is the only allowed data type and it uses the resampled T1w
53
+ found in ``target_data.reference``. The ``"reference"``
54
+ key is added if the :class:`.SpaceWarper` is used or if the
55
+ data is provided in native space.
56
+ target_data : dict
57
+ The corresponding item of the data object to which the maps
58
+ will be applied.
59
+ warp_data : dict or None
60
+ The warp data item of the data object. The value is unused if
61
+ ``dst!="T1w"``.
62
+
63
+ Returns
64
+ -------
65
+ nibabel.nifti1.Nifti1Image
66
+ The transformed maps image.
67
+
68
+ Raises
69
+ ------
70
+ ValueError
71
+ If ``warp_data`` is None when ``dst="T1w"``.
72
+
73
+ """
74
+ # Create element-scoped tempdir so that warped maps is
75
+ # available later as nibabel stores file path reference for
76
+ # loading on computation
77
+ prefix = (
78
+ f"ants_maps_warper_{maps_name}"
79
+ f"{'' if not src else f'_from_{src}'}_to_{dst}_"
80
+ f"{uuid.uuid1()}"
81
+ )
82
+ element_tempdir = WorkDirManager().get_element_tempdir(
83
+ prefix=prefix,
84
+ )
85
+
86
+ # Native space warping
87
+ if dst == "native": # pragma: no cover
88
+ # Warp data check
89
+ if warp_data is None:
90
+ raise_error("No `warp_data` provided")
91
+ if "reference" not in target_data:
92
+ raise_error("No `reference` provided")
93
+ if "path" not in target_data["reference"]:
94
+ raise_error("No `path` provided in `reference`")
95
+
96
+ logger.debug("Using ANTs for maps transformation")
97
+
98
+ # Save existing maps image to a tempfile
99
+ prewarp_maps_path = element_tempdir / "prewarp_maps.nii.gz"
100
+ nib.save(maps_img, prewarp_maps_path)
101
+
102
+ # Create a tempfile for warped output
103
+ warped_maps_path = element_tempdir / "maps_warped.nii.gz"
104
+ # Set antsApplyTransforms command
105
+ apply_transforms_cmd = [
106
+ "antsApplyTransforms",
107
+ "-d 3",
108
+ "-e 3",
109
+ "-n LanczosWindowedSinc",
110
+ f"-i {prewarp_maps_path.resolve()}",
111
+ # use resampled reference
112
+ f"-r {target_data['reference']['path'].resolve()}",
113
+ f"-t {warp_data['path'].resolve()}",
114
+ f"-o {warped_maps_path.resolve()}",
115
+ ]
116
+ # Call antsApplyTransforms
117
+ run_ext_cmd(name="antsApplyTransforms", cmd=apply_transforms_cmd)
118
+
119
+ # Template space warping
120
+ else:
121
+ logger.debug(f"Using ANTs to warp maps from {src} to {dst}")
122
+
123
+ # Get xfm file
124
+ xfm_file_path = get_xfm(src=src, dst=dst)
125
+ # Get template space image
126
+ template_space_img = get_template(
127
+ space=dst,
128
+ target_img=maps_img,
129
+ extra_input=None,
130
+ )
131
+ # Save template to a tempfile
132
+ template_space_img_path = element_tempdir / f"{dst}_T1w.nii.gz"
133
+ nib.save(template_space_img, template_space_img_path)
134
+
135
+ # Save existing maps image to a tempfile
136
+ prewarp_maps_path = element_tempdir / "prewarp_maps.nii.gz"
137
+ nib.save(maps_img, prewarp_maps_path)
138
+
139
+ # Create a tempfile for warped output
140
+ warped_maps_path = element_tempdir / "maps_warped.nii.gz"
141
+ # Set antsApplyTransforms command
142
+ apply_transforms_cmd = [
143
+ "antsApplyTransforms",
144
+ "-d 3",
145
+ "-e 3",
146
+ "-n LanczosWindowedSinc",
147
+ f"-i {prewarp_maps_path.resolve()}",
148
+ f"-r {template_space_img_path.resolve()}",
149
+ f"-t {xfm_file_path.resolve()}",
150
+ f"-o {warped_maps_path.resolve()}",
151
+ ]
152
+ # Call antsApplyTransforms
153
+ run_ext_cmd(name="antsApplyTransforms", cmd=apply_transforms_cmd)
154
+
155
+ # Load nifti
156
+ return nib.load(warped_maps_path)
@@ -0,0 +1,85 @@
1
+ """Provide class for maps space warping via FSL FLIRT."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ import uuid
7
+ from typing import TYPE_CHECKING, Any
8
+
9
+ import nibabel as nib
10
+
11
+ from ...pipeline import WorkDirManager
12
+ from ...utils import logger, run_ext_cmd
13
+
14
+
15
+ if TYPE_CHECKING:
16
+ from nibabel.nifti1 import Nifti1Image
17
+
18
+
19
+ __all__ = ["FSLMapsWarper"]
20
+
21
+
22
+ class FSLMapsWarper:
23
+ """Class for maps space warping via FSL FLIRT.
24
+
25
+ This class uses FSL FLIRT's ``applywarp`` for transformation.
26
+
27
+ """
28
+
29
+ def warp(
30
+ self,
31
+ maps_name: str,
32
+ maps_img: "Nifti1Image",
33
+ target_data: dict[str, Any],
34
+ warp_data: dict[str, Any],
35
+ ) -> "Nifti1Image": # pragma: no cover
36
+ """Warp ``maps_img`` to correct space.
37
+
38
+ Parameters
39
+ ----------
40
+ maps_name : str
41
+ The name of the maps.
42
+ maps_img : nibabel.nifti1.Nifti1Image
43
+ The maps image to transform.
44
+ target_data : dict
45
+ The corresponding item of the data object to which the maps
46
+ will be applied.
47
+ warp_data : dict
48
+ The warp data item of the data object.
49
+
50
+ Returns
51
+ -------
52
+ nibabel.nifti1.Nifti1Image
53
+ The transformed maps image.
54
+
55
+ """
56
+ logger.debug("Using FSL for maps transformation")
57
+
58
+ # Create element-scoped tempdir so that warped maps is
59
+ # available later as nibabel stores file path reference for
60
+ # loading on computation
61
+ element_tempdir = WorkDirManager().get_element_tempdir(
62
+ prefix=f"fsl_maps_warper_{maps_name}_{uuid.uuid1()}"
63
+ )
64
+
65
+ # Save existing maps image to a tempfile
66
+ prewarp_maps_path = element_tempdir / "prewarp_maps.nii.gz"
67
+ nib.save(maps_img, prewarp_maps_path)
68
+
69
+ # Create a tempfile for warped output
70
+ warped_maps_path = element_tempdir / "maps_warped.nii.gz"
71
+ # Set applywarp command
72
+ applywarp_cmd = [
73
+ "applywarp",
74
+ "--interp=spline",
75
+ f"-i {prewarp_maps_path.resolve()}",
76
+ # use resampled reference
77
+ f"-r {target_data['reference']['path'].resolve()}",
78
+ f"-w {warp_data['path'].resolve()}",
79
+ f"-o {warped_maps_path.resolve()}",
80
+ ]
81
+ # Call applywarp
82
+ run_ext_cmd(name="applywarp", cmd=applywarp_cmd)
83
+
84
+ # Load nifti
85
+ return nib.load(warped_maps_path)