siibra 1.0.1a0__py3-none-any.whl → 1.0.1a1__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.

Potentially problematic release.


This version of siibra might be problematic. Click here for more details.

Files changed (82) hide show
  1. siibra/VERSION +1 -1
  2. siibra/__init__.py +4 -4
  3. siibra/commons.py +8 -7
  4. siibra/configuration/__init__.py +1 -1
  5. siibra/configuration/configuration.py +1 -1
  6. siibra/configuration/factory.py +1 -1
  7. siibra/core/__init__.py +1 -1
  8. siibra/core/assignment.py +1 -1
  9. siibra/core/atlas.py +1 -1
  10. siibra/core/concept.py +3 -3
  11. siibra/core/parcellation.py +6 -6
  12. siibra/core/region.py +59 -49
  13. siibra/core/space.py +1 -1
  14. siibra/core/structure.py +2 -2
  15. siibra/exceptions.py +6 -2
  16. siibra/experimental/__init__.py +1 -1
  17. siibra/experimental/contour.py +2 -2
  18. siibra/experimental/cortical_profile_sampler.py +1 -1
  19. siibra/experimental/patch.py +1 -1
  20. siibra/experimental/plane3d.py +4 -4
  21. siibra/explorer/__init__.py +1 -1
  22. siibra/explorer/url.py +2 -2
  23. siibra/explorer/util.py +1 -1
  24. siibra/features/__init__.py +1 -1
  25. siibra/features/anchor.py +2 -2
  26. siibra/features/connectivity/__init__.py +1 -1
  27. siibra/features/connectivity/functional_connectivity.py +1 -1
  28. siibra/features/connectivity/regional_connectivity.py +2 -2
  29. siibra/features/connectivity/streamline_counts.py +1 -1
  30. siibra/features/connectivity/streamline_lengths.py +1 -1
  31. siibra/features/connectivity/tracing_connectivity.py +1 -1
  32. siibra/features/dataset/__init__.py +1 -1
  33. siibra/features/dataset/ebrains.py +1 -1
  34. siibra/features/feature.py +10 -10
  35. siibra/features/image/__init__.py +1 -1
  36. siibra/features/image/image.py +2 -2
  37. siibra/features/image/sections.py +1 -1
  38. siibra/features/image/volume_of_interest.py +1 -1
  39. siibra/features/tabular/__init__.py +1 -1
  40. siibra/features/tabular/bigbrain_intensity_profile.py +1 -1
  41. siibra/features/tabular/cell_density_profile.py +2 -2
  42. siibra/features/tabular/cortical_profile.py +3 -3
  43. siibra/features/tabular/gene_expression.py +1 -1
  44. siibra/features/tabular/layerwise_bigbrain_intensities.py +1 -1
  45. siibra/features/tabular/layerwise_cell_density.py +1 -1
  46. siibra/features/tabular/receptor_density_fingerprint.py +13 -10
  47. siibra/features/tabular/receptor_density_profile.py +1 -1
  48. siibra/features/tabular/regional_timeseries_activity.py +2 -2
  49. siibra/features/tabular/tabular.py +7 -5
  50. siibra/livequeries/__init__.py +1 -1
  51. siibra/livequeries/allen.py +3 -3
  52. siibra/livequeries/bigbrain.py +15 -6
  53. siibra/livequeries/ebrains.py +1 -1
  54. siibra/livequeries/query.py +2 -2
  55. siibra/locations/__init__.py +2 -2
  56. siibra/locations/boundingbox.py +3 -7
  57. siibra/locations/location.py +1 -1
  58. siibra/locations/point.py +3 -3
  59. siibra/locations/pointcloud.py +9 -14
  60. siibra/retrieval/__init__.py +1 -1
  61. siibra/retrieval/cache.py +1 -1
  62. siibra/retrieval/datasets.py +4 -4
  63. siibra/retrieval/exceptions/__init__.py +1 -1
  64. siibra/retrieval/repositories.py +4 -4
  65. siibra/retrieval/requests.py +6 -6
  66. siibra/vocabularies/__init__.py +1 -1
  67. siibra/volumes/__init__.py +1 -1
  68. siibra/volumes/parcellationmap.py +31 -10
  69. siibra/volumes/providers/__init__.py +1 -1
  70. siibra/volumes/providers/freesurfer.py +3 -3
  71. siibra/volumes/providers/gifti.py +1 -1
  72. siibra/volumes/providers/neuroglancer.py +6 -6
  73. siibra/volumes/providers/nifti.py +1 -1
  74. siibra/volumes/providers/provider.py +1 -1
  75. siibra/volumes/sparsemap.py +1 -1
  76. siibra/volumes/volume.py +12 -12
  77. {siibra-1.0.1a0.dist-info → siibra-1.0.1a1.dist-info}/METADATA +12 -3
  78. siibra-1.0.1a1.dist-info/RECORD +84 -0
  79. {siibra-1.0.1a0.dist-info → siibra-1.0.1a1.dist-info}/WHEEL +1 -1
  80. siibra-1.0.1a0.dist-info/RECORD +0 -84
  81. {siibra-1.0.1a0.dist-info → siibra-1.0.1a1.dist-info}/LICENSE +0 -0
  82. {siibra-1.0.1a0.dist-info → siibra-1.0.1a1.dist-info}/top_level.txt +0 -0
siibra/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.1-alpha.0
1
+ 1.0.1-alpha.1
siibra/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -108,7 +108,7 @@ def set_feasible_download_size(maxsize_gbyte):
108
108
 
109
109
  def set_cache_size(maxsize_gbyte: int):
110
110
  """
111
- siibra runs maintainance on its local cache to keep it under a predetermined
111
+ siibra runs maintenance on its local cache to keep it under a predetermined
112
112
  size of 2 gigabytes. This method changes the cache size.
113
113
 
114
114
  Parameters
@@ -129,9 +129,9 @@ def warm_cache(level=WarmupLevel.INSTANCE):
129
129
  Preload preconfigured siibra concepts.
130
130
 
131
131
  Siibra relies on preconfigurations that simplify integrating various
132
- concepts such as parcellations, refernce spaces, and multimodal data
132
+ concepts such as parcellations, reference spaces, and multimodal data
133
133
  features. By preloading the instances, siibra commits all preconfigurations
134
- to the memory at once instead of commiting them when required.
134
+ to the memory at once instead of committing them when required.
135
135
  """
136
136
  Warmup.warmup(level)
137
137
 
siibra/commons.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -139,7 +139,7 @@ class InstanceTable(Generic[T], Iterable):
139
139
  return (w for w in self._elements.values())
140
140
 
141
141
  def __contains__(self, key: Union[str, T]) -> bool:
142
- """Test wether the given key or element is defined by the registry."""
142
+ """Test whether the given key or element is defined by the registry."""
143
143
  if isinstance(key, str):
144
144
  return key in self._elements
145
145
  return key in [item for _, item in self._elements.values()]
@@ -536,7 +536,8 @@ def resample_img_to_img(
536
536
  resampled_img = resample_to_img(
537
537
  source_img=source_img,
538
538
  target_img=target_img,
539
- interpolation=interpolation
539
+ interpolation=interpolation,
540
+ force_resample=True, # False is intended for testing. see nilearn docs
540
541
  )
541
542
  return resampled_img
542
543
 
@@ -554,7 +555,7 @@ def connected_components(
554
555
 
555
556
  Note
556
557
  ----
557
- `Uses skimage.measure.label()` to determine foreground compenents.
558
+ `Uses skimage.measure.label()` to determine foreground components.
558
559
 
559
560
  Parameters
560
561
  ----------
@@ -568,7 +569,7 @@ def connected_components(
568
569
  Yields
569
570
  ------
570
571
  Generator[Tuple[int, np.ndarray], None, None]
571
- tuple of integer label of the component and component as an nd.array in
572
+ tuple of integer label of the component and component as an ndarray in
572
573
  the shape of the original image.
573
574
  """
574
575
  from skimage import measure
@@ -644,11 +645,11 @@ def MI(arr1, arr2, nbins=100, normalized=True):
644
645
  assert (all(arr.size > 0) for arr in [arr1, arr2])
645
646
 
646
647
  # compute the normalized joint 2D histogram as an
647
- # empirical measure of the joint probabily of arr1 and arr2
648
+ # empirical measure of the joint probability of arr1 and arr2
648
649
  pxy, _, _ = np.histogram2d(arr1.ravel(), arr2.ravel(), bins=nbins)
649
650
  pxy /= pxy.sum()
650
651
 
651
- # extract the empirical propabilities of intensities
652
+ # extract the empirical probabilities of intensities
652
653
  # from the joint histogram
653
654
  px = np.sum(pxy, axis=1) # marginal for x over y
654
655
  py = np.sum(pxy, axis=0) # marginal for y over x
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
siibra/core/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
siibra/core/assignment.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
siibra/core/atlas.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
siibra/core/concept.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -145,9 +145,9 @@ class AtlasConcept:
145
145
  @property
146
146
  def authors(self):
147
147
  return [
148
- contributer['name']
148
+ contributor['name']
149
149
  for ds in self.datasets
150
- for contributer in ds.contributors
150
+ for contributor in ds.contributors
151
151
  ]
152
152
 
153
153
  @property
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,7 @@ from . import region
17
17
 
18
18
  from ..commons import logger, MapType, Species
19
19
  from ..volumes import parcellationmap
20
- from ..exceptions import NoMapMatchingValues
20
+ from ..exceptions import MapNotFound
21
21
 
22
22
  from functools import lru_cache
23
23
  import re
@@ -193,13 +193,13 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
193
193
  and m.parcellation.matches(self)
194
194
  ]
195
195
  if len(candidates) == 0:
196
- raise NoMapMatchingValues(f"No '{maptype}' map in '{space}' available for {str(self)}")
196
+ raise MapNotFound(f"No '{maptype}' map in '{space}' available for {str(self)}")
197
197
  if len(candidates) > 1:
198
198
  spec_candidates = [
199
199
  c for c in candidates if all(w.lower() in c.id.lower() for w in spec.split())
200
200
  ]
201
201
  if len(spec_candidates) == 0:
202
- raise NoMapMatchingValues(f"'{spec}' does not match any options from {[c.name for c in candidates]}.")
202
+ raise MapNotFound(f"'{spec}' does not match any options from {[c.name for c in candidates]}.")
203
203
  if len(spec_candidates) > 1:
204
204
  logger.warning(
205
205
  f"Multiple maps are available in this specification of space, parcellation, and map type.\n"
@@ -221,7 +221,7 @@ class Parcellation(region.Region, configuration_folder="parcellations"):
221
221
  """
222
222
  spec = re.sub(r'Group: *', '', spec)
223
223
  for substr in re.findall(r'\(.*?\)', spec):
224
- # temporarilty replace commas inside brackets with a placeholder
224
+ # temporarily replace commas inside brackets with a placeholder
225
225
  # because these are not region spec delimiters
226
226
  spec = spec.replace(substr, re.sub(r', *', '##', substr))
227
227
  # process the comma separated substrings
@@ -354,7 +354,7 @@ def find_regions(
354
354
  ):
355
355
  """
356
356
  Find regions matching the given region specification across all parcellation
357
- instances in the registery.
357
+ instances in the registry.
358
358
 
359
359
  Parameters
360
360
  ----------
siibra/core/region.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,7 +31,7 @@ from ..exceptions import NoMapAvailableError, SpaceWarpingFailedError
31
31
 
32
32
  import re
33
33
  import anytree
34
- from typing import List, Union, Iterable, Dict, Callable, Tuple
34
+ from typing import List, Union, Iterable, Dict, Callable, Tuple, Set
35
35
  from difflib import SequenceMatcher
36
36
  from ebrains_drive import BucketApiClient
37
37
  import json
@@ -53,8 +53,8 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
53
53
  _regex_re = re.compile(r'^\/(?P<expression>.+)\/(?P<flags>[a-zA-Z]*)$')
54
54
  _accepted_flags = "aiLmsux"
55
55
 
56
- _GETMAP_CACHE = {}
57
- _GETMAP_CACHE_MAX_ENTRIES = 1
56
+ _GETMASK_CACHE = {}
57
+ _GETMASK_CACHE_MAX_ENTRIES = 1
58
58
 
59
59
  def __init__(
60
60
  self,
@@ -111,20 +111,20 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
111
111
  )
112
112
 
113
113
  # anytree node will take care to use this appropriately
114
- self.parent = parent
115
- self.children = children
114
+ self.parent: "Region" = parent
115
+ self.children: List["Region"] = children
116
116
  # convert hex to int tuple if rgb is given
117
117
  self.rgb = (
118
118
  None if rgb is None
119
119
  else tuple(int(rgb[p:p + 2], 16) for p in [1, 3, 5])
120
120
  )
121
- self._supported_spaces = None # computed on 1st call of self.supported_spaces
121
+ self._supported_spaces: Set[_space.Space] = None # computed on 1st call of self.supported_spaces
122
122
  self._str_aliases = None
123
123
  self.find = lru_cache(maxsize=3)(self.find)
124
124
 
125
125
  def get_related_regions(self) -> Iterable["RegionRelationAssessments"]:
126
126
  """
127
- Get assements on relations of this region to others defined on EBRAINS.
127
+ Get assessments on relations of this region to others defined on EBRAINS.
128
128
 
129
129
  Yields
130
130
  ------
@@ -133,8 +133,8 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
133
133
  Example
134
134
  -------
135
135
  >>> region = siibra.get_region("monkey", "PG")
136
- >>> for assesment in region.get_related_regions():
137
- >>> print(assesment)
136
+ >>> for assessment in region.get_related_regions():
137
+ >>> print(assessment)
138
138
  'PG' is homologous to 'Area PGa (IPL)'
139
139
  'PG' is homologous to 'Area PGa (IPL) left'
140
140
  'PG' is homologous to 'Area PGa (IPL) right'
@@ -441,12 +441,21 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
441
441
  maptype = MapType[maptype.upper()]
442
442
 
443
443
  threshold_info = "" if maptype == MapType.LABELLED else f"(threshold: {threshold}) "
444
+ # check cache
445
+ getmask_hash = hash(f"{self.id} - {space} - {maptype}{threshold_info}")
446
+ if getmask_hash in self._GETMASK_CACHE:
447
+ return self._GETMASK_CACHE[getmask_hash]
448
+
444
449
  name = f"Mask {threshold_info}of '{self.name} ({self.parcellation})' in "
445
450
  try:
446
451
  regional_map = self.get_regional_map(space=space, maptype=maptype)
447
452
  if maptype == MapType.LABELLED:
448
453
  assert threshold == 0.0, f"threshold can only be set for {MapType.STATISTICAL} maps."
449
- result = regional_map
454
+ result = volume.FilteredVolume(
455
+ parent_volume=regional_map,
456
+ label=regional_map.label,
457
+ fragment=regional_map.fragment
458
+ )
450
459
  result._boundingbox = None
451
460
  if maptype == MapType.STATISTICAL:
452
461
  result = volume.FilteredVolume(
@@ -456,21 +465,30 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
456
465
  if threshold == 0.0:
457
466
  result._boundingbox = regional_map._boundingbox
458
467
  name += f"'{result.space}'"
459
- except NoMapAvailableError:
468
+ except NoMapAvailableError as e:
460
469
  # This region is not mapped directly in any map in the registry.
461
470
  # Try building a map from the child regions
462
- if (len(self.children) > 0) and all(c.mapped_in_space(space) for c in self.children):
463
- logger.info(f"{self.name} is not mapped in {space}. Merging the masks of its {len(self.children)} child regions.")
464
- child_volumes = [
465
- child.get_regional_mask(space=space, maptype=maptype, threshold=threshold)
466
- for child in self.children
471
+ if (len(self.children) > 0) and self.mapped_in_space(space, recurse=True):
472
+ mapped_descendants: List[Region] = [
473
+ d for d in self.descendants if d.mapped_in_space(space, recurse=False)
474
+ ]
475
+ logger.info(f"{self.name} is not mapped in {space}. Merging the masks of its {len(mapped_descendants)} map descendants.")
476
+ descendant_volumes = [
477
+ descendant.get_regional_mask(space=space, maptype=maptype, threshold=threshold)
478
+ for descendant in mapped_descendants
467
479
  ]
468
480
  result = volume.FilteredVolume(
469
- volume.merge(child_volumes),
481
+ volume.merge(descendant_volumes),
470
482
  label=1
471
483
  )
472
- name += f"'{result.space}' (built by merging the mask {threshold_info} of its decendants)"
484
+ name += f"'{result.space}' (built by merging the mask {threshold_info} of its descendants)"
485
+ else:
486
+ raise e
473
487
  result._name = name
488
+
489
+ while len(self._GETMASK_CACHE) > self._GETMASK_CACHE_MAX_ENTRIES:
490
+ self._GETMASK_CACHE.pop(next(iter(self._GETMASK_CACHE)))
491
+ self._GETMASK_CACHE[getmask_hash] = result
474
492
  return result
475
493
 
476
494
  def get_regional_map(
@@ -479,7 +497,7 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
479
497
  maptype: MapType = MapType.LABELLED,
480
498
  ) -> Union[volume.FilteredVolume, volume.Volume, volume.Subvolume]:
481
499
  """
482
- Get a volume reprsenting this region in the given space and MapType.
500
+ Get a volume representing this region in the given space and MapType.
483
501
 
484
502
  Note
485
503
  ----
@@ -515,34 +533,31 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
515
533
  and self.name in m.regions
516
534
  ):
517
535
  return m.get_volume(region=self)
518
- else:
519
- raise NoMapAvailableError(
520
- f"{self.name} is not mapped in {space} as a {str(maptype)} map."
521
- " Please try getting the children or getting the mask."
522
- )
536
+ raise NoMapAvailableError(
537
+ f"{self.name} is not mapped in {space} as a {str(maptype)} map."
538
+ " Please try getting the children or getting the mask."
539
+ )
523
540
 
524
- def mapped_in_space(self, space, recurse: bool = True) -> bool:
541
+ def mapped_in_space(self, space, recurse: bool = False) -> bool:
525
542
  """
526
- Verifies wether this region is defined by an explicit map in the given space.
543
+ Verifies whether this region is defined by an explicit map in the given space.
527
544
 
528
545
  Parameters
529
546
  ----------
530
547
  space: Space or str
531
548
  reference space
532
- recurse: bool, default: True
533
- If True, check if all child regions are mapped instead
549
+ recurse: bool, default: False
550
+ If True, check if itself or all child regions are mapped instead recursively.
534
551
  Returns
535
552
  -------
536
553
  bool
537
554
  """
538
555
  from ..volumes.parcellationmap import Map
539
556
  for m in Map.registry():
540
- # Use and operant for efficiency (short circuiting logic)
541
- # Put the most inexpensive logic first
542
557
  if (
543
- self.name in m.regions
544
- and m.space.matches(space)
558
+ m.space.matches(space)
545
559
  and m.parcellation.matches(self.parcellation)
560
+ and self.name in m.regions
546
561
  ):
547
562
  return True
548
563
  if recurse and not self.is_leaf:
@@ -553,21 +568,16 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
553
568
  @property
554
569
  def supported_spaces(self) -> List[_space.Space]:
555
570
  """
556
- The set of spaces for which a mask could be extracted.
557
- Overwrites the corresponding method of AtlasConcept.
571
+ The list of spaces for which a mask could be extracted from an existing
572
+ map or combination of masks of its children.
558
573
  """
559
574
  if self._supported_spaces is None:
560
- self._supported_spaces = sorted(
561
- {s for s in _space.Space.registry() if self.mapped_in_space(s)}
562
- )
575
+ self._supported_spaces = sorted({
576
+ s for s in _space.Space.registry()
577
+ if self.mapped_in_space(s, recurse=True)
578
+ })
563
579
  return self._supported_spaces
564
580
 
565
- def supports_space(self, space: _space.Space):
566
- """
567
- Return true if this region supports the given space, else False.
568
- """
569
- return any(s.matches(space) for s in self.supported_spaces)
570
-
571
581
  @property
572
582
  def spaces(self):
573
583
  return InstanceTable(
@@ -610,7 +620,7 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
610
620
  return self._ASSIGNMENT_CACHE[other, self].invert()
611
621
 
612
622
  if isinstance(other, (location.Location, volume.Volume)):
613
- if self.mapped_in_space(other.space):
623
+ if self.mapped_in_space(other.space, recurse=True):
614
624
  regionmap = self.get_regional_mask(other.space)
615
625
  self._ASSIGNMENT_CACHE[self, other] = regionmap.assign(other)
616
626
  return self._ASSIGNMENT_CACHE[self, other]
@@ -842,7 +852,7 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
842
852
  def intersection(self, other: "location.Location") -> "location.Location":
843
853
  """Use this region for filtering a location object."""
844
854
 
845
- if self.supports_space(other.space):
855
+ if self.mapped_in_space(other.space, recurse=True):
846
856
  try:
847
857
  volume = self.get_regional_mask(other.space)
848
858
  if volume is not None:
@@ -908,7 +918,7 @@ def get_peid_from_region(region: Region) -> str:
908
918
 
909
919
  def get_related_regions(region: Region) -> Iterable["RegionRelationAssessments"]:
910
920
  """
911
- Get assements on relations of a region to others defined on EBRAINS.
921
+ Get assessments on relations of a region to others defined on EBRAINS.
912
922
 
913
923
  Parameters
914
924
  ----------
@@ -921,8 +931,8 @@ def get_related_regions(region: Region) -> Iterable["RegionRelationAssessments"]
921
931
  Example
922
932
  -------
923
933
  >>> region = siibra.get_region("monkey", "PG")
924
- >>> for assesment in siibra.core.region.get_related_regions(region):
925
- >>> print(assesment)
934
+ >>> for assessment in siibra.core.region.get_related_regions(region):
935
+ >>> print(assessment)
926
936
  'PG' is homologous to 'Area PGa (IPL)'
927
937
  'PG' is homologous to 'Area PGa (IPL) left'
928
938
  'PG' is homologous to 'Area PGa (IPL) right'
siibra/core/space.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
siibra/core/structure.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -76,7 +76,7 @@ class BrainStructure(ABC):
76
76
  # Two cases:
77
77
  # 1) self is location, other is location -> look at spatial intersection/relationship, do it here
78
78
  # 2) self is location, other is region -> get region map, then call again. do it here
79
- # If self is region -> Region overwrite this method, adressed there
79
+ # If self is region -> Region overwrite this method, addressed there
80
80
 
81
81
  assert not isinstance(self, _region.Region) # method is overwritten by Region!
82
82
  if (self, other) in self._ASSIGNMENT_CACHE:
siibra/exceptions.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -55,9 +55,13 @@ class NoneCoordinateSuppliedError(ValueError):
55
55
  pass
56
56
 
57
57
 
58
- class NoMapMatchingValues(ValueError):
58
+ class MapNotFound(ValueError):
59
59
  pass
60
60
 
61
61
 
62
62
  class EmptyPointCloudError(ValueError):
63
63
  pass
64
+
65
+
66
+ class NoPredifinedColormapException(ValueError):
67
+ pass
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -46,7 +46,7 @@ class Contour(pointcloud.PointCloud):
46
46
 
47
47
  if cropped is not None and not isinstance(cropped, point.Point):
48
48
  assert isinstance(cropped, pointcloud.PointCloud)
49
- # Identifiy contour splits are by discontinuouities ("jumps")
49
+ # Identify contour splits are by discontinuouities ("jumps")
50
50
  # of their labels, which denote positions in the original contour
51
51
  jumps = np.diff([self.labels.index(lb) for lb in cropped.labels])
52
52
  splits = [0] + list(np.where(jumps > 1)[0] + 1) + [len(cropped)]
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,7 +33,7 @@ class Plane3D:
33
33
  The plane's reference space is defined by the first point.
34
34
  """
35
35
  self.space = point1.space
36
- # normal is the cross product of two arbitray in-plane vectors
36
+ # normal is the cross product of two arbitrary in-plane vectors
37
37
  n = np.cross(
38
38
  (point2.warp(self.space) - point1).coordinate,
39
39
  (point3.warp(self.space) - point1).coordinate,
@@ -107,7 +107,7 @@ class Plane3D:
107
107
  )[0]
108
108
  faces = mesh["faces"][face_indices]
109
109
 
110
- # for each of N selected faces, indicate wether we cross the plane
110
+ # for each of N selected faces, indicate whether we cross the plane
111
111
  # as we go from vertex 2->0, 0->1, 1->2, respectively.
112
112
  # This gives us an Nx3 array, where forward crossings are identified by 1,
113
113
  # and backward crossings by -1.
@@ -160,7 +160,7 @@ class Plane3D:
160
160
  face_id = 0 # index of the mesh face to consider
161
161
  while len(face_indices) > 0:
162
162
 
163
- # continue the contour with the next foward edge intersection
163
+ # continue the contour with the next forward edge intersection
164
164
  p = fwd_intersections[face_id]
165
165
  points.append(p)
166
166
  # Remember the ids of the face and start-/end vertices for the point
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
siibra/explorer/url.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -211,7 +211,7 @@ def get_hash(full_string: str):
211
211
  for char in full_string:
212
212
  # overflowing is expected and in fact the whole reason why convert number to int32
213
213
 
214
- # in windows, int32((0 - min_int32) << 5), rather than overflow to wraper around, raises OverflowError
214
+ # in windows, int32((0 - min_int32) << 5), rather than overflow to wrapper around, raises OverflowError
215
215
  shifted_5 = int32(
216
216
  (return_val - min_int32) if return_val > max_int32 else return_val << 5
217
217
  )
siibra/explorer/util.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
siibra/features/anchor.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -88,7 +88,7 @@ class AnatomicalAnchor:
88
88
 
89
89
  @property
90
90
  def space(self) -> Space:
91
- # may be overriden by derived classes, e.g. in features.VolumeOfInterest
91
+ # may be overridden by derived classes, e.g. in features.VolumeOfInterest
92
92
  return None if self.location is None else self.location.space
93
93
 
94
94
  @property
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -275,7 +275,7 @@ class RegionalConnectivity(Feature, Compoundable):
275
275
 
276
276
  regions = [r for r in matrix.index if matches(r, region)]
277
277
  if len(regions) == 0:
278
- raise ValueError(f"Invalid region specificiation: {region}")
278
+ raise ValueError(f"Invalid region specification: {region}")
279
279
  elif len(regions) > 1:
280
280
  raise ValueError(f"Region specification {region} matched more than one profile: {regions}")
281
281
  else:
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
1
- # Copyright 2018-2024
1
+ # Copyright 2018-2025
2
2
  # Institute of Neuroscience and Medicine (INM-1), Forschungszentrum Jülich GmbH
3
3
 
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");