From 606530943cbfcc3105df08d4b4eb987643263d21 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Thu, 29 Feb 2024 08:57:06 +0100 Subject: [PATCH] Remove deprecated code from Labels layer (#6641) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # References and relevant issues This completes the deprecations started in #6542. All it does is remove the things we warned we would remove. 😂 --------- Co-authored-by: Grzegorz Bokota Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- napari/benchmarks/benchmark_labels_layer.py | 13 +- .../benchmarks/benchmark_qt_viewer_labels.py | 3 +- napari/components/_tests/test_viewer_model.py | 10 -- napari/layers/labels/_tests/test_labels.py | 80 ++------- napari/layers/labels/labels.py | 153 ------------------ 5 files changed, 23 insertions(+), 236 deletions(-) diff --git a/napari/benchmarks/benchmark_labels_layer.py b/napari/benchmarks/benchmark_labels_layer.py index 4814739d480..99e271aeec9 100644 --- a/napari/benchmarks/benchmark_labels_layer.py +++ b/napari/benchmarks/benchmark_labels_layer.py @@ -10,6 +10,7 @@ import napari from napari.components.dims import Dims from napari.layers import Labels +from napari.utils.colormaps import DirectLabelColormap from .utils import Skip, labeled_particles @@ -95,12 +96,13 @@ def setup(self, n, brush_size, color_mode, contour): (n, n), dtype=np.int32, n=int(np.log2(n) ** 2), seed=1 ) - colors = None + self.layer = Labels(self.data) + if color_mode == 'direct': random_label_ids = np.random.randint(64, size=50) colors = {i + 1: np.random.random(4) for i in random_label_ids} - - self.layer = Labels(self.data, color=colors) + colors[None] = np.array([0, 0, 0, 0.3]) + self.layer.colormap = DirectLabelColormap(color_dict=colors) self.layer.brush_size = brush_size self.layer.contour = contour @@ -132,9 +134,10 @@ def setup(self, n, dtype): random_label_ids = np.random.randint( low=max(-10000, info.min), high=min(10000, info.max), size=20 ) + colors = {i + 1: np.random.random(4) for i in random_label_ids} + colors[None] = np.array([0, 0, 0, 0.3]) self.layer = Labels( - self.data, - color={i + 1: np.random.random(4) for i in random_label_ids}, + self.data, colormap=DirectLabelColormap(color_dict=colors) ) self.layer._raw_to_displayed( self.layer._slice.image.raw, (slice(0, n), slice(0, n)) diff --git a/napari/benchmarks/benchmark_qt_viewer_labels.py b/napari/benchmarks/benchmark_qt_viewer_labels.py index 2ead2912cd6..dae103d0fc1 100644 --- a/napari/benchmarks/benchmark_qt_viewer_labels.py +++ b/napari/benchmarks/benchmark_qt_viewer_labels.py @@ -16,6 +16,7 @@ import napari from napari.components.viewer_model import ViewerModel from napari.qt import QtViewer +from napari.utils.colormaps import DirectLabelColormap from .utils import Skip @@ -150,7 +151,7 @@ def setup(self, radius, dtype, label_mode): ) colors[None] = 'yellow' colors[0] = 'transparent' - self.layer.color = colors + self.layer.colormap = DirectLabelColormap(color_dict=colors) self.qt_viewr.show() @staticmethod diff --git a/napari/components/_tests/test_viewer_model.py b/napari/components/_tests/test_viewer_model.py index abc5f985e3a..75c7790adfe 100644 --- a/napari/components/_tests/test_viewer_model.py +++ b/napari/components/_tests/test_viewer_model.py @@ -138,16 +138,6 @@ def test_add_labels(): assert viewer.dims.ndim == 2 -def test_add_labels_warnings(): - """Test adding labels image.""" - viewer = ViewerModel() - np.random.seed(0) - with pytest.warns( - FutureWarning, match='Setting Labels.num_colors is deprecated since' - ): - viewer.add_labels(np.zeros((10, 15), dtype=np.uint8), num_colors=20) - - def test_add_points(): """Test adding points.""" viewer = ViewerModel() diff --git a/napari/layers/labels/_tests/test_labels.py b/napari/layers/labels/_tests/test_labels.py index b1fb8839d58..845b7a62ca7 100644 --- a/napari/layers/labels/_tests/test_labels.py +++ b/napari/layers/labels/_tests/test_labels.py @@ -1,6 +1,7 @@ import copy import itertools import time +from collections import defaultdict from dataclasses import dataclass from tempfile import TemporaryDirectory from typing import List @@ -12,7 +13,6 @@ import xarray as xr import zarr from numpy.core.numerictypes import issubdtype -from numpy.testing import assert_array_almost_equal, assert_raises from skimage import data as sk_data from napari._tests.utils import check_layer_world_data_extent @@ -261,56 +261,6 @@ def test_blending(): @pytest.mark.filterwarnings('ignore:.*seed is deprecated.*') -def test_seed(): - """Test setting seed.""" - np.random.seed(0) - data = np.random.randint(20, size=(10, 15)) - layer = Labels(data) - assert layer.seed == 0.5 - - layer.seed = 0.9 - assert layer.seed == 0.9 - - layer = Labels(data, seed=0.7) - assert layer.seed == 0.7 - - # ensure setting seed updates the random colormap - mapped_07 = layer.colormap.map(layer.data) - layer.seed = 0.4 - mapped_04 = layer.colormap.map(layer.data) - assert_raises( - AssertionError, assert_array_almost_equal, mapped_07, mapped_04 - ) - - -def test_num_colors(): - """Test setting number of colors in colormap with deprecated API.""" - np.random.seed(0) - data = np.random.randint(20, size=(10, 15)) - layer = Labels(data) - - with pytest.warns(FutureWarning, match='num_colors is deprecated'): - assert layer.num_colors == 50 - - with pytest.warns(FutureWarning, match='num_colors is deprecated'): - layer.num_colors = 80 - - assert len(layer.colormap) == 80 - - with pytest.warns(FutureWarning, match='num_colors is deprecated'): - layer = Labels(data, num_colors=60) - - assert len(layer.colormap) == 60 - - with pytest.raises(ValueError, match=r'.*Only up to 2\*\*16=65535 colors'): - with pytest.warns(FutureWarning, match='num_colors is deprecated'): - layer.num_colors = 2**17 - - with pytest.raises(ValueError, match=r'.*Only up to 2\*\*16=65535 colors'): - with pytest.warns(FutureWarning, match='num_colors is deprecated'): - Labels(data, num_colors=2**17) - - def test_properties(): """Test adding labels with properties.""" np.random.seed(0) @@ -447,11 +397,13 @@ def test_custom_color_dict(): """Test custom color dict.""" np.random.seed(0) data = np.random.randint(20, size=(10, 15)) - with pytest.warns(FutureWarning, match='Labels.color is deprecated'): - layer = Labels( - data, - color={2: 'white', 4: 'red', 8: 'blue', 16: 'red', 32: 'blue'}, + cmap = DirectLabelColormap( + color_dict=defaultdict( + lambda: 'black', + {2: 'white', 4: 'red', 8: 'blue', 16: 'red', 32: 'blue'}, ) + ) + layer = Labels(data, colormap=cmap) # test with custom color dict assert isinstance(layer.get_color(2), np.ndarray) @@ -462,8 +414,6 @@ def test_custom_color_dict(): # test disable custom color dict # should not initialize as white since we are using random.seed - with pytest.warns(FutureWarning, match='Labels.color_mode is deprecated'): - layer.color_mode = 'auto' assert not (layer.get_color(1) == np.array([1.0, 1.0, 1.0, 1.0])).all() @@ -1511,8 +1461,6 @@ def test_is_default_color(): # setting color to default colors doesn't update color mode layer.colormap = DirectLabelColormap(color_dict=current_color) assert isinstance(layer.colormap, CyclicLabelColormap) - with pytest.warns(FutureWarning, match='Labels.color_mode is deprecated'): - assert layer.color_mode == 'auto' # new colors are not default new_color = {0: 'white', 1: 'red', 3: 'green', None: 'blue'} @@ -1520,8 +1468,6 @@ def test_is_default_color(): # setting the color with non-default colors updates color mode layer.colormap = DirectLabelColormap(color_dict=new_color) assert isinstance(layer.colormap, DirectLabelColormap) - with pytest.warns(FutureWarning, match='Labels.color_mode is deprecated'): - assert layer.color_mode == 'direct' def test_large_labels_direct_color(): @@ -1529,12 +1475,12 @@ def test_large_labels_direct_color(): pytest.importorskip('numba') data = np.array([[0, 1], [2**16, 2**20]], dtype=np.uint32) colors = {1: 'white', 2**16: 'green', 2**20: 'magenta'} - layer = Labels(data) - with pytest.warns(FutureWarning, match='Labels.color is deprecated'): - layer.color = colors - - with pytest.warns(FutureWarning, match='Labels.color_mode is deprecated'): - assert layer.color_mode == 'direct' + layer = Labels( + data, + colormap=DirectLabelColormap( + color_dict=defaultdict(lambda: 'black', colors) + ), + ) np.testing.assert_allclose(layer.get_color(2**20), [1.0, 0.0, 1.0, 1.0]) diff --git a/napari/layers/labels/labels.py b/napari/layers/labels/labels.py index 12f07eec248..fdc97b1f85c 100644 --- a/napari/layers/labels/labels.py +++ b/napari/layers/labels/labels.py @@ -55,15 +55,12 @@ ) from napari.utils.colormaps.colormap import ( CyclicLabelColormap, - DirectLabelColormap, LabelColormapBase, ) from napari.utils.colormaps.colormap_utils import shuffle_and_extend_colormap from napari.utils.events import EmitterGroup, Event from napari.utils.events.custom_types import Array -from napari.utils.events.event import WarningEmitter from napari.utils.geometry import clamp_point_to_bounding_box -from napari.utils.migrations import deprecated_constructor_arg_by_attr from napari.utils.misc import StringEnum, _is_array_type from napari.utils.naming import magic_name from napari.utils.status_messages import generate_layer_coords_status @@ -276,9 +273,6 @@ class Labels(_ImageBase): _history_limit = 100 - @deprecated_constructor_arg_by_attr('color') - @deprecated_constructor_arg_by_attr('num_colors') - @deprecated_constructor_arg_by_attr('seed') def __init__( self, data, @@ -348,15 +342,6 @@ def __init__( self.events.add( brush_shape=Event, brush_size=Event, - color_mode=WarningEmitter( - trans._( - 'Labels.events.color_mode is deprecated since 0.4.19 and ' - 'will be removed in 0.5.0, please use ' - 'Labels.events.colormap.', - deferred=True, - ), - type_name='color_mode', - ), colormap=Event, contiguous=Event, contour=Event, @@ -481,33 +466,6 @@ def _calculate_cursor_size(self): ) return abs(self.brush_size * min_scale) - @property - def seed(self): - """float: Seed for colormap random generator.""" - warnings.warn( - 'seed is deprecated since 0.4.19 and will be removed in 0.5.0, ' - 'please check Labels.colormap directly.', - FutureWarning, - stacklevel=2, - ) - return self._random_colormap.seed - - @seed.setter - def seed(self, seed): - warnings.warn( - 'seed is deprecated since 0.4.19 and will be removed in 0.5.0, ' - 'please use the new_colormap method instead, or set the colormap ' - 'directly.', - FutureWarning, - stacklevel=2, - ) - - self.colormap = label_colormap( - len(self.colormap) - 1, - seed=seed, - background_value=self.colormap.background_value, - ) - def new_colormap(self, seed: Optional[int] = None): if seed is None: seed = np.random.default_rng().integers(2**32 - 1) @@ -555,39 +513,6 @@ def _set_colormap(self, colormap): self.events.selected_label() self.refresh() - @property - def num_colors(self): - """int: Number of unique colors to use in colormap.""" - warnings.warn( - trans._( - 'Labels.num_colors is deprecated since 0.4.19 and will be ' - 'removed in 0.5.0, please use len(Labels.colormap) ' - 'instead.', - deferred=True, - ), - FutureWarning, - stacklevel=2, - ) - return len(self.colormap) - - @num_colors.setter - def num_colors(self, num_colors): - warnings.warn( - trans._( - 'Setting Labels.num_colors is deprecated since 0.4.19 and ' - 'will be removed in 0.5.0, please set Labels.colormap ' - 'instead.', - deferred=True, - ), - FutureWarning, - stacklevel=2, - ) - self.colormap = label_colormap( - num_colors - 1, - seed=self._random_colormap.seed, - background_value=self.colormap.background_value, - ) - @property def data(self) -> LayerDataProtocol: """array: Image data.""" @@ -648,35 +573,6 @@ def _make_label_index(self) -> Dict[int, int]: label_index = {i: i for i in range(features.shape[0])} return label_index - @property - def color(self) -> dict: - """dict: custom color dict for label coloring""" - warnings.warn( - 'Labels.color is deprecated since 0.4.19 and will be removed in ' - '0.5.0, please use Labels.colormap.color_dict instead. Note: this' - 'will only work when the colormap is a DirectLabelsColormap.', - FutureWarning, - stacklevel=2, - ) - return {**self._direct_colormap.color_dict} - - @color.setter - def color(self, color: Dict[Optional[int], Union[str, np.ndarray]]): - warnings.warn( - 'Labels.color is deprecated since 0.4.19 and will be removed in ' - '0.5.0, please set Labels.colormap directly with an instance ' - 'of napari.utils.colormaps.DirectLabelColormap instead.', - FutureWarning, - stacklevel=2, - ) - color = dict(color) if color else {} - - color[self.colormap.background_value] = color.get( - self.colormap.background_value, 'transparent' - ) - color[None] = color.get(None, 'black') - self.colormap = DirectLabelColormap(color_dict=color) - def _is_default_colors(self, color): """Returns True if color contains only default colors, otherwise False. @@ -783,55 +679,6 @@ def swap_selected_and_background_labels(self): else: self.selected_label = self._prev_selected_label - @property - def color_mode(self): - """Color mode to change how color is represented. - - AUTO (default) allows color to be set via a hash function with a seed. - - DIRECT allows color of each label to be set directly by a color dict. - """ - warnings.warn( - trans._( - 'Labels.color_mode is deprecated since 0.4.19 and will be ' - 'removed in 0.5.0. Please check type(Labels.colormap) ' - 'instead. napari.utils.colormaps.CyclicLabelColormap ' - 'corresponds to AUTO color mode, and ' - 'napari.utils.colormaps.DirectLabelColormap' - ' corresponds to DIRECT color mode.', - deferred=True, - ), - FutureWarning, - stacklevel=2, - ) - return str(self._color_mode) - - @color_mode.setter - def color_mode(self, color_mode: Union[str, LabelColorMode]): - warnings.warn( - trans._( - 'Labels.color_mode is deprecated since 0.4.19 and will be ' - 'removed in 0.5.0. Please set Labels.colormap instead, to an' - 'instance of napari.utils.colormaps.CyclicLabelColormap for ' - '"auto" mode, or napari.utils.colormaps.DirectLabelColormap ' - 'for "direct" mode.', - deferred=True, - ), - FutureWarning, - stacklevel=2, - ) - color_mode = LabelColorMode(color_mode) - self._color_mode = color_mode - if color_mode == LabelColorMode.AUTO: - self._colormap = self._random_colormap - else: - self._colormap = self._direct_colormap - self._selected_color = self.get_color(self.selected_label) - self.events.color_mode() - self.events.colormap() # If remove this emitting, connect shader update to color_mode - self.events.selected_label() - self.refresh() - @property def show_selected_label(self): """Whether to filter displayed labels to only the selected label or not"""