From 09c8830be5166c87dd532f9262f22980b74c2d11 Mon Sep 17 00:00:00 2001 From: Ahmet Nihat Simsek Date: Fri, 17 Nov 2023 16:01:20 +0100 Subject: [PATCH 1/2] introduce `Compoundable._merge_anchors` for special cases. Use original implementation by default. --- siibra/features/anchor.py | 4 ++-- siibra/features/feature.py | 6 ++++- .../tabular/bigbrain_intensity_profile.py | 22 +++++++++++++++++-- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/siibra/features/anchor.py b/siibra/features/anchor.py index b0ec17740..f8559b4a7 100644 --- a/siibra/features/anchor.py +++ b/siibra/features/anchor.py @@ -25,7 +25,7 @@ from ..vocabularies import REGION_ALIASES -from typing import Union, List, Dict +from typing import Union, List, Dict, Iterable class AnatomicalAnchor: @@ -45,7 +45,7 @@ def __init__( if isinstance(species, (str, Species)): self.species = {Species.decode(species)} - elif isinstance(species, list): + elif isinstance(species, Iterable): assert all(isinstance(_, Species) for _ in species) self.species = set(species) else: diff --git a/siibra/features/feature.py b/siibra/features/feature.py index 912234b4d..12fb62b4e 100644 --- a/siibra/features/feature.py +++ b/siibra/features/feature.py @@ -667,6 +667,10 @@ def _element_index(self) -> Any: assert hash(index), "`_element_index` of a compoundable must be hashable." return index + @classmethod + def _merge_anchors(cls, anchors: List[_anchor.AnatomicalAnchor]): + return sum(anchors) + class CompoundFeature(Feature): """ @@ -711,7 +715,7 @@ def __init__( self, modality=modality, description="\n".join({f.description for f in elements}), - anchor=sum([f.anchor for f in elements]), + anchor=self._feature_type._merge_anchors([f.anchor for f in elements]), datasets=list(dict.fromkeys([ds for f in elements for ds in f.datasets])) ) self._queryconcept = queryconcept diff --git a/siibra/features/tabular/bigbrain_intensity_profile.py b/siibra/features/tabular/bigbrain_intensity_profile.py index 74a2f7c6e..687095a78 100644 --- a/siibra/features/tabular/bigbrain_intensity_profile.py +++ b/siibra/features/tabular/bigbrain_intensity_profile.py @@ -15,7 +15,9 @@ from . import cortical_profile -from ...locations import point +from typing import List, TYPE_CHECKING +if TYPE_CHECKING: + from ...locations import point class BigBrainIntensityProfile( @@ -42,7 +44,7 @@ def __init__( depths: list, values: list, boundaries: list, - location: point.Point + location: 'point.Point' ): from ..anchor import AnatomicalAnchor anchor = AnatomicalAnchor( @@ -67,3 +69,19 @@ def __init__( @property def location(self): return self.anchor.location + + @classmethod + def _merge_anchors(cls, anchors: List['AnatomicalAnchor']): + from ...locations.pointset import PointSet + from ...features.anchor import AnatomicalAnchor + + location = PointSet( + [anchor.location for anchor in anchors], + space="BigBrain" + ) + regions = {anchor._regionspec for anchor in anchors} + return AnatomicalAnchor( + location=location, + region=", ".join(regions), + species='Homo sapiens' + ) From 4d6f42ff79030a11c5000be26ea9ed98c3a83aa1 Mon Sep 17 00:00:00 2001 From: Ahmet Nihat Simsek Date: Thu, 14 Dec 2023 11:10:36 +0100 Subject: [PATCH 2/2] Create anchors of BigBrainIntensity features in bigbrain.py to use the same logic and avoid unnecessary imports --- .../tabular/bigbrain_intensity_profile.py | 13 +++---------- .../tabular/layerwise_bigbrain_intensities.py | 12 +++++------- siibra/livequeries/bigbrain.py | 18 +++++++++++++----- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/siibra/features/tabular/bigbrain_intensity_profile.py b/siibra/features/tabular/bigbrain_intensity_profile.py index 687095a78..70172bdb7 100644 --- a/siibra/features/tabular/bigbrain_intensity_profile.py +++ b/siibra/features/tabular/bigbrain_intensity_profile.py @@ -17,7 +17,7 @@ from typing import List, TYPE_CHECKING if TYPE_CHECKING: - from ...locations import point + from ...features.anchor import AnatomicalAnchor class BigBrainIntensityProfile( @@ -40,18 +40,11 @@ class BigBrainIntensityProfile( def __init__( self, - regionname: str, + anchor: "AnatomicalAnchor", depths: list, values: list, - boundaries: list, - location: 'point.Point' + boundaries: list ): - from ..anchor import AnatomicalAnchor - anchor = AnatomicalAnchor( - location=location, - region=regionname, - species='Homo sapiens' - ) cortical_profile.CorticalProfile.__init__( self, description=self.DESCRIPTION, diff --git a/siibra/features/tabular/layerwise_bigbrain_intensities.py b/siibra/features/tabular/layerwise_bigbrain_intensities.py index b374b15a4..af73f4bb6 100644 --- a/siibra/features/tabular/layerwise_bigbrain_intensities.py +++ b/siibra/features/tabular/layerwise_bigbrain_intensities.py @@ -19,6 +19,10 @@ import pandas as pd import numpy as np +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from ...features.anchor import AnatomicalAnchor + class LayerwiseBigBrainIntensities( tabular.Tabular, @@ -39,16 +43,10 @@ class LayerwiseBigBrainIntensities( def __init__( self, - regionname: str, + anchor: "AnatomicalAnchor", means: list, stds: list, ): - - from ..anchor import AnatomicalAnchor - anchor = AnatomicalAnchor( - region=regionname, - species='Homo sapiens', - ) data = pd.DataFrame( np.array([means, stds]).T, columns=['mean', 'std'], diff --git a/siibra/livequeries/bigbrain.py b/siibra/livequeries/bigbrain.py index fc77f4226..190983ade 100644 --- a/siibra/livequeries/bigbrain.py +++ b/siibra/livequeries/bigbrain.py @@ -88,12 +88,16 @@ def query(self, concept: structure.BrainStructure, **kwargs) -> List[bigbrain_in matched = concept.intersection(pointset.PointSet(loader._vertices, space='bigbrain')) assert matched.labels is not None for i in matched.labels: + anchor = _anchor.AnatomicalAnchor( + location=point.Point(loader._vertices[i], space='bigbrain'), + region=str(concept), + species='Homo sapiens' + ) prof = bigbrain_intensity_profile.BigBrainIntensityProfile( - regionname=str(concept), + anchor=anchor, depths=loader.profile_labels, values=loader._profiles[i], - boundaries=loader._boundary_depths[i], - location=point.Point(loader._vertices[i], space='bigbrain') + boundaries=loader._boundary_depths[i] ) prof.anchor._assignments[concept] = _anchor.AnatomicalAssignment( query_structure=concept, @@ -128,12 +132,16 @@ def query(self, concept: structure.BrainStructure, **kwargs) -> List[layerwise_b for b in boundary_depths ]).reshape((-1, 200)) + anchor = _anchor.AnatomicalAnchor( + location=pointset.PointSet(loader._vertices[indices, :], space='bigbrain'), + region=str(concept), + species='Homo sapiens' + ) result = layerwise_bigbrain_intensities.LayerwiseBigBrainIntensities( - regionname=str(concept), + anchor=anchor, means=[matched_profiles[layer_labels == layer].mean() for layer in range(1, 7)], stds=[matched_profiles[layer_labels == layer].std() for layer in range(1, 7)], ) - result.anchor._location_cached = pointset.PointSet(loader._vertices[indices, :], space='bigbrain') result.anchor._assignments[concept] = _anchor.AnatomicalAssignment( query_structure=concept, assigned_structure=concept,