siibra 1.0.1a0__py3-none-any.whl → 1.0.1a2__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.
- siibra/VERSION +1 -1
- siibra/__init__.py +11 -20
- siibra/commons.py +17 -14
- siibra/configuration/__init__.py +1 -1
- siibra/configuration/configuration.py +6 -6
- siibra/configuration/factory.py +10 -9
- siibra/core/__init__.py +2 -2
- siibra/core/assignment.py +2 -1
- siibra/core/atlas.py +4 -4
- siibra/core/concept.py +7 -5
- siibra/core/parcellation.py +10 -10
- siibra/core/region.py +82 -73
- siibra/core/space.py +5 -7
- siibra/core/structure.py +4 -4
- siibra/exceptions.py +6 -2
- siibra/explorer/__init__.py +1 -1
- siibra/explorer/url.py +2 -2
- siibra/explorer/util.py +1 -1
- siibra/features/__init__.py +1 -1
- siibra/features/anchor.py +4 -6
- siibra/features/connectivity/__init__.py +1 -1
- siibra/features/connectivity/functional_connectivity.py +1 -1
- siibra/features/connectivity/regional_connectivity.py +12 -15
- siibra/features/connectivity/streamline_counts.py +1 -1
- siibra/features/connectivity/streamline_lengths.py +1 -1
- siibra/features/connectivity/tracing_connectivity.py +1 -1
- siibra/features/dataset/__init__.py +1 -1
- siibra/features/dataset/ebrains.py +2 -2
- siibra/features/feature.py +31 -28
- siibra/features/image/__init__.py +5 -3
- siibra/features/image/image.py +4 -6
- siibra/features/image/sections.py +82 -3
- siibra/features/image/volume_of_interest.py +1 -9
- siibra/features/tabular/__init__.py +2 -2
- siibra/features/tabular/bigbrain_intensity_profile.py +3 -2
- siibra/features/tabular/cell_density_profile.py +10 -11
- siibra/features/tabular/cortical_profile.py +9 -9
- siibra/features/tabular/gene_expression.py +7 -6
- siibra/features/tabular/layerwise_bigbrain_intensities.py +5 -4
- siibra/features/tabular/layerwise_cell_density.py +5 -7
- siibra/features/tabular/receptor_density_fingerprint.py +47 -19
- siibra/features/tabular/receptor_density_profile.py +2 -3
- siibra/features/tabular/regional_timeseries_activity.py +9 -9
- siibra/features/tabular/tabular.py +10 -9
- siibra/livequeries/__init__.py +1 -1
- siibra/livequeries/allen.py +23 -25
- siibra/livequeries/bigbrain.py +252 -55
- siibra/livequeries/ebrains.py +14 -11
- siibra/livequeries/query.py +5 -5
- siibra/locations/__init__.py +19 -10
- siibra/locations/boundingbox.py +10 -13
- siibra/{experimental/plane3d.py → locations/experimental.py} +117 -17
- siibra/locations/location.py +11 -13
- siibra/locations/point.py +10 -19
- siibra/locations/pointcloud.py +59 -23
- siibra/retrieval/__init__.py +1 -1
- siibra/retrieval/cache.py +2 -1
- siibra/retrieval/datasets.py +23 -17
- siibra/retrieval/exceptions/__init__.py +1 -1
- siibra/retrieval/repositories.py +14 -15
- siibra/retrieval/requests.py +32 -30
- siibra/vocabularies/__init__.py +2 -3
- siibra/volumes/__init__.py +5 -4
- siibra/volumes/parcellationmap.py +55 -20
- siibra/volumes/providers/__init__.py +1 -1
- siibra/volumes/providers/freesurfer.py +7 -7
- siibra/volumes/providers/gifti.py +5 -5
- siibra/volumes/providers/neuroglancer.py +25 -28
- siibra/volumes/providers/nifti.py +7 -7
- siibra/volumes/providers/provider.py +4 -3
- siibra/volumes/sparsemap.py +8 -7
- siibra/volumes/volume.py +33 -40
- {siibra-1.0.1a0.dist-info → siibra-1.0.1a2.dist-info}/METADATA +21 -8
- siibra-1.0.1a2.dist-info/RECORD +80 -0
- {siibra-1.0.1a0.dist-info → siibra-1.0.1a2.dist-info}/WHEEL +1 -1
- siibra/experimental/__init__.py +0 -19
- siibra/experimental/contour.py +0 -61
- siibra/experimental/cortical_profile_sampler.py +0 -57
- siibra/experimental/patch.py +0 -98
- siibra-1.0.1a0.dist-info/RECORD +0 -84
- {siibra-1.0.1a0.dist-info → siibra-1.0.1a2.dist-info}/LICENSE +0 -0
- {siibra-1.0.1a0.dist-info → siibra-1.0.1a2.dist-info}/top_level.txt +0 -0
siibra/core/region.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2018-
|
|
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");
|
|
@@ -14,9 +14,18 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
"""Representation of a brain region."""
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
from
|
|
17
|
+
import re
|
|
18
|
+
from typing import List, Union, Iterable, Dict, Callable, Tuple, Set
|
|
19
|
+
from difflib import SequenceMatcher
|
|
20
|
+
import json
|
|
21
|
+
from functools import wraps, reduce
|
|
22
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
23
|
+
from functools import lru_cache
|
|
24
|
+
|
|
25
|
+
import anytree
|
|
26
|
+
from ebrains_drive import BucketApiClient
|
|
19
27
|
|
|
28
|
+
from . import concept, structure, space as _space, parcellation as _parcellation, assignment
|
|
20
29
|
from ..retrieval.cache import cache_user_fn
|
|
21
30
|
from ..locations import location, pointcloud, boundingbox as _boundingbox
|
|
22
31
|
from ..volumes import parcellationmap, volume
|
|
@@ -29,16 +38,6 @@ from ..commons import (
|
|
|
29
38
|
)
|
|
30
39
|
from ..exceptions import NoMapAvailableError, SpaceWarpingFailedError
|
|
31
40
|
|
|
32
|
-
import re
|
|
33
|
-
import anytree
|
|
34
|
-
from typing import List, Union, Iterable, Dict, Callable, Tuple
|
|
35
|
-
from difflib import SequenceMatcher
|
|
36
|
-
from ebrains_drive import BucketApiClient
|
|
37
|
-
import json
|
|
38
|
-
from functools import wraps, reduce
|
|
39
|
-
from concurrent.futures import ThreadPoolExecutor
|
|
40
|
-
from functools import lru_cache
|
|
41
|
-
|
|
42
41
|
|
|
43
42
|
REGEX_TYPE = type(re.compile("test"))
|
|
44
43
|
|
|
@@ -53,8 +52,8 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
|
|
|
53
52
|
_regex_re = re.compile(r'^\/(?P<expression>.+)\/(?P<flags>[a-zA-Z]*)$')
|
|
54
53
|
_accepted_flags = "aiLmsux"
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
_GETMASK_CACHE = {}
|
|
56
|
+
_GETMASK_CACHE_MAX_ENTRIES = 1
|
|
58
57
|
|
|
59
58
|
def __init__(
|
|
60
59
|
self,
|
|
@@ -111,30 +110,30 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
|
|
|
111
110
|
)
|
|
112
111
|
|
|
113
112
|
# anytree node will take care to use this appropriately
|
|
114
|
-
self.parent = parent
|
|
115
|
-
self.children = children
|
|
113
|
+
self.parent: "Region" = parent
|
|
114
|
+
self.children: List["Region"] = children
|
|
116
115
|
# convert hex to int tuple if rgb is given
|
|
117
116
|
self.rgb = (
|
|
118
117
|
None if rgb is None
|
|
119
118
|
else tuple(int(rgb[p:p + 2], 16) for p in [1, 3, 5])
|
|
120
119
|
)
|
|
121
|
-
self._supported_spaces = None # computed on 1st call of self.supported_spaces
|
|
120
|
+
self._supported_spaces: Set[_space.Space] = None # computed on 1st call of self.supported_spaces
|
|
122
121
|
self._str_aliases = None
|
|
123
122
|
self.find = lru_cache(maxsize=3)(self.find)
|
|
124
123
|
|
|
125
124
|
def get_related_regions(self) -> Iterable["RegionRelationAssessments"]:
|
|
126
125
|
"""
|
|
127
|
-
Get
|
|
126
|
+
Get assessments on relations of this region to others defined on EBRAINS.
|
|
128
127
|
|
|
129
128
|
Yields
|
|
130
129
|
------
|
|
131
|
-
Qualification
|
|
130
|
+
assignment.Qualification
|
|
132
131
|
|
|
133
132
|
Example
|
|
134
133
|
-------
|
|
135
134
|
>>> region = siibra.get_region("monkey", "PG")
|
|
136
|
-
>>> for
|
|
137
|
-
>>> print(
|
|
135
|
+
>>> for assessment in region.get_related_regions():
|
|
136
|
+
>>> print(assessment)
|
|
138
137
|
'PG' is homologous to 'Area PGa (IPL)'
|
|
139
138
|
'PG' is homologous to 'Area PGa (IPL) left'
|
|
140
139
|
'PG' is homologous to 'Area PGa (IPL) right'
|
|
@@ -441,12 +440,21 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
|
|
|
441
440
|
maptype = MapType[maptype.upper()]
|
|
442
441
|
|
|
443
442
|
threshold_info = "" if maptype == MapType.LABELLED else f"(threshold: {threshold}) "
|
|
443
|
+
# check cache
|
|
444
|
+
getmask_hash = hash(f"{self.id} - {space} - {maptype}{threshold_info}")
|
|
445
|
+
if getmask_hash in self._GETMASK_CACHE:
|
|
446
|
+
return self._GETMASK_CACHE[getmask_hash]
|
|
447
|
+
|
|
444
448
|
name = f"Mask {threshold_info}of '{self.name} ({self.parcellation})' in "
|
|
445
449
|
try:
|
|
446
450
|
regional_map = self.get_regional_map(space=space, maptype=maptype)
|
|
447
451
|
if maptype == MapType.LABELLED:
|
|
448
452
|
assert threshold == 0.0, f"threshold can only be set for {MapType.STATISTICAL} maps."
|
|
449
|
-
result =
|
|
453
|
+
result = volume.FilteredVolume(
|
|
454
|
+
parent_volume=regional_map,
|
|
455
|
+
label=regional_map.label,
|
|
456
|
+
fragment=regional_map.fragment
|
|
457
|
+
)
|
|
450
458
|
result._boundingbox = None
|
|
451
459
|
if maptype == MapType.STATISTICAL:
|
|
452
460
|
result = volume.FilteredVolume(
|
|
@@ -456,21 +464,30 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
|
|
|
456
464
|
if threshold == 0.0:
|
|
457
465
|
result._boundingbox = regional_map._boundingbox
|
|
458
466
|
name += f"'{result.space}'"
|
|
459
|
-
except NoMapAvailableError:
|
|
467
|
+
except NoMapAvailableError as e:
|
|
460
468
|
# This region is not mapped directly in any map in the registry.
|
|
461
469
|
# Try building a map from the child regions
|
|
462
|
-
if (len(self.children) > 0) and
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
470
|
+
if (len(self.children) > 0) and self.mapped_in_space(space, recurse=True):
|
|
471
|
+
mapped_descendants: List[Region] = [
|
|
472
|
+
d for d in self.descendants if d.mapped_in_space(space, recurse=False)
|
|
473
|
+
]
|
|
474
|
+
logger.info(f"{self.name} is not mapped in {space}. Merging the masks of its {len(mapped_descendants)} map descendants.")
|
|
475
|
+
descendant_volumes = [
|
|
476
|
+
descendant.get_regional_mask(space=space, maptype=maptype, threshold=threshold)
|
|
477
|
+
for descendant in mapped_descendants
|
|
467
478
|
]
|
|
468
479
|
result = volume.FilteredVolume(
|
|
469
|
-
volume.merge(
|
|
480
|
+
volume.merge(descendant_volumes),
|
|
470
481
|
label=1
|
|
471
482
|
)
|
|
472
|
-
name += f"'{result.space}' (built by merging the mask {threshold_info} of its
|
|
483
|
+
name += f"'{result.space}' (built by merging the mask {threshold_info} of its descendants)"
|
|
484
|
+
else:
|
|
485
|
+
raise e
|
|
473
486
|
result._name = name
|
|
487
|
+
|
|
488
|
+
while len(self._GETMASK_CACHE) > self._GETMASK_CACHE_MAX_ENTRIES:
|
|
489
|
+
self._GETMASK_CACHE.pop(next(iter(self._GETMASK_CACHE)))
|
|
490
|
+
self._GETMASK_CACHE[getmask_hash] = result
|
|
474
491
|
return result
|
|
475
492
|
|
|
476
493
|
def get_regional_map(
|
|
@@ -479,7 +496,7 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
|
|
|
479
496
|
maptype: MapType = MapType.LABELLED,
|
|
480
497
|
) -> Union[volume.FilteredVolume, volume.Volume, volume.Subvolume]:
|
|
481
498
|
"""
|
|
482
|
-
Get a volume
|
|
499
|
+
Get a volume representing this region in the given space and MapType.
|
|
483
500
|
|
|
484
501
|
Note
|
|
485
502
|
----
|
|
@@ -515,34 +532,31 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
|
|
|
515
532
|
and self.name in m.regions
|
|
516
533
|
):
|
|
517
534
|
return m.get_volume(region=self)
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
)
|
|
535
|
+
raise NoMapAvailableError(
|
|
536
|
+
f"{self.name} is not mapped in {space} as a {str(maptype)} map."
|
|
537
|
+
" Please try getting the children or getting the mask."
|
|
538
|
+
)
|
|
523
539
|
|
|
524
|
-
def mapped_in_space(self, space, recurse: bool =
|
|
540
|
+
def mapped_in_space(self, space, recurse: bool = False) -> bool:
|
|
525
541
|
"""
|
|
526
|
-
Verifies
|
|
542
|
+
Verifies whether this region is defined by an explicit map in the given space.
|
|
527
543
|
|
|
528
544
|
Parameters
|
|
529
545
|
----------
|
|
530
546
|
space: Space or str
|
|
531
547
|
reference space
|
|
532
|
-
recurse: bool, default:
|
|
533
|
-
If True, check if all child regions are mapped instead
|
|
548
|
+
recurse: bool, default: False
|
|
549
|
+
If True, check if itself or all child regions are mapped instead recursively.
|
|
534
550
|
Returns
|
|
535
551
|
-------
|
|
536
552
|
bool
|
|
537
553
|
"""
|
|
538
554
|
from ..volumes.parcellationmap import Map
|
|
539
555
|
for m in Map.registry():
|
|
540
|
-
# Use and operant for efficiency (short circuiting logic)
|
|
541
|
-
# Put the most inexpensive logic first
|
|
542
556
|
if (
|
|
543
|
-
|
|
544
|
-
and m.space.matches(space)
|
|
557
|
+
m.space.matches(space)
|
|
545
558
|
and m.parcellation.matches(self.parcellation)
|
|
559
|
+
and self.name in m.regions
|
|
546
560
|
):
|
|
547
561
|
return True
|
|
548
562
|
if recurse and not self.is_leaf:
|
|
@@ -553,21 +567,16 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
|
|
|
553
567
|
@property
|
|
554
568
|
def supported_spaces(self) -> List[_space.Space]:
|
|
555
569
|
"""
|
|
556
|
-
The
|
|
557
|
-
|
|
570
|
+
The list of spaces for which a mask could be extracted from an existing
|
|
571
|
+
map or combination of masks of its children.
|
|
558
572
|
"""
|
|
559
573
|
if self._supported_spaces is None:
|
|
560
|
-
self._supported_spaces = sorted(
|
|
561
|
-
|
|
562
|
-
|
|
574
|
+
self._supported_spaces = sorted({
|
|
575
|
+
s for s in _space.Space.registry()
|
|
576
|
+
if self.mapped_in_space(s, recurse=True)
|
|
577
|
+
})
|
|
563
578
|
return self._supported_spaces
|
|
564
579
|
|
|
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
580
|
@property
|
|
572
581
|
def spaces(self):
|
|
573
582
|
return InstanceTable(
|
|
@@ -585,7 +594,7 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
|
|
|
585
594
|
except NoMapAvailableError:
|
|
586
595
|
return False
|
|
587
596
|
|
|
588
|
-
def assign(self, other: structure.BrainStructure) -> AnatomicalAssignment:
|
|
597
|
+
def assign(self, other: structure.BrainStructure) -> assignment.AnatomicalAssignment:
|
|
589
598
|
"""
|
|
590
599
|
Compute assignment of a location to this region.
|
|
591
600
|
|
|
@@ -599,8 +608,8 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
|
|
|
599
608
|
|
|
600
609
|
Returns
|
|
601
610
|
-------
|
|
602
|
-
AnatomicalAssignment or None
|
|
603
|
-
None if there is no Qualification found.
|
|
611
|
+
assignment.AnatomicalAssignment or None
|
|
612
|
+
None if there is no assignment.Qualification found.
|
|
604
613
|
"""
|
|
605
614
|
if (self, other) in self._ASSIGNMENT_CACHE:
|
|
606
615
|
return self._ASSIGNMENT_CACHE[self, other]
|
|
@@ -610,7 +619,7 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
|
|
|
610
619
|
return self._ASSIGNMENT_CACHE[other, self].invert()
|
|
611
620
|
|
|
612
621
|
if isinstance(other, (location.Location, volume.Volume)):
|
|
613
|
-
if self.mapped_in_space(other.space):
|
|
622
|
+
if self.mapped_in_space(other.space, recurse=True):
|
|
614
623
|
regionmap = self.get_regional_mask(other.space)
|
|
615
624
|
self._ASSIGNMENT_CACHE[self, other] = regionmap.assign(other)
|
|
616
625
|
return self._ASSIGNMENT_CACHE[self, other]
|
|
@@ -649,17 +658,17 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
|
|
|
649
658
|
else: # other is a Region
|
|
650
659
|
assert isinstance(other, Region)
|
|
651
660
|
if self == other:
|
|
652
|
-
qualification = Qualification.EXACT
|
|
661
|
+
qualification = assignment.Qualification.EXACT
|
|
653
662
|
elif self.__contains__(other):
|
|
654
|
-
qualification = Qualification.CONTAINS
|
|
663
|
+
qualification = assignment.Qualification.CONTAINS
|
|
655
664
|
elif other.__contains__(self):
|
|
656
|
-
qualification = Qualification.CONTAINED
|
|
665
|
+
qualification = assignment.Qualification.CONTAINED
|
|
657
666
|
else:
|
|
658
667
|
qualification = None
|
|
659
668
|
if qualification is None:
|
|
660
669
|
self._ASSIGNMENT_CACHE[self, other] = None
|
|
661
670
|
else:
|
|
662
|
-
self._ASSIGNMENT_CACHE[self, other] = AnatomicalAssignment(self, other, qualification)
|
|
671
|
+
self._ASSIGNMENT_CACHE[self, other] = assignment.AnatomicalAssignment(self, other, qualification)
|
|
663
672
|
return self._ASSIGNMENT_CACHE[self, other]
|
|
664
673
|
|
|
665
674
|
def tree2str(self):
|
|
@@ -842,7 +851,7 @@ class Region(anytree.NodeMixin, concept.AtlasConcept, structure.BrainStructure):
|
|
|
842
851
|
def intersection(self, other: "location.Location") -> "location.Location":
|
|
843
852
|
"""Use this region for filtering a location object."""
|
|
844
853
|
|
|
845
|
-
if self.
|
|
854
|
+
if self.mapped_in_space(other.space, recurse=True):
|
|
846
855
|
try:
|
|
847
856
|
volume = self.get_regional_mask(other.space)
|
|
848
857
|
if volume is not None:
|
|
@@ -908,7 +917,7 @@ def get_peid_from_region(region: Region) -> str:
|
|
|
908
917
|
|
|
909
918
|
def get_related_regions(region: Region) -> Iterable["RegionRelationAssessments"]:
|
|
910
919
|
"""
|
|
911
|
-
Get
|
|
920
|
+
Get assessments on relations of a region to others defined on EBRAINS.
|
|
912
921
|
|
|
913
922
|
Parameters
|
|
914
923
|
----------
|
|
@@ -916,13 +925,13 @@ def get_related_regions(region: Region) -> Iterable["RegionRelationAssessments"]
|
|
|
916
925
|
|
|
917
926
|
Yields
|
|
918
927
|
------
|
|
919
|
-
Qualification
|
|
928
|
+
assignment.Qualification
|
|
920
929
|
|
|
921
930
|
Example
|
|
922
931
|
-------
|
|
923
932
|
>>> region = siibra.get_region("monkey", "PG")
|
|
924
|
-
>>> for
|
|
925
|
-
>>> print(
|
|
933
|
+
>>> for assessment in siibra.core.region.get_related_regions(region):
|
|
934
|
+
>>> print(assessment)
|
|
926
935
|
'PG' is homologous to 'Area PGa (IPL)'
|
|
927
936
|
'PG' is homologous to 'Area PGa (IPL) left'
|
|
928
937
|
'PG' is homologous to 'Area PGa (IPL) right'
|
|
@@ -958,7 +967,7 @@ def _register_region_reference_type(ebrain_type: str):
|
|
|
958
967
|
return outer
|
|
959
968
|
|
|
960
969
|
|
|
961
|
-
class RegionRelationAssessments(AnatomicalAssignment[Region]):
|
|
970
|
+
class RegionRelationAssessments(assignment.AnatomicalAssignment[Region]):
|
|
962
971
|
"""
|
|
963
972
|
A collection of methods on finding related regions and the quantification
|
|
964
973
|
of the relationship.
|
|
@@ -1100,7 +1109,7 @@ class RegionRelationAssessments(AnatomicalAssignment[Region]):
|
|
|
1100
1109
|
yield cls(
|
|
1101
1110
|
query_structure=src,
|
|
1102
1111
|
assigned_structure=found_target,
|
|
1103
|
-
qualification=Qualification.parse_relation_assessment(overlap)
|
|
1112
|
+
qualification=assignment.Qualification.parse_relation_assessment(overlap)
|
|
1104
1113
|
)
|
|
1105
1114
|
|
|
1106
1115
|
if "https://openminds.ebrains.eu/sands/ParcellationEntity" in target.get("type"):
|
|
@@ -1114,7 +1123,7 @@ class RegionRelationAssessments(AnatomicalAssignment[Region]):
|
|
|
1114
1123
|
yield cls(
|
|
1115
1124
|
query_structure=src,
|
|
1116
1125
|
assigned_structure=reg,
|
|
1117
|
-
qualification=Qualification.parse_relation_assessment(overlap)
|
|
1126
|
+
qualification=assignment.Qualification.parse_relation_assessment(overlap)
|
|
1118
1127
|
)
|
|
1119
1128
|
|
|
1120
1129
|
@classmethod
|
|
@@ -1168,7 +1177,7 @@ class RegionRelationAssessments(AnatomicalAssignment[Region]):
|
|
|
1168
1177
|
yield cls(
|
|
1169
1178
|
query_structure=src,
|
|
1170
1179
|
assigned_structure=region,
|
|
1171
|
-
qualification=Qualification.OTHER_VERSION
|
|
1180
|
+
qualification=assignment.Qualification.OTHER_VERSION
|
|
1172
1181
|
)
|
|
1173
1182
|
|
|
1174
1183
|
# homologuous
|
siibra/core/space.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2018-
|
|
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");
|
|
@@ -14,18 +14,16 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
"""A particular brain reference space."""
|
|
16
16
|
|
|
17
|
+
from typing import List, TYPE_CHECKING, Union
|
|
17
18
|
|
|
18
|
-
from .
|
|
19
|
-
|
|
19
|
+
from . import concept
|
|
20
20
|
from ..commons import logger, Species
|
|
21
21
|
|
|
22
|
-
from typing import List, TYPE_CHECKING, Union
|
|
23
|
-
|
|
24
22
|
if TYPE_CHECKING:
|
|
25
23
|
from ..volumes import volume
|
|
26
24
|
|
|
27
25
|
|
|
28
|
-
class Space(AtlasConcept, configuration_folder="spaces"):
|
|
26
|
+
class Space(concept.AtlasConcept, configuration_folder="spaces"):
|
|
29
27
|
|
|
30
28
|
def __init__(
|
|
31
29
|
self,
|
|
@@ -66,7 +64,7 @@ class Space(AtlasConcept, configuration_folder="spaces"):
|
|
|
66
64
|
Key: EBRAINS KG schema, value: EBRAINS KG @id
|
|
67
65
|
"""
|
|
68
66
|
|
|
69
|
-
AtlasConcept.__init__(
|
|
67
|
+
concept.AtlasConcept.__init__(
|
|
70
68
|
self,
|
|
71
69
|
identifier=identifier,
|
|
72
70
|
name=name,
|
siibra/core/structure.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2018-
|
|
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");
|
|
@@ -21,11 +21,11 @@ a brain region is a structure which is at the same time an AtlasConcept. A
|
|
|
21
21
|
bounding box in MNI space is a structure, but not an AtlasConcept.
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
|
-
from . import assignment, region as _region
|
|
25
|
-
|
|
26
24
|
from abc import ABC, abstractmethod
|
|
27
25
|
from typing import Tuple, Dict
|
|
28
26
|
|
|
27
|
+
from . import assignment, region as _region
|
|
28
|
+
|
|
29
29
|
|
|
30
30
|
class BrainStructure(ABC):
|
|
31
31
|
"""Abstract base class for types who can act as a location filter."""
|
|
@@ -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,
|
|
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-
|
|
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
|
|
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
|
siibra/explorer/__init__.py
CHANGED
siibra/explorer/url.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2018-
|
|
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
|
|
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
siibra/features/__init__.py
CHANGED
siibra/features/anchor.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2018-
|
|
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");
|
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
"""Handles the relation between study targets and BrainStructures."""
|
|
16
16
|
|
|
17
|
-
from
|
|
17
|
+
from typing import Union, List, Dict, Iterable
|
|
18
18
|
|
|
19
|
+
from ..commons import Species, logger
|
|
19
20
|
from ..core.structure import BrainStructure
|
|
20
21
|
from ..core.assignment import AnatomicalAssignment, Qualification
|
|
21
22
|
from ..locations.location import Location
|
|
@@ -23,11 +24,8 @@ from ..core.parcellation import Parcellation, find_regions
|
|
|
23
24
|
from ..core.region import Region
|
|
24
25
|
from ..core.space import Space
|
|
25
26
|
from ..exceptions import SpaceWarpingFailedError
|
|
26
|
-
|
|
27
27
|
from ..vocabularies import REGION_ALIASES
|
|
28
28
|
|
|
29
|
-
from typing import Union, List, Dict, Iterable
|
|
30
|
-
|
|
31
29
|
|
|
32
30
|
class AnatomicalAnchor:
|
|
33
31
|
"""
|
|
@@ -88,7 +86,7 @@ class AnatomicalAnchor:
|
|
|
88
86
|
|
|
89
87
|
@property
|
|
90
88
|
def space(self) -> Space:
|
|
91
|
-
# may be
|
|
89
|
+
# may be overridden by derived classes, e.g. in features.VolumeOfInterest
|
|
92
90
|
return None if self.location is None else self.location.space
|
|
93
91
|
|
|
94
92
|
@property
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2018-
|
|
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");
|
|
@@ -14,11 +14,18 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
16
|
from zipfile import ZipFile
|
|
17
|
-
from
|
|
18
|
-
|
|
17
|
+
from typing import Callable, Union, List, Tuple, Iterator
|
|
18
|
+
try:
|
|
19
|
+
from typing import Literal
|
|
20
|
+
except ImportError: # support python 3.7
|
|
21
|
+
from typing_extensions import Literal
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
import numpy as np
|
|
24
|
+
import pandas as pd
|
|
21
25
|
|
|
26
|
+
from .. import anchor as _anchor
|
|
27
|
+
from ..feature import Feature, Compoundable
|
|
28
|
+
from ..tabular.tabular import Tabular
|
|
22
29
|
from ...commons import logger, QUIET, siibra_tqdm
|
|
23
30
|
from ...core import region as _region
|
|
24
31
|
from ...locations import pointcloud
|
|
@@ -26,16 +33,6 @@ from ...retrieval.repositories import RepositoryConnector
|
|
|
26
33
|
from ...retrieval.requests import HttpRequest
|
|
27
34
|
|
|
28
35
|
|
|
29
|
-
import pandas as pd
|
|
30
|
-
import numpy as np
|
|
31
|
-
from typing import Callable, Union, List, Tuple, Iterator
|
|
32
|
-
|
|
33
|
-
try:
|
|
34
|
-
from typing import Literal
|
|
35
|
-
except ImportError: # support python 3.7
|
|
36
|
-
from typing_extensions import Literal
|
|
37
|
-
|
|
38
|
-
|
|
39
36
|
class RegionalConnectivity(Feature, Compoundable):
|
|
40
37
|
"""
|
|
41
38
|
Parcellation-averaged connectivity, providing one or more matrices of a
|
|
@@ -275,7 +272,7 @@ class RegionalConnectivity(Feature, Compoundable):
|
|
|
275
272
|
|
|
276
273
|
regions = [r for r in matrix.index if matches(r, region)]
|
|
277
274
|
if len(regions) == 0:
|
|
278
|
-
raise ValueError(f"Invalid region
|
|
275
|
+
raise ValueError(f"Invalid region specification: {region}")
|
|
279
276
|
elif len(regions) > 1:
|
|
280
277
|
raise ValueError(f"Region specification {region} matched more than one profile: {regions}")
|
|
281
278
|
else:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2018-
|
|
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");
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
"""Non-preconfigured data features hosted at EBRAINS."""
|
|
16
16
|
|
|
17
17
|
from zipfile import ZipFile
|
|
18
|
+
|
|
18
19
|
from .. import anchor as _anchor
|
|
19
20
|
from .. import feature
|
|
20
|
-
|
|
21
21
|
from ...retrieval import datasets
|
|
22
22
|
|
|
23
23
|
|