Skip to content

Commit 7356d42

Browse files
authored
Merge pull request #637 from FZJ-INM1-BDA/fix_query_bbprof_w_locations
Fix: query BigBrainProfileIntensity with locations
2 parents 3c900fe + bc7c1d5 commit 7356d42

File tree

5 files changed

+76
-25
lines changed

5 files changed

+76
-25
lines changed

e2e/features/test_get.py

+54-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import pytest
2-
import siibra
32
from e2e.util import check_duplicate
43

4+
import siibra
5+
from siibra.locations import Location, PointCloud
6+
from siibra.livequeries.bigbrain import WagstylProfileLoader
7+
from siibra.features.feature import CompoundFeature
8+
9+
import numpy as np
10+
511

612
# We get all registered subclasses of Feature
713
@pytest.mark.parametrize(
@@ -67,8 +73,53 @@ def test_querying_with_volume():
6773
# Use features with location anchors only. Because hybrid ones will also
6874
# employ semantic links between regions, potentially changing the result.
6975
region = siibra.get_region("julich 2.9", "ca1")
70-
volume = region.get_regional_mask('mni152')
76+
volume = region.get_regional_mask("mni152")
7177
profiles_region = siibra.features.get(region, "BigBrainIntensityProfile")[0]
7278
profiles_volume = siibra.features.get(volume, "BigBrainIntensityProfile")[0]
7379
# the ids will be different but the content has to be the same. Even the order.
74-
assert [p.location for p in profiles_region] == [p.location for p in profiles_volume]
80+
assert [p.location for p in profiles_region] == [
81+
p.location for p in profiles_volume
82+
]
83+
84+
85+
WagstylProfileLoader._load()
86+
verts = WagstylProfileLoader._vertices
87+
np.random.seed(10)
88+
loc_queries = [
89+
(
90+
siibra.get_map("julich 2.9", "bigbrain")
91+
.get_volume("hoc1 left")
92+
.get_boundingbox(clip=True),
93+
"BigBrainIntensityProfile",
94+
13968,
95+
),
96+
(
97+
PointCloud(verts[np.random.randint(0, len(verts) - 1, 100)], space="bigbrain"),
98+
"BigBrainIntensityProfile",
99+
100,
100+
),
101+
(
102+
PointCloud(
103+
np.concatenate(
104+
[
105+
verts[np.random.randint(0, len(verts) - 1, 100)] + 1000,
106+
verts[np.random.randint(0, len(verts) - 1, 10)],
107+
]
108+
),
109+
space="bigbrain",
110+
),
111+
"BigBrainIntensityProfile",
112+
10,
113+
),
114+
]
115+
116+
117+
@pytest.mark.parametrize("loc, feat_type, res_len", loc_queries)
118+
def test_query_w_locations(loc: Location, feat_type: str, res_len: int):
119+
results = siibra.features.get(loc, feat_type)
120+
assert len(results) > 0
121+
assert results[0].data is not None
122+
if len(results) == 1 and isinstance(results[0], CompoundFeature):
123+
assert len(results[0]) == res_len
124+
else:
125+
assert len(results) == res_len

siibra/core/region.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def __init__(
124124

125125
def get_related_regions(self) -> Iterable["RegionRelationAssessments"]:
126126
"""
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.
128128
129129
Yields
130130
------
@@ -918,7 +918,7 @@ def get_peid_from_region(region: Region) -> str:
918918

919919
def get_related_regions(region: Region) -> Iterable["RegionRelationAssessments"]:
920920
"""
921-
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.
922922
923923
Parameters
924924
----------

siibra/livequeries/bigbrain.py

+13-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from ..features.tabular import bigbrain_intensity_profile, layerwise_bigbrain_intensities
2020
from ..features import anchor as _anchor
2121
from ..commons import logger
22-
from ..locations import point, pointcloud
22+
from ..locations import point, pointcloud, location
2323
from ..core import structure
2424
from ..retrieval import requests, cache
2525
from ..retrieval.datasets import GenericDataset
@@ -123,11 +123,16 @@ def query(self, concept: structure.BrainStructure, **kwargs) -> List[bigbrain_in
123123
matched = concept.intersection(mesh_vertices) # returns a reduced PointCloud with og indices as labels
124124
if matched is None:
125125
return []
126+
if isinstance(matched, point.Point):
127+
matched = pointcloud.from_points([matched])
126128
assert isinstance(matched, pointcloud.PointCloud)
129+
if isinstance(concept, location.Location):
130+
mesh_as_list = mesh_vertices.as_list()
131+
matched.labels = [mesh_as_list.index(v.coordinate) for v in matched]
127132
indices = matched.labels
128133
assert indices is not None
129134
features = []
130-
for i in matched.labels:
135+
for i in indices:
131136
anchor = _anchor.AnatomicalAnchor(
132137
location=point.Point(loader._vertices[i], space='bigbrain'),
133138
region=str(concept),
@@ -160,12 +165,16 @@ def query(self, concept: structure.BrainStructure, **kwargs) -> List[layerwise_b
160165

161166
loader = WagstylProfileLoader()
162167
mesh_vertices = pointcloud.PointCloud(loader._vertices, space='bigbrain')
163-
matched = concept.intersection(mesh_vertices) # returns a reduced PointCloud with og indices as labels
168+
matched = concept.intersection(mesh_vertices) # returns a reduced PointCloud with og indices as labels if the concept is a region
164169
if matched is None:
165170
return []
171+
if isinstance(matched, point.Point):
172+
matched = pointcloud.from_points([matched])
166173
assert isinstance(matched, pointcloud.PointCloud)
174+
if isinstance(concept, location.Location):
175+
mesh_as_list = mesh_vertices.as_list()
176+
matched.labels = [mesh_as_list.index(v.coordinate) for v in matched]
167177
indices = matched.labels
168-
assert indices is not None
169178
matched_profiles = loader._profiles[indices, :]
170179
boundary_depths = loader._boundary_depths[indices, :]
171180
# compute array of layer labels for all coefficients in profiles_left

siibra/locations/boundingbox.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,7 @@ def intersection(self, other: 'BrainStructure', dims=[0, 1, 2]):
148148
points_inside = [p for p in other if self.intersects(p)]
149149
if len(points_inside) == 0:
150150
return None
151-
result = pointcloud.PointCloud(
152-
points_inside,
153-
space=other.space,
154-
sigma_mm=[p.sigma for p in points_inside]
155-
)
151+
result = pointcloud.from_points(points_inside)
156152
return result[0] if len(result) == 1 else result # if PointCloud has single point return as a Point
157153

158154
return other.intersection(self)

siibra/locations/pointcloud.py

+6-11
Original file line numberDiff line numberDiff line change
@@ -120,18 +120,13 @@ def intersection(self, other: location.Location):
120120
if not isinstance(other, (point.Point, PointCloud, _boundingbox.BoundingBox)):
121121
return other.intersection(self)
122122

123-
intersections = [(i, p) for i, p in enumerate(self) if p.intersects(other)]
124-
if len(intersections) == 0:
123+
if isinstance(other, PointCloud):
124+
intersecting_points = [p for p in self if p.coordinate in other.coordinates]
125+
else:
126+
intersecting_points = [p for p in self if p.intersects(other)]
127+
if len(intersecting_points) == 0:
125128
return None
126-
ids, points = zip(*intersections)
127-
labels = None if self.labels is None else [self.labels[i] for i in ids]
128-
sigma = [p.sigma for p in points]
129-
intersection = PointCloud(
130-
points,
131-
space=self.space,
132-
sigma_mm=sigma,
133-
labels=labels
134-
)
129+
intersection = from_points(intersecting_points)
135130
return intersection[0] if len(intersection) == 1 else intersection
136131

137132
@property

0 commit comments

Comments
 (0)