From 6cb9cd2f0ae2c05ff53f8b2b4cb541347caacc20 Mon Sep 17 00:00:00 2001 From: valentin-pinkau Date: Mon, 11 Aug 2025 17:22:45 +0200 Subject: [PATCH 1/2] add get_segments_for_agglomerate to RemoteAnnotation --- .../webknossos/annotation/annotation.py | 31 +++++++++++++++++++ .../webknossos/client/api_client/models.py | 14 +++++++++ .../api_client/tracingstore_api_client.py | 11 +++++++ 3 files changed, 56 insertions(+) diff --git a/webknossos/webknossos/annotation/annotation.py b/webknossos/webknossos/annotation/annotation.py index c7f8f44cc..b1913c387 100644 --- a/webknossos/webknossos/annotation/annotation.py +++ b/webknossos/webknossos/annotation/annotation.py @@ -1520,6 +1520,7 @@ def _set_annotation_info( modified=annotation_info.modified, data_store=annotation_info.data_store, tracing_time=annotation_info.tracing_time, + annotation_layers=None, ), ) @@ -1528,6 +1529,36 @@ def save(self, path: str | PathLike) -> None: "Remote annotations cannot be saved. Changes are applied ." ) + def get_segments_for_agglomerate(self, agglomerate_id: int) -> list[int]: + """Get the segment ids for a given agglomerate id. + + Args: + agglomerate_id (int): The agglomerate id. + + Returns: + np.ndarray: The segment ids. + """ + from ..client.context import _get_context + + context = _get_context() + annotation_info = self._get_annotation_info() + assert annotation_info.annotation_layers is not None, "Annotation has no layers" + tracingstore_client = context.get_tracingstore_api_client() + volume_layer = [ + layer + for layer in annotation_info.annotation_layers + if layer.typ == "Volume" + ] + assert len(volume_layer) == 1, "Expected exactly one volume layer" + segment_list_result = tracingstore_client.get_segments_for_agglomerate( + volume_layer[0].tracing_id, agglomerate_id + ) + segment_list = segment_list_result.segmentIds + assert segment_list_result.agglomerateIdIsPresent, ( + "This agglomerate was not edited in this annotation. To get the segment ids, check the underlying agglomerate view" + ) + return segment_list + def download_mesh( self, segment_id: int, diff --git a/webknossos/webknossos/client/api_client/models.py b/webknossos/webknossos/client/api_client/models.py index 299056fc6..049b60a7d 100644 --- a/webknossos/webknossos/client/api_client/models.py +++ b/webknossos/webknossos/client/api_client/models.py @@ -357,6 +357,19 @@ class ApiProjectCreate: owner: str | None = None +@attr.s(auto_attribs=True) +class ApiAnnotationLayer: + tracing_id: str + typ: str + name: str + + +@attr.s(auto_attribs=True) +class ApiEditableMappingSegmentListResult: + segmentIds: list[int] + agglomerateIdIsPresent: bool + + @attr.s(auto_attribs=True) class ApiAnnotation: id: str @@ -366,6 +379,7 @@ class ApiAnnotation: description: str state: str modified: int + annotation_layers: list[ApiAnnotationLayer] | None data_store: ApiDataStore | None = None tracing_time: int | None = None # millis diff --git a/webknossos/webknossos/client/api_client/tracingstore_api_client.py b/webknossos/webknossos/client/api_client/tracingstore_api_client.py index 103d19e76..8b22be557 100644 --- a/webknossos/webknossos/client/api_client/tracingstore_api_client.py +++ b/webknossos/webknossos/client/api_client/tracingstore_api_client.py @@ -2,6 +2,7 @@ from webknossos.client.api_client.models import ( ApiAdHocMeshInfo, + ApiEditableMappingSegmentListResult, ApiPrecomputedMeshInfo, ) @@ -26,6 +27,16 @@ def __init__( def url_prefix(self) -> str: return f"{self.base_url}/tracings" + def get_segments_for_agglomerate( + self, tracing_id: str, agglomerate_id: int + ) -> ApiEditableMappingSegmentListResult: + route = f"/mapping/{tracing_id}/segmentsForAgglomerate" + query: Query = {"agglomerateId": agglomerate_id} + + return self._get_json( + route, query=query, response_type=ApiEditableMappingSegmentListResult + ) + def annotation_download_mesh( self, mesh: ApiPrecomputedMeshInfo | ApiAdHocMeshInfo, From 0c025210623beb87f51288b0b789117ff7e7fed9 Mon Sep 17 00:00:00 2001 From: valentin-pinkau Date: Tue, 12 Aug 2025 10:55:48 +0200 Subject: [PATCH 2/2] return None if agglomerate was not edited --- webknossos/webknossos/annotation/annotation.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/webknossos/webknossos/annotation/annotation.py b/webknossos/webknossos/annotation/annotation.py index b1913c387..920540798 100644 --- a/webknossos/webknossos/annotation/annotation.py +++ b/webknossos/webknossos/annotation/annotation.py @@ -1529,14 +1529,14 @@ def save(self, path: str | PathLike) -> None: "Remote annotations cannot be saved. Changes are applied ." ) - def get_segments_for_agglomerate(self, agglomerate_id: int) -> list[int]: + def get_segments_for_agglomerate(self, agglomerate_id: int) -> list[int] | None: """Get the segment ids for a given agglomerate id. Args: agglomerate_id (int): The agglomerate id. Returns: - np.ndarray: The segment ids. + List[int] | None: The segment ids if the agglomerate was edited, None otherwise. """ from ..client.context import _get_context @@ -1554,10 +1554,10 @@ def get_segments_for_agglomerate(self, agglomerate_id: int) -> list[int]: volume_layer[0].tracing_id, agglomerate_id ) segment_list = segment_list_result.segmentIds - assert segment_list_result.agglomerateIdIsPresent, ( - "This agglomerate was not edited in this annotation. To get the segment ids, check the underlying agglomerate view" - ) - return segment_list + if segment_list_result.agglomerateIdIsPresent: + return segment_list + else: + return None def download_mesh( self,