From 753a82e9bac1a83379c5eab0d13b8b2a45ac715a Mon Sep 17 00:00:00 2001 From: Andy Sweet Date: Wed, 15 May 2024 16:42:47 -0700 Subject: [PATCH] Merge with offset fix --- src/napari_cryoet_data_portal/_open_widget.py | 39 +++++++++---------- src/napari_cryoet_data_portal/_sample_data.py | 4 +- .../_tests/test_open_widget.py | 4 +- .../_tests/test_reader.py | 3 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/napari_cryoet_data_portal/_open_widget.py b/src/napari_cryoet_data_portal/_open_widget.py index 5df928a..3b15f78 100644 --- a/src/napari_cryoet_data_portal/_open_widget.py +++ b/src/napari_cryoet_data_portal/_open_widget.py @@ -34,16 +34,6 @@ class Resolution: indices: Tuple[int, ...] scale: float - @property - def offset(self) -> float: - """The offset due to a larger first pixel for lower resolutions. - - When visualized in napari, this ensures that the different multi-scale - layers opened separately share the same visual extent in the canvas that - starts at (-0.5, -0.5, -0.5). - """ - return (self.scale - 1) / 2 - MULTI_RESOLUTION = Resolution(name="Multi", indices=(0, 1, 2), scale=1) HIGH_RESOLUTION = Resolution(name="High", indices=(0,), scale=1) @@ -139,7 +129,8 @@ def _loadTomogram( ) -> Generator[FullLayerData, None, None]: logger.debug("OpenWidget._loadTomogram: %s", tomogram.name) image_layer = read_tomogram(tomogram) - # Extract image_scale before the resolution is taken into account. + # Extract image_scale before the resolution is taken into account, + # so we can use it to align other annotations later. image_scale = image_layer[1]["scale"] yield _handle_image_at_resolution(image_layer, resolution) @@ -155,9 +146,9 @@ def _loadTomogram( for annotation in annotations: for layer in read_annotation_files(annotation, tomogram=tomogram): if layer[2] == "labels": - layer = _handle_image_at_resolution(layer, resolution=resolution) + layer = _handle_image_at_resolution(layer, resolution) elif layer[2] == "points": - layer = _handle_points_annotation(layer, image_scale) + layer = _handle_points_at_scale(layer, image_scale) yield layer def _onLayerLoaded(self, layer_data: FullLayerData) -> None: @@ -186,17 +177,25 @@ def _handle_image_at_resolution(layer_data: FullLayerData, resolution: Resolutio data = np.asarray(data) # Adjust the scale and and translation based on the resolution. - attrs["scale"] = tuple(resolution.scale * s for s in attrs["scale"]) - image_translate = attrs.get("translate", (0,) * len(attrs["scale"])) - attrs["translate"] = tuple(resolution.offset + t for t in image_translate) + image_scale = attrs["scale"] + attrs["scale"] = tuple(resolution.scale * s for s in image_scale) + # Offset the translation due to a larger first pixel for lower resolutions. + # When visualized in napari, this ensures that the different multi-scale + # layers opened separately share the same visual extent in the canvas that + # starts at some scaled version of (-0.5, -0.5, -0.5). + image_translate = attrs.get("translate", (0,) * len(image_scale)) + attrs["translate"] = tuple( + (s * (resolution.scale - 1) / 2) + t + for s, t in zip(image_scale, image_translate) + ) return data, attrs, layer_type -def _handle_points_annotation(layer_data: FullLayerData, image_scale: Tuple[float, float, float]) -> FullLayerData: +def _handle_points_at_scale(layer_data: FullLayerData, image_scale: Tuple[float, float, float]) -> FullLayerData: data, attrs, layer_type = layer_data - # Inherit scale from full resolution image so that we can pick up - # that scale when it changes. + # Inherit scale from full resolution image, so that points are visually + # aligned with the image. attrs["scale"] = image_scale # Scaling points also changes the size, so adjust accordingly. attrs["size"] /= np.mean(image_scale) - return data, attrs, layer_type \ No newline at end of file + return data, attrs, layer_type \ No newline at end of file diff --git a/src/napari_cryoet_data_portal/_sample_data.py b/src/napari_cryoet_data_portal/_sample_data.py index 225396e..735f94d 100644 --- a/src/napari_cryoet_data_portal/_sample_data.py +++ b/src/napari_cryoet_data_portal/_sample_data.py @@ -36,12 +36,12 @@ def _read_tomogram_from_10000(name: str) -> List[FullLayerData]: ribosome_annotations = [ item for item in annotations - if item.object_name.lower() == "cytosolic ribosome" + if "cytosolic ribosome" in item.object_name.lower() ].pop() fas_annotations = [ item for item in annotations - if item.object_name.lower() == "fatty acid synthase" + if "fatty acid synthase" in item.object_name.lower() ].pop() ribosome_points = read_annotation(ribosome_annotations, tomogram=tomogram) fatty_acid_points = read_annotation(fas_annotations, tomogram=tomogram) diff --git a/src/napari_cryoet_data_portal/_tests/test_open_widget.py b/src/napari_cryoet_data_portal/_tests/test_open_widget.py index c33e782..70f1bbf 100644 --- a/src/napari_cryoet_data_portal/_tests/test_open_widget.py +++ b/src/napari_cryoet_data_portal/_tests/test_open_widget.py @@ -36,7 +36,7 @@ def test_set_tomogram_adds_layers_to_viewer(widget: OpenWidget, tomogram: Tomogr with qtbot.waitSignal(widget._progress.finished, timeout=30000): widget.setTomogram(tomogram) - assert len(widget._viewer.layers) == 9 + assert len(widget._viewer.layers) > 1 def test_set_tomogram_adds_layers_to_viewer_without_clearing_existing(widget: OpenWidget, tomogram: Tomogram, qtbot: QtBot): @@ -48,5 +48,5 @@ def test_set_tomogram_adds_layers_to_viewer_without_clearing_existing(widget: Op with qtbot.waitSignal(widget._progress.finished, timeout=30000): widget.setTomogram(tomogram) - assert len(widget._viewer.layers) == 10 + assert len(widget._viewer.layers) > 1 \ No newline at end of file diff --git a/src/napari_cryoet_data_portal/_tests/test_reader.py b/src/napari_cryoet_data_portal/_tests/test_reader.py index 88910af..b5a5309 100644 --- a/src/napari_cryoet_data_portal/_tests/test_reader.py +++ b/src/napari_cryoet_data_portal/_tests/test_reader.py @@ -1,6 +1,7 @@ import pytest from typing import Callable +import numpy as np from cryoet_data_portal import Annotation from napari import Viewer from napari.layers import Points @@ -26,7 +27,7 @@ def test_read_tomogram_ome_zarr(): assert data[0].shape == (1000, 928, 960) assert data[1].shape == (500, 464, 480) assert data[2].shape == (250, 232, 240) - assert attrs["scale"] == (1, 1, 1) + np.testing.assert_allclose(attrs["scale"], (13.48, 13.48, 13.48), atol=0.01) assert layer_type == "image"