junifer 0.0.6.dev422__py3-none-any.whl → 0.0.6.dev459__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.
junifer/_version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.0.6.dev422'
16
- __version_tuple__ = version_tuple = (0, 0, 6, 'dev422')
15
+ __version__ = version = '0.0.6.dev459'
16
+ __version_tuple__ = version_tuple = (0, 0, 6, 'dev459')
@@ -43,12 +43,12 @@ def test_get_dependency_information_short() -> None:
43
43
  "nilearn",
44
44
  "sqlalchemy",
45
45
  "ruamel.yaml",
46
- "httpx",
47
46
  "tqdm",
48
47
  "templateflow",
49
48
  "lapy",
50
49
  "lazy_loader",
51
50
  "looseversion",
51
+ "junifer_data",
52
52
  ]
53
53
 
54
54
  if sys.version_info < (3, 11):
@@ -73,7 +73,6 @@ def test_get_dependency_information_long() -> None:
73
73
  "nilearn",
74
74
  "sqlalchemy",
75
75
  "ruamel.yaml",
76
- "httpx",
77
76
  "tqdm",
78
77
  "templateflow",
79
78
  "lapy",
@@ -9,12 +9,13 @@ from typing import Any, Optional
9
9
 
10
10
  import numpy as np
11
11
  import pandas as pd
12
+ from junifer_data import get
12
13
  from numpy.typing import ArrayLike
13
14
 
14
15
  from ...utils import logger, raise_error
15
16
  from ...utils.singleton import Singleton
16
17
  from ..pipeline_data_registry_base import BasePipelineDataRegistry
17
- from ..utils import get_native_warper
18
+ from ..utils import JUNIFER_DATA_VERSION, get_dataset_path, get_native_warper
18
19
  from ._ants_coordinates_warper import ANTsCoordinatesWarper
19
20
  from ._fsl_coordinates_warper import FSLCoordinatesWarper
20
21
 
@@ -32,104 +33,104 @@ class CoordinatesRegistry(BasePipelineDataRegistry, metaclass=Singleton):
32
33
 
33
34
  def __init__(self) -> None:
34
35
  """Initialize the class."""
36
+ super().__init__()
35
37
  # Each entry in registry is a dictionary that must contain at least
36
38
  # the following keys:
37
39
  # * 'space': the coordinates' space (e.g., 'MNI')
38
- # The built-in coordinates are files that are shipped with the package
39
- # in the data/VOIs directory. The user can also register their own
40
+ # The built-in coordinates are files that are shipped with the
41
+ # junifer-data dataset. The user can also register their own
40
42
  # coordinates, which will be stored as numpy arrays in the dictionary.
41
43
  # Make built-in and external dictionaries for validation later
42
44
  self._builtin = {}
43
45
  self._external = {}
44
46
 
45
- # Path to the metadata of the VOIs
46
- _vois_meta_path = Path(__file__).parent / "VOIs" / "meta"
47
-
48
- self._builtin = {
49
- "CogAC": {
50
- "path": _vois_meta_path / "CogAC_VOIs.txt",
51
- "space": "MNI",
52
- },
53
- "CogAR": {
54
- "path": _vois_meta_path / "CogAR_VOIs.txt",
55
- "space": "MNI",
56
- },
57
- "DMNBuckner": {
58
- "path": _vois_meta_path / "DMNBuckner_VOIs.txt",
59
- "space": "MNI",
60
- },
61
- "eMDN": {
62
- "path": _vois_meta_path / "eMDN_VOIs.txt",
63
- "space": "MNI",
64
- },
65
- "Empathy": {
66
- "path": _vois_meta_path / "Empathy_VOIs.txt",
67
- "space": "MNI",
68
- },
69
- "eSAD": {
70
- "path": _vois_meta_path / "eSAD_VOIs.txt",
71
- "space": "MNI",
72
- },
73
- "extDMN": {
74
- "path": _vois_meta_path / "extDMN_VOIs.txt",
75
- "space": "MNI",
76
- },
77
- "Motor": {
78
- "path": _vois_meta_path / "Motor_VOIs.txt",
79
- "space": "MNI",
80
- },
81
- "MultiTask": {
82
- "path": _vois_meta_path / "MultiTask_VOIs.txt",
83
- "space": "MNI",
84
- },
85
- "PhysioStress": {
86
- "path": _vois_meta_path / "PhysioStress_VOIs.txt",
87
- "space": "MNI",
88
- },
89
- "Rew": {
90
- "path": _vois_meta_path / "Rew_VOIs.txt",
91
- "space": "MNI",
92
- },
93
- "Somatosensory": {
94
- "path": _vois_meta_path / "Somatosensory_VOIs.txt",
95
- "space": "MNI",
96
- },
97
- "ToM": {
98
- "path": _vois_meta_path / "ToM_VOIs.txt",
99
- "space": "MNI",
100
- },
101
- "VigAtt": {
102
- "path": _vois_meta_path / "VigAtt_VOIs.txt",
103
- "space": "MNI",
104
- },
105
- "WM": {
106
- "path": _vois_meta_path / "WM_VOIs.txt",
107
- "space": "MNI",
108
- },
109
- "Power": {
110
- "path": _vois_meta_path / "Power2011_MNI_VOIs.txt",
111
- "space": "MNI",
112
- },
113
- "Power2011": {
114
- "path": _vois_meta_path / "Power2011_MNI_VOIs.txt",
115
- "space": "MNI",
116
- },
117
- "Dosenbach": {
118
- "path": _vois_meta_path / "Dosenbach2010_MNI_VOIs.txt",
119
- "space": "MNI",
120
- },
121
- "Power2013": {
122
- "path": _vois_meta_path / "Power2013_MNI_VOIs.tsv",
123
- "space": "MNI",
124
- },
125
- "AutobiographicalMemory": {
126
- "path": _vois_meta_path / "AutobiographicalMemory_VOIs.txt",
127
- "space": "MNI",
128
- },
129
- }
130
-
131
- # Set built-in to registry
132
- self._registry = self._builtin
47
+ self._builtin.update(
48
+ {
49
+ "CogAC": {
50
+ "file_path_suffix": "CogAC_VOIs.txt",
51
+ "space": "MNI",
52
+ },
53
+ "CogAR": {
54
+ "file_path_suffix": "CogAR_VOIs.txt",
55
+ "space": "MNI",
56
+ },
57
+ "DMNBuckner": {
58
+ "file_path_suffix": "DMNBuckner_VOIs.txt",
59
+ "space": "MNI",
60
+ },
61
+ "eMDN": {
62
+ "file_path_suffix": "eMDN_VOIs.txt",
63
+ "space": "MNI",
64
+ },
65
+ "Empathy": {
66
+ "file_path_suffix": "Empathy_VOIs.txt",
67
+ "space": "MNI",
68
+ },
69
+ "eSAD": {
70
+ "file_path_suffix": "eSAD_VOIs.txt",
71
+ "space": "MNI",
72
+ },
73
+ "extDMN": {
74
+ "file_path_suffix": "extDMN_VOIs.txt",
75
+ "space": "MNI",
76
+ },
77
+ "Motor": {
78
+ "file_path_suffix": "Motor_VOIs.txt",
79
+ "space": "MNI",
80
+ },
81
+ "MultiTask": {
82
+ "file_path_suffix": "MultiTask_VOIs.txt",
83
+ "space": "MNI",
84
+ },
85
+ "PhysioStress": {
86
+ "file_path_suffix": "PhysioStress_VOIs.txt",
87
+ "space": "MNI",
88
+ },
89
+ "Rew": {
90
+ "file_path_suffix": "Rew_VOIs.txt",
91
+ "space": "MNI",
92
+ },
93
+ "Somatosensory": {
94
+ "file_path_suffix": "Somatosensory_VOIs.txt",
95
+ "space": "MNI",
96
+ },
97
+ "ToM": {
98
+ "file_path_suffix": "ToM_VOIs.txt",
99
+ "space": "MNI",
100
+ },
101
+ "VigAtt": {
102
+ "file_path_suffix": "VigAtt_VOIs.txt",
103
+ "space": "MNI",
104
+ },
105
+ "WM": {
106
+ "file_path_suffix": "WM_VOIs.txt",
107
+ "space": "MNI",
108
+ },
109
+ "Power": {
110
+ "file_path_suffix": "Power2011_MNI_VOIs.txt",
111
+ "space": "MNI",
112
+ },
113
+ "Power2011": {
114
+ "file_path_suffix": "Power2011_MNI_VOIs.txt",
115
+ "space": "MNI",
116
+ },
117
+ "Dosenbach": {
118
+ "file_path_suffix": "Dosenbach2010_MNI_VOIs.txt",
119
+ "space": "MNI",
120
+ },
121
+ "Power2013": {
122
+ "file_path_suffix": "Power2013_MNI_VOIs.tsv",
123
+ "space": "MNI",
124
+ },
125
+ "AutobiographicalMemory": {
126
+ "file_path_suffix": "AutobiographicalMemory_VOIs.txt",
127
+ "space": "MNI",
128
+ },
129
+ }
130
+ )
131
+
132
+ # Update registry with built-in ones
133
+ self._registry.update(self._builtin)
133
134
 
134
135
  def register(
135
136
  self,
@@ -161,9 +162,9 @@ class CoordinatesRegistry(BasePipelineDataRegistry, metaclass=Singleton):
161
162
  Raises
162
163
  ------
163
164
  ValueError
164
- If the coordinates ``name`` is already registered and
165
+ If the coordinates ``name`` is a built-in coordinates or
166
+ if the coordinates ``name`` is already registered and
165
167
  ``overwrite=False`` or
166
- if the coordinates ``name`` is a built-in coordinates or
167
168
  if the ``coordinates`` is not a 2D array or
168
169
  if coordinate value does not have 3 components or
169
170
  if the ``voi_names`` shape does not match the
@@ -174,11 +175,12 @@ class CoordinatesRegistry(BasePipelineDataRegistry, metaclass=Singleton):
174
175
  """
175
176
  # Check for attempt of overwriting built-in coordinates
176
177
  if name in self._builtin:
177
- if isinstance(self._registry[name].get("path"), Path):
178
- raise_error(
179
- f"Coordinates: {name} already registered as built-in "
180
- "coordinates."
181
- )
178
+ raise_error(
179
+ f"Coordinates: {name} already registered as built-in "
180
+ "coordinates."
181
+ )
182
+ # Check for attempt of overwriting external coordinates
183
+ if name in self._external:
182
184
  if overwrite:
183
185
  logger.info(f"Overwriting coordinates: {name}")
184
186
  else:
@@ -186,7 +188,7 @@ class CoordinatesRegistry(BasePipelineDataRegistry, metaclass=Singleton):
186
188
  f"Coordinates: {name} already registered. "
187
189
  "Set `overwrite=True` to update its value."
188
190
  )
189
-
191
+ # Further checks
190
192
  if not isinstance(coordinates, np.ndarray):
191
193
  raise_error(
192
194
  "Coordinates must be a `numpy.ndarray`, "
@@ -207,6 +209,7 @@ class CoordinatesRegistry(BasePipelineDataRegistry, metaclass=Singleton):
207
209
  f"Length of `voi_names` ({len(voi_names)}) does not match the "
208
210
  f"number of `coordinates` ({coordinates.shape[0]})."
209
211
  )
212
+ # Registration
210
213
  logger.info(f"Registering coordinates: {name}")
211
214
  # Add coordinates info
212
215
  self._external[name] = {
@@ -257,6 +260,8 @@ class CoordinatesRegistry(BasePipelineDataRegistry, metaclass=Singleton):
257
260
  ------
258
261
  ValueError
259
262
  If ``name`` is invalid.
263
+ RuntimeError
264
+ If there is a problem fetching the coordinates file.
260
265
 
261
266
  """
262
267
  # Check for valid coordinates name
@@ -265,17 +270,31 @@ class CoordinatesRegistry(BasePipelineDataRegistry, metaclass=Singleton):
265
270
  f"Coordinates: {name} not found. "
266
271
  f"Valid options are: {self.list}"
267
272
  )
268
- # Load coordinates
273
+ # Load coordinates info
269
274
  t_coord = self._registry[name]
270
- # Load data
271
- if isinstance(t_coord.get("path"), Path):
272
- logger.debug(f"Loading coordinates {t_coord['path'].absolute()!s}")
275
+
276
+ # Load data for in-built ones
277
+ if t_coord.get("file_path_suffix") is not None:
278
+ # Set file path to retrieve
279
+ coords_file_path = Path(
280
+ f"coordinates/{name}/{t_coord['file_path_suffix']}"
281
+ )
282
+ logger.debug(f"Loading coordinates: `{name}`")
273
283
  # Load via pandas
274
- df_coords = pd.read_csv(t_coord["path"], sep="\t", header=None)
284
+ df_coords = pd.read_csv(
285
+ get(
286
+ file_path=coords_file_path,
287
+ dataset_path=get_dataset_path(),
288
+ tag=JUNIFER_DATA_VERSION,
289
+ ),
290
+ sep="\t",
291
+ header=None,
292
+ )
275
293
  # Convert dataframe to numpy ndarray
276
294
  coords = df_coords.iloc[:, [0, 1, 2]].to_numpy()
277
295
  # Get label names
278
296
  names = list(df_coords.iloc[:, [3]].values[:, 0])
297
+ # Load data for external ones
279
298
  else:
280
299
  coords = t_coord["coords"]
281
300
  names = t_coord["voi_names"]
@@ -21,7 +21,6 @@ def test_register_built_in_check() -> None:
21
21
  coordinates=np.zeros(2),
22
22
  voi_names=["1", "2"],
23
23
  space="MNI",
24
- overwrite=True,
25
24
  )
26
25
 
27
26
 
@@ -32,7 +31,6 @@ def test_register_overwrite() -> None:
32
31
  coordinates=np.zeros((2, 3)),
33
32
  voi_names=["roi1", "roi2"],
34
33
  space="MNI",
35
- overwrite=True,
36
34
  )
37
35
  with pytest.raises(ValueError, match=r"already registered"):
38
36
  CoordinatesRegistry().register(
@@ -40,6 +38,7 @@ def test_register_overwrite() -> None:
40
38
  coordinates=np.ones((2, 3)),
41
39
  voi_names=["roi2", "roi3"],
42
40
  space="MNI",
41
+ overwrite=False,
43
42
  )
44
43
 
45
44
  CoordinatesRegistry().register(
@@ -16,6 +16,7 @@ from typing import (
16
16
  import nibabel as nib
17
17
  import nilearn.image as nimg
18
18
  import numpy as np
19
+ from junifer_data import get
19
20
  from nilearn.masking import (
20
21
  compute_background_mask,
21
22
  compute_epi_mask,
@@ -26,7 +27,12 @@ from ...utils import logger, raise_error
26
27
  from ...utils.singleton import Singleton
27
28
  from ..pipeline_data_registry_base import BasePipelineDataRegistry
28
29
  from ..template_spaces import get_template
29
- from ..utils import closest_resolution, get_native_warper
30
+ from ..utils import (
31
+ JUNIFER_DATA_VERSION,
32
+ closest_resolution,
33
+ get_dataset_path,
34
+ get_native_warper,
35
+ )
30
36
  from ._ants_mask_warper import ANTsMaskWarper
31
37
  from ._fsl_mask_warper import FSLMaskWarper
32
38
 
@@ -38,10 +44,6 @@ if TYPE_CHECKING:
38
44
  __all__ = ["MaskRegistry", "compute_brain_mask"]
39
45
 
40
46
 
41
- # Path to the masks
42
- _masks_path = Path(__file__).parent
43
-
44
-
45
47
  def compute_brain_mask(
46
48
  target_data: dict[str, Any],
47
49
  warp_data: Optional[dict[str, Any]] = None,
@@ -224,6 +226,7 @@ class MaskRegistry(BasePipelineDataRegistry, metaclass=Singleton):
224
226
 
225
227
  def __init__(self) -> None:
226
228
  """Initialize the class."""
229
+ super().__init__()
227
230
  # Each entry in registry is a dictionary that must contain at least
228
231
  # the following keys:
229
232
  # * 'family': the mask's family name
@@ -240,38 +243,40 @@ class MaskRegistry(BasePipelineDataRegistry, metaclass=Singleton):
240
243
  self._builtin = {}
241
244
  self._external = {}
242
245
 
243
- self._builtin = {
244
- "GM_prob0.2": {
245
- "family": "Vickery-Patil",
246
- "space": "IXI549Space",
247
- },
248
- "GM_prob0.2_cortex": {
249
- "family": "Vickery-Patil",
250
- "space": "IXI549Space",
251
- },
252
- "compute_brain_mask": {
253
- "family": "Callable",
254
- "func": compute_brain_mask,
255
- "space": "inherit",
256
- },
257
- "compute_background_mask": {
258
- "family": "Callable",
259
- "func": compute_background_mask,
260
- "space": "inherit",
261
- },
262
- "compute_epi_mask": {
263
- "family": "Callable",
264
- "func": compute_epi_mask,
265
- "space": "inherit",
266
- },
267
- "UKB_15K_GM": {
268
- "family": "UKB",
269
- "space": "MNI152NLin6Asym",
270
- },
271
- }
246
+ self._builtin.update(
247
+ {
248
+ "GM_prob0.2": {
249
+ "family": "Vickery-Patil",
250
+ "space": "IXI549Space",
251
+ },
252
+ "GM_prob0.2_cortex": {
253
+ "family": "Vickery-Patil",
254
+ "space": "IXI549Space",
255
+ },
256
+ "compute_brain_mask": {
257
+ "family": "Callable",
258
+ "func": compute_brain_mask,
259
+ "space": "inherit",
260
+ },
261
+ "compute_background_mask": {
262
+ "family": "Callable",
263
+ "func": compute_background_mask,
264
+ "space": "inherit",
265
+ },
266
+ "compute_epi_mask": {
267
+ "family": "Callable",
268
+ "func": compute_epi_mask,
269
+ "space": "inherit",
270
+ },
271
+ "UKB_15K_GM": {
272
+ "family": "UKB",
273
+ "space": "MNI152NLin6Asym",
274
+ },
275
+ }
276
+ )
272
277
 
273
- # Set built-in to registry
274
- self._registry = self._builtin
278
+ # Update registry with built-in ones
279
+ self._registry.update(self._builtin)
275
280
 
276
281
  def register(
277
282
  self,
@@ -297,19 +302,18 @@ class MaskRegistry(BasePipelineDataRegistry, metaclass=Singleton):
297
302
  Raises
298
303
  ------
299
304
  ValueError
300
- If the mask ``name`` is already registered and
301
- ``overwrite=False`` or
302
- if the mask ``name`` is a built-in mask.
305
+ If the mask ``name`` is a built-in mask or
306
+ if the mask ``name`` is already registered and
307
+ ``overwrite=False``.
303
308
 
304
309
  """
305
310
  # Check for attempt of overwriting built-in mask
306
311
  if name in self._builtin:
312
+ raise_error(f"Mask: {name} already registered as built-in mask.")
313
+ # Check for attempt of overwriting external masks
314
+ if name in self._external:
307
315
  if overwrite:
308
316
  logger.info(f"Overwriting mask: {name}")
309
- if self._registry[name]["family"] != "CustomUserMask":
310
- raise_error(
311
- f"Mask: {name} already registered as built-in mask."
312
- )
313
317
  else:
314
318
  raise_error(
315
319
  f"Mask: {name} already registered. Set `overwrite=True` "
@@ -318,16 +322,17 @@ class MaskRegistry(BasePipelineDataRegistry, metaclass=Singleton):
318
322
  # Convert str to Path
319
323
  if not isinstance(mask_path, Path):
320
324
  mask_path = Path(mask_path)
325
+ # Registration
321
326
  logger.info(f"Registering mask: {name}")
322
327
  # Add mask info
323
328
  self._external[name] = {
324
- "path": str(mask_path.absolute()),
329
+ "path": mask_path,
325
330
  "family": "CustomUserMask",
326
331
  "space": space,
327
332
  }
328
333
  # Update registry
329
334
  self._registry[name] = {
330
- "path": str(mask_path.absolute()),
335
+ "path": mask_path,
331
336
  "family": "CustomUserMask",
332
337
  "space": space,
333
338
  }
@@ -396,14 +401,19 @@ class MaskRegistry(BasePipelineDataRegistry, metaclass=Singleton):
396
401
  # Check if the mask family is custom or built-in
397
402
  mask_img = None
398
403
  if t_family == "CustomUserMask":
399
- mask_fname = Path(mask_definition["path"])
400
- elif t_family == "Vickery-Patil":
401
- mask_fname = _load_vickery_patil_mask(name, resolution)
404
+ mask_fname = mask_definition["path"]
402
405
  elif t_family == "Callable":
403
406
  mask_img = mask_definition["func"]
404
407
  mask_fname = None
405
- elif t_family == "UKB":
406
- mask_fname = _load_ukb_mask(name)
408
+ elif t_family in ["Vickery-Patil", "UKB"]:
409
+ # Load mask
410
+ if t_family == "Vickery-Patil":
411
+ mask_fname = _load_vickery_patil_mask(
412
+ name=name,
413
+ resolution=resolution,
414
+ )
415
+ elif t_family == "UKB":
416
+ mask_fname = _load_ukb_mask(name=name)
407
417
  else:
408
418
  raise_error(f"Unknown mask family: {t_family}")
409
419
 
@@ -712,6 +722,7 @@ def _load_vickery_patil_mask(
712
722
  ``name = "GM_prob0.2"``.
713
723
 
714
724
  """
725
+ # Check name
715
726
  if name == "GM_prob0.2":
716
727
  available_resolutions = [1.5, 3.0]
717
728
  to_load = closest_resolution(resolution, available_resolutions)
@@ -730,10 +741,12 @@ def _load_vickery_patil_mask(
730
741
  else:
731
742
  raise_error(f"Cannot find a Vickery-Patil mask called {name}")
732
743
 
733
- # Set path for masks
734
- mask_fname = _masks_path / "vickery-patil" / mask_fname
735
-
736
- return mask_fname
744
+ # Fetch file
745
+ return get(
746
+ file_path=Path(f"masks/Vickery-Patil/{mask_fname}"),
747
+ dataset_path=get_dataset_path(),
748
+ tag=JUNIFER_DATA_VERSION,
749
+ )
737
750
 
738
751
 
739
752
  def _load_ukb_mask(name: str) -> Path:
@@ -755,15 +768,18 @@ def _load_ukb_mask(name: str) -> Path:
755
768
  If ``name`` is invalid.
756
769
 
757
770
  """
771
+ # Check name
758
772
  if name == "UKB_15K_GM":
759
773
  mask_fname = "UKB_15K_GM_template.nii.gz"
760
774
  else:
761
775
  raise_error(f"Cannot find a UKB mask called {name}")
762
776
 
763
- # Set path for masks
764
- mask_fname = _masks_path / "ukb" / mask_fname
765
-
766
- return mask_fname
777
+ # Fetch file
778
+ return get(
779
+ file_path=Path(f"masks/UKB/{mask_fname}"),
780
+ dataset_path=get_dataset_path(),
781
+ tag=JUNIFER_DATA_VERSION,
782
+ )
767
783
 
768
784
 
769
785
  def _get_interpolation_method(img: "Nifti1Image") -> str: