From e3973201f90e4a9cd6fcd1376efa75ab66a837aa Mon Sep 17 00:00:00 2001 From: Andy Sweet Date: Wed, 4 Sep 2024 13:48:17 -0700 Subject: [PATCH] Only rescale points for older napari versions (#33) napari v0.5 includes a fix to handle expected combinations of point size and layer scale. Previously, we worked around that issue by rescaling the point sizes ourselves. After this PR, we only do that for older versions of napari. The check is cached to avoid spamming the logs. Alternatively, we could require `napari>=0.5` in `setup.cfg`. I decided to support both versions for now, since v0.5 is quite new and comes with a few of its own new bugs. This was tested manually by installing v0.4.19 and v0.5.2 of napari and visually inspecting the resulting point sizes. --- src/napari_cryoet_data_portal/_open_widget.py | 53 ++++++++++++++++--- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/src/napari_cryoet_data_portal/_open_widget.py b/src/napari_cryoet_data_portal/_open_widget.py index 3b15f78..dbd09e6 100644 --- a/src/napari_cryoet_data_portal/_open_widget.py +++ b/src/napari_cryoet_data_portal/_open_widget.py @@ -1,7 +1,9 @@ from dataclasses import dataclass +from functools import lru_cache from typing import TYPE_CHECKING, Generator, Optional, Tuple import numpy as np +from cryoet_data_portal import Annotation, Client, Tomogram from npe2.types import FullLayerData from qtpy.QtCore import Qt from qtpy.QtWidgets import ( @@ -14,7 +16,6 @@ QVBoxLayout, QWidget, ) -from cryoet_data_portal import Annotation, Client, Tomogram from napari_cryoet_data_portal._logging import logger from napari_cryoet_data_portal._progress_widget import ProgressWidget @@ -139,8 +140,11 @@ def _loadTomogram( # A single client is not thread safe, so we need a new instance for each query. client = Client(self._uri) annotations = Annotation.find( - client, - [Annotation.tomogram_voxel_spacing_id == tomogram.tomogram_voxel_spacing_id], + client, + [ + Annotation.tomogram_voxel_spacing_id + == tomogram.tomogram_voxel_spacing_id + ], ) for annotation in annotations: @@ -164,7 +168,9 @@ def _onLayerLoaded(self, layer_data: FullLayerData) -> None: raise AssertionError(f"Unexpected {layer_type=}") -def _handle_image_at_resolution(layer_data: FullLayerData, resolution: Resolution) -> FullLayerData: +def _handle_image_at_resolution( + layer_data: FullLayerData, resolution: Resolution +) -> FullLayerData: data, attrs, layer_type = layer_data # Skip indexing for multi-resolution to avoid adding any # unnecessary nodes to the dask compute graph. @@ -191,11 +197,42 @@ def _handle_image_at_resolution(layer_data: FullLayerData, resolution: Resolutio return data, attrs, layer_type -def _handle_points_at_scale(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 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 + # Scaling points also changes the size in some version of napari, so adjust accordingly. + if _is_napari_version_less_than("0.5"): + attrs["size"] /= np.mean(image_scale) + return data, attrs, layer_type + + +@lru_cache(maxsize=None) +def _is_napari_version_less_than(version: str) -> bool: + try: + import napari + except ImportError: + logger.warn("Failed to import napari") + return False + try: + from packaging.version import InvalidVersion, Version + except ImportError: + logger.warn("Failed to import packaging") + return False + try: + actual_version = Version(napari.__version__) + except InvalidVersion: + logger.warn( + "Failed to parse actual napari version from %s ", + napari.__version__, + ) + return False + try: + target_version = Version(version) + except InvalidVersion: + logger.warn("Failed to parse target napari version from %s", version) + return False + return actual_version < target_version