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
@@ -0,0 +1,446 @@
1
+ """Provide a class for centralized maps data registry."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ from pathlib import Path
7
+ from typing import TYPE_CHECKING, Any, Optional, Union
8
+
9
+ import nibabel as nib
10
+ import nilearn.image as nimg
11
+ import numpy as np
12
+ from junifer_data import get
13
+
14
+ from ...utils import logger, raise_error
15
+ from ..pipeline_data_registry_base import BasePipelineDataRegistry
16
+ from ..utils import (
17
+ JUNIFER_DATA_PARAMS,
18
+ closest_resolution,
19
+ get_dataset_path,
20
+ get_native_warper,
21
+ )
22
+ from ._ants_maps_warper import ANTsMapsWarper
23
+ from ._fsl_maps_warper import FSLMapsWarper
24
+
25
+
26
+ if TYPE_CHECKING:
27
+ from nibabel.nifti1 import Nifti1Image
28
+
29
+
30
+ __all__ = ["MapsRegistry"]
31
+
32
+
33
+ class MapsRegistry(BasePipelineDataRegistry):
34
+ """Class for maps data registry.
35
+
36
+ This class is a singleton and is used for managing available maps
37
+ data in a centralized manner.
38
+
39
+ """
40
+
41
+ def __init__(self) -> None:
42
+ """Initialize the class."""
43
+ super().__init__()
44
+ # Each entry in registry is a dictionary that must contain at least
45
+ # the following keys:
46
+ # * 'family': the maps' family name (e.g., 'Smith')
47
+ # * 'space': the maps' space (e.g., 'MNI')
48
+ # and can also have optional key(s):
49
+ # * 'valid_resolutions': a list of valid resolutions for the
50
+ # maps (e.g., [1, 2])
51
+ # The built-in maps are files that are shipped with the
52
+ # junifer-data dataset.
53
+ # Make built-in and external dictionaries for validation later
54
+ self._builtin = {}
55
+ self._external = {}
56
+
57
+ # Add Smith
58
+ for comp in ["rsn", "bm"]:
59
+ for dim in [10, 20, 70]:
60
+ self._builtin.update(
61
+ {
62
+ f"Smith_{comp}_{dim}": {
63
+ "family": "Smith2009",
64
+ "components": comp,
65
+ "dimension": dim,
66
+ "space": "MNI152NLin6Asym",
67
+ }
68
+ }
69
+ )
70
+
71
+ # Update registry with built-in ones
72
+ self._registry.update(self._builtin)
73
+
74
+ def register(
75
+ self,
76
+ name: str,
77
+ maps_path: Union[str, Path],
78
+ maps_labels: list[str],
79
+ space: str,
80
+ overwrite: bool = False,
81
+ ) -> None:
82
+ """Register a custom user map(s).
83
+
84
+ Parameters
85
+ ----------
86
+ name : str
87
+ The name of the map(s).
88
+ maps_path : str or pathlib.Path
89
+ The path to the map(s) file.
90
+ maps_labels : list of str
91
+ The list of labels for the map(s).
92
+ space : str
93
+ The template space of the map(s), e.g., "MNI152NLin6Asym".
94
+ overwrite : bool, optional
95
+ If True, overwrite an existing maps with the same name.
96
+ Does not apply to built-in maps (default False).
97
+
98
+ Raises
99
+ ------
100
+ ValueError
101
+ If the map(s) ``name`` is a built-in map(s) or
102
+ if the map(s) ``name`` is already registered and
103
+ ``overwrite=False``.
104
+
105
+ """
106
+ # Check for attempt of overwriting built-in maps
107
+ if name in self._builtin:
108
+ raise_error(
109
+ f"Map(s): {name} already registered as built-in map(s)."
110
+ )
111
+ # Check for attempt of overwriting external maps
112
+ if name in self._external:
113
+ if overwrite:
114
+ logger.info(f"Overwriting map(s): {name}")
115
+ else:
116
+ raise_error(
117
+ f"Map(s): {name} already registered. Set "
118
+ "`overwrite=True` to update its value."
119
+ )
120
+ # Convert str to Path
121
+ if not isinstance(maps_path, Path):
122
+ maps_path = Path(maps_path)
123
+ # Registration
124
+ logger.info(f"Registering map(s): {name}")
125
+ # Add user maps info
126
+ self._external[name] = {
127
+ "path": maps_path,
128
+ "labels": maps_labels,
129
+ "family": "CustomUserMaps",
130
+ "space": space,
131
+ }
132
+ # Update registry
133
+ self._registry[name] = {
134
+ "path": maps_path,
135
+ "labels": maps_labels,
136
+ "family": "CustomUserMaps",
137
+ "space": space,
138
+ }
139
+
140
+ def deregister(self, name: str) -> None:
141
+ """De-register a custom user map(s).
142
+
143
+ Parameters
144
+ ----------
145
+ name : str
146
+ The name of the map(s).
147
+
148
+ """
149
+ logger.info(f"De-registering map(s): {name}")
150
+ # Remove maps info
151
+ _ = self._external.pop(name)
152
+ # Update registry
153
+ _ = self._registry.pop(name)
154
+
155
+ def load(
156
+ self,
157
+ name: str,
158
+ target_space: str,
159
+ resolution: Optional[float] = None,
160
+ path_only: bool = False,
161
+ ) -> tuple[Optional["Nifti1Image"], list[str], Path, str]:
162
+ """Load map(s) and labels.
163
+
164
+ Parameters
165
+ ----------
166
+ name : str
167
+ The name of the map(s).
168
+ target_space : str
169
+ The desired space of the map(s).
170
+ resolution : float, optional
171
+ The desired resolution of the map(s) to load. If it is not
172
+ available, the closest resolution will be loaded. Preferably, use a
173
+ resolution higher than the desired one. By default, will load the
174
+ highest one (default None).
175
+ path_only : bool, optional
176
+ If True, the map(s) image will not be loaded (default False).
177
+
178
+ Returns
179
+ -------
180
+ Nifti1Image or None
181
+ Loaded map(s) image.
182
+ list of str
183
+ Map(s) labels.
184
+ pathlib.Path
185
+ File path to the map(s) image.
186
+ str
187
+ The space of the map(s).
188
+
189
+ Raises
190
+ ------
191
+ ValueError
192
+ If ``name`` is invalid or
193
+ if the map(s) family is invalid or
194
+ if the map(s) values and labels
195
+ don't have equal dimension or if the value range is invalid.
196
+
197
+ """
198
+ # Check for valid maps name
199
+ if name not in self._registry:
200
+ raise_error(
201
+ f"Map(s): {name} not found. Valid options are: {self.list}"
202
+ )
203
+
204
+ # Copy maps definition to avoid edits in original object
205
+ maps_def = self._registry[name].copy()
206
+ t_family = maps_def.pop("family")
207
+ space = maps_def.pop("space")
208
+
209
+ # Check and get highest resolution
210
+ if space != target_space:
211
+ logger.info(
212
+ f"Map(s) will be warped from {space} to {target_space} "
213
+ "using highest resolution"
214
+ )
215
+ resolution = None
216
+
217
+ # Check if the maps family is custom or built-in
218
+ if t_family == "CustomUserMaps":
219
+ maps_fname = maps_def["path"]
220
+ maps_labels = maps_def["labels"]
221
+ elif t_family in [
222
+ "Smith2009",
223
+ ]:
224
+ # Load maps and labels
225
+ if t_family == "Smith2009":
226
+ maps_fname, maps_labels = _retrieve_smith(
227
+ resolution=resolution,
228
+ **maps_def,
229
+ )
230
+ else: # pragma: no cover
231
+ raise_error(f"Unknown map(s) family: {t_family}")
232
+
233
+ # Load maps image and values
234
+ logger.info(f"Loading map(s): {maps_fname.absolute()!s}")
235
+ maps_img = None
236
+ if not path_only:
237
+ # Load image via nibabel
238
+ maps_img = nib.load(maps_fname)
239
+ # Get regions
240
+ maps_regions = maps_img.get_fdata().shape[-1]
241
+ # Check for dimension
242
+ if maps_regions != len(maps_labels):
243
+ raise_error(
244
+ f"Map(s) {name} has {maps_regions} "
245
+ f"regions but {len(maps_labels)} labels."
246
+ )
247
+
248
+ return maps_img, maps_labels, maps_fname, space
249
+
250
+ def get(
251
+ self,
252
+ maps: str,
253
+ target_data: dict[str, Any],
254
+ extra_input: Optional[dict[str, Any]] = None,
255
+ ) -> tuple["Nifti1Image", list[str]]:
256
+ """Get map(s), tailored for the target image.
257
+
258
+ Parameters
259
+ ----------
260
+ maps : str
261
+ The name of the map(s).
262
+ target_data : dict
263
+ The corresponding item of the data object to which the map(s)
264
+ will be applied.
265
+ extra_input : dict, optional
266
+ The other fields in the data object. Useful for accessing other
267
+ data kinds that needs to be used in the computation of
268
+ map(s) (default None).
269
+
270
+ Returns
271
+ -------
272
+ Nifti1Image
273
+ The map(s) image.
274
+ list of str
275
+ Map(s) labels.
276
+
277
+ Raises
278
+ ------
279
+ ValueError
280
+ If ``extra_input`` is None when ``target_data``'s space is native.
281
+
282
+ """
283
+ # Check pre-requirements for space manipulation
284
+ target_space = target_data["space"]
285
+ logger.debug(f"Getting {maps} in {target_space} space.")
286
+ # Extra data type requirement check if target space is native
287
+ if target_space == "native": # pragma: no cover
288
+ # Check for extra inputs
289
+ if extra_input is None:
290
+ raise_error(
291
+ "No extra input provided, requires `Warp` and `T1w` "
292
+ "data types in particular for transformation to "
293
+ f"{target_data['space']} space for further computation."
294
+ )
295
+ # Get native space warper spec
296
+ warper_spec = get_native_warper(
297
+ target_data=target_data,
298
+ other_data=extra_input,
299
+ )
300
+ # Set target standard space to warp file space source
301
+ target_std_space = warper_spec["src"]
302
+ logger.debug(
303
+ f"Target space is native. Will warp from {target_std_space}"
304
+ )
305
+ else:
306
+ # Set target standard space to target space
307
+ target_std_space = target_space
308
+
309
+ # Get the min of the voxels sizes and use it as the resolution
310
+ target_img = target_data["data"]
311
+ resolution = np.min(target_img.header.get_zooms()[:3])
312
+
313
+ # Load maps
314
+ logger.debug(f"Loading map(s) {maps}")
315
+ img, labels, _, space = self.load(
316
+ name=maps,
317
+ resolution=resolution,
318
+ target_space=target_space,
319
+ )
320
+
321
+ # Convert maps spaces if required;
322
+ # cannot be "native" due to earlier check
323
+ if space != target_std_space:
324
+ logger.debug(
325
+ f"Warping {maps} to {target_std_space} space using ANTs."
326
+ )
327
+ raw_img = ANTsMapsWarper().warp(
328
+ maps_name=maps,
329
+ maps_img=img,
330
+ src=space,
331
+ dst=target_std_space,
332
+ target_data=target_data,
333
+ warp_data=None,
334
+ )
335
+ # Remove extra dimension added by ANTs
336
+ img = nimg.math_img("np.squeeze(img)", img=raw_img)
337
+
338
+ if target_space != "native":
339
+ # No warping is going to happen, just resampling, because
340
+ # we are in the correct space
341
+ logger.debug(f"Resampling {maps} to target image.")
342
+ # Resample maps to target image
343
+ img = nimg.resample_to_img(
344
+ source_img=img,
345
+ target_img=target_img,
346
+ interpolation="continuous",
347
+ copy=True,
348
+ )
349
+ else: # pragma: no cover
350
+ # Warp maps if target space is native as either
351
+ # the image is in the right non-native space or it's
352
+ # warped from one non-native space to another non-native space
353
+ logger.debug(
354
+ "Warping map(s) to native space using "
355
+ f"{warper_spec['warper']}."
356
+ )
357
+ # extra_input check done earlier and warper_spec exists
358
+ if warper_spec["warper"] == "fsl":
359
+ img = FSLMapsWarper().warp(
360
+ maps_name="native",
361
+ maps_img=img,
362
+ target_data=target_data,
363
+ warp_data=warper_spec,
364
+ )
365
+ elif warper_spec["warper"] == "ants":
366
+ img = ANTsMapsWarper().warp(
367
+ maps_name="native",
368
+ maps_img=img,
369
+ src="",
370
+ dst="native",
371
+ target_data=target_data,
372
+ warp_data=warper_spec,
373
+ )
374
+
375
+ return img, labels
376
+
377
+
378
+ def _retrieve_smith(
379
+ resolution: Optional[float] = None,
380
+ components: Optional[str] = None,
381
+ dimension: Optional[int] = None,
382
+ ) -> tuple[Path, list[str]]:
383
+ """Retrieve Smith maps.
384
+
385
+ Parameters
386
+ ----------
387
+ resolution : 2.0, optional
388
+ The desired resolution of the maps to load. If it is not
389
+ available, the closest resolution will be loaded. Preferably, use a
390
+ resolution higher than the desired one. By default, will load the
391
+ highest one (default None). Available resolution for these
392
+ maps are 2mm.
393
+ components : {"rsn", "bm"}, optional
394
+ The components to load. "rsn" loads the resting-fMRI components and
395
+ "bm" loads the BrainMap components (default None).
396
+ dimension : {10, 20, 70}, optional
397
+ The number of dimensions to load (default None).
398
+
399
+ Returns
400
+ -------
401
+ pathlib.Path
402
+ File path to the maps image.
403
+ list of str
404
+ Maps labels.
405
+
406
+ Raises
407
+ ------
408
+ ValueError
409
+ If invalid value is provided for ``components`` or ``dimension``.
410
+
411
+ """
412
+ logger.info("Maps parameters:")
413
+ logger.info(f"\tresolution: {resolution}")
414
+ logger.info(f"\tcomponents: {components}")
415
+ logger.info(f"\tdimension: {dimension}")
416
+
417
+ # Check resolution
418
+ _valid_resolutions = [2.0]
419
+ resolution = closest_resolution(resolution, _valid_resolutions)
420
+
421
+ # Check components value
422
+ _valid_components = ["rsn", "bm"]
423
+ if components not in _valid_components:
424
+ raise_error(
425
+ f"The parameter `components` ({components}) needs to be one of "
426
+ f"the following: {_valid_components}"
427
+ )
428
+
429
+ # Check dimension value
430
+ _valid_dimension = [10, 20, 70]
431
+ if dimension not in _valid_dimension:
432
+ raise_error(
433
+ f"The parameter `dimension` ({dimension}) needs to be one of the "
434
+ f"following: {_valid_dimension}"
435
+ )
436
+
437
+ # Fetch file path
438
+ maps_img_path = get(
439
+ file_path=Path(
440
+ f"parcellations/Smith2009/{components}{dimension}.nii.gz"
441
+ ),
442
+ dataset_path=get_dataset_path(),
443
+ **JUNIFER_DATA_PARAMS,
444
+ )
445
+
446
+ return maps_img_path, [f"Map_{i}" for i in range(dimension)]
@@ -0,0 +1,255 @@
1
+ """Provide tests for maps."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ import pytest
7
+ from numpy.testing import assert_array_equal
8
+
9
+ from junifer.data import (
10
+ deregister_data,
11
+ get_data,
12
+ list_data,
13
+ load_data,
14
+ register_data,
15
+ )
16
+ from junifer.data.maps._maps import _retrieve_smith
17
+ from junifer.datagrabber import PatternDataladDataGrabber
18
+ from junifer.datareader import DefaultDataReader
19
+ from junifer.pipeline.utils import _check_ants
20
+ from junifer.testing.datagrabbers import PartlyCloudyTestingDataGrabber
21
+
22
+
23
+ def test_register_built_in_check() -> None:
24
+ """Test maps registration check for built-in maps."""
25
+ with pytest.raises(ValueError, match=r"built-in"):
26
+ register_data(
27
+ kind="maps",
28
+ name="Smith_rsn_10",
29
+ maps_path="testmaps.nii.gz",
30
+ maps_labels=["1", "2"],
31
+ space="MNI",
32
+ )
33
+
34
+
35
+ def test_list_incorrect() -> None:
36
+ """Test incorrect information check for list mapss."""
37
+ assert "testmaps" not in list_data(kind="maps")
38
+
39
+
40
+ def test_register_overwrite() -> None:
41
+ """Test maps registration check for overwriting."""
42
+ register_data(
43
+ kind="maps",
44
+ name="testmaps",
45
+ maps_path="testmaps.nii.gz",
46
+ maps_labels=["1", "2"],
47
+ space="MNI152NLin6Sym",
48
+ )
49
+ with pytest.raises(ValueError, match=r"already registered"):
50
+ register_data(
51
+ kind="maps",
52
+ name="testmaps",
53
+ maps_path="testmaps.nii.gz",
54
+ maps_labels=["1", "2"],
55
+ space="MNI152NLin6Sym",
56
+ overwrite=False,
57
+ )
58
+
59
+ register_data(
60
+ kind="maps",
61
+ name="testmaps",
62
+ maps_path="testmaps.nii.gz",
63
+ maps_labels=["1", "2"],
64
+ space="MNI152NLin6Sym",
65
+ overwrite=True,
66
+ )
67
+
68
+ assert (
69
+ load_data(
70
+ kind="maps",
71
+ name="testmaps",
72
+ target_space="MNI152NLin6Sym",
73
+ path_only=True,
74
+ )[2].name
75
+ == "testmaps.nii.gz"
76
+ )
77
+
78
+
79
+ def test_register_valid_input() -> None:
80
+ """Test maps registration check for valid input."""
81
+ maps, labels, maps_path, _ = load_data(
82
+ kind="maps",
83
+ name="Smith_rsn_10",
84
+ target_space="MNI152NLin6Asym",
85
+ )
86
+ assert maps is not None
87
+
88
+ # Test wrong number of labels
89
+ register_data(
90
+ kind="maps",
91
+ name="WrongLabels",
92
+ maps_path=maps_path,
93
+ maps_labels=labels[:5],
94
+ space="MNI152NLin6Asym",
95
+ )
96
+ with pytest.raises(ValueError, match=r"has 10 regions but 5"):
97
+ load_data(
98
+ kind="maps",
99
+ name="WrongLabels",
100
+ target_space="MNI152NLin6Asym",
101
+ )
102
+
103
+
104
+ def test_list() -> None:
105
+ """Test listing of available coordinates."""
106
+ assert {"Smith_rsn_10", "Smith_bm_70"}.issubset(
107
+ set(list_data(kind="maps"))
108
+ )
109
+
110
+
111
+ def test_load_nonexisting() -> None:
112
+ """Test loading maps that not exist."""
113
+ with pytest.raises(ValueError, match=r"not found"):
114
+ load_data(kind="maps", name="nomaps", target_space="MNI152NLin6Sym")
115
+
116
+
117
+ def test_get() -> None:
118
+ """Test tailored maps fetch."""
119
+ with PatternDataladDataGrabber(
120
+ uri="https://github.com/OpenNeuroDatasets/ds005226.git",
121
+ types=["BOLD"],
122
+ patterns={
123
+ "BOLD": {
124
+ "pattern": (
125
+ "derivatives/pre-processed_data/space-MNI/{subject}/"
126
+ "{subject-padded}_task-{task}_run-{run}_space-MNI152NLin6Asym"
127
+ "_res-2_desc-preproc_bold.nii.gz"
128
+ ),
129
+ "space": "MNI152NLin6Asym",
130
+ },
131
+ },
132
+ replacements=["subject", "subject-padded", "task", "run"],
133
+ ) as dg:
134
+ element = dg[("sub-01", "sub-001", "rest", "1")]
135
+ element_data = DefaultDataReader().fit_transform(element)
136
+ bold = element_data["BOLD"]
137
+ bold_img = bold["data"]
138
+ # Get tailored coordinates
139
+ tailored_maps, tailored_labels = get_data(
140
+ kind="maps", names="Smith_rsn_10", target_data=bold
141
+ )
142
+
143
+ # Check shape with original element data
144
+ assert tailored_maps.shape[:3] == bold_img.shape[:3]
145
+
146
+ # Get raw maps
147
+ raw_maps, raw_labels, _, _ = load_data(
148
+ kind="maps", name="Smith_rsn_10", target_space="MNI152NLin6Asym"
149
+ )
150
+ # Tailored and raw shape should be same
151
+ assert tailored_maps.shape[:3] == raw_maps.shape[:3]
152
+ assert tailored_labels == raw_labels
153
+
154
+
155
+ @pytest.mark.skipif(
156
+ _check_ants() is False, reason="requires ANTs to be in PATH"
157
+ )
158
+ def test_get_different_space() -> None:
159
+ """Test tailored maps fetch in different space."""
160
+ with PartlyCloudyTestingDataGrabber() as dg:
161
+ element = dg["sub-01"]
162
+ element_data = DefaultDataReader().fit_transform(element)
163
+ bold = element_data["BOLD"]
164
+ bold_img = bold["data"]
165
+ # Get tailored coordinates
166
+ tailored_maps, tailored_labels = get_data(
167
+ kind="maps", names="Smith_rsn_10", target_data=bold
168
+ )
169
+
170
+ # Check shape with original element data
171
+ assert tailored_maps.shape[:3] == bold_img.shape[:3]
172
+
173
+ # Get raw maps
174
+ raw_maps, raw_labels, _, _ = load_data(
175
+ kind="maps",
176
+ name="Smith_rsn_10",
177
+ target_space="MNI152NLin2009cAsym",
178
+ )
179
+ # Tailored and raw should not be same
180
+ assert tailored_maps.shape[:3] != raw_maps.shape[:3]
181
+ assert tailored_labels == raw_labels
182
+
183
+
184
+ def test_deregister() -> None:
185
+ """Test maps deregistration."""
186
+ deregister_data(kind="maps", name="testmaps")
187
+ assert "testmaps" not in list_data(kind="maps")
188
+
189
+
190
+ @pytest.mark.parametrize(
191
+ "resolution, components, dimension",
192
+ [
193
+ (2.0, "rsn", 10),
194
+ (2.0, "rsn", 20),
195
+ (2.0, "rsn", 70),
196
+ (2.0, "bm", 10),
197
+ (2.0, "bm", 20),
198
+ (2.0, "bm", 70),
199
+ ],
200
+ )
201
+ def test_smith(
202
+ resolution: float,
203
+ components: str,
204
+ dimension: int,
205
+ ) -> None:
206
+ """Test Smith maps.
207
+
208
+ Parameters
209
+ ----------
210
+ resolution : float
211
+ The parametrized resolution values.
212
+ components : str
213
+ The parametrized components values.
214
+ dimension : int
215
+ The parametrized dimension values.
216
+
217
+ """
218
+ maps = list_data(kind="maps")
219
+ maps_name = f"Smith_{components}_{dimension}"
220
+ assert maps_name in maps
221
+
222
+ maps_file = f"{components}{dimension}.nii.gz"
223
+ # Load maps
224
+ img, label, img_path, space = load_data(
225
+ kind="maps",
226
+ name=maps_name,
227
+ target_space="MNI152NLin6Asym",
228
+ resolution=resolution,
229
+ )
230
+ assert img is not None
231
+ assert img_path.name == maps_file
232
+ assert space == "MNI152NLin6Asym"
233
+ assert len(label) == dimension
234
+ assert_array_equal(
235
+ img.header["pixdim"][1:4],
236
+ 3 * [2.0],
237
+ )
238
+
239
+
240
+ def test_retrieve_smith_incorrect_components() -> None:
241
+ """Test retrieve Smith with incorrect components."""
242
+ with pytest.raises(ValueError, match="The parameter `components`"):
243
+ _retrieve_smith(
244
+ components="abc",
245
+ dimension=10,
246
+ )
247
+
248
+
249
+ def test_retrieve_smith_incorrect_dimension() -> None:
250
+ """Test retrieve Smith with incorrect dimension."""
251
+ with pytest.raises(ValueError, match="The parameter `dimension`"):
252
+ _retrieve_smith(
253
+ components="rsn",
254
+ dimension=100,
255
+ )