Skip to content

Commit

Permalink
Distinguish between update_dims, extent changes, and refresh (#5363)
Browse files Browse the repository at this point in the history
* Replace some usage of _update_dims with refresh

* Use extent event instead of set_data
  • Loading branch information
andy-sweet committed Nov 30, 2022
1 parent 3105a06 commit 6cd7f78
Show file tree
Hide file tree
Showing 11 changed files with 39 additions and 32 deletions.
2 changes: 1 addition & 1 deletion examples/interaction_box_points.py
Expand Up @@ -36,7 +36,7 @@ def on_transform_changed_drag(event):

for i, index in enumerate(sel_i):
viewer.layers.selection.active._data[index] = viewer.layers.selection.active.world_to_data(event.value(points[i]))
viewer.layers.selection.active._update_dims()
viewer.layers.selection.active._clear_extent()
viewer.layers.selection.active.events.data(value=viewer.layers.selection.active.data)

X, Y = np.mgrid[-500:500:50, -500:500:50]
Expand Down
4 changes: 2 additions & 2 deletions napari/components/layerlist.py
Expand Up @@ -94,7 +94,7 @@ def _on_selection_changed(self, event):

def _process_delete_item(self, item: Layer):
super()._process_delete_item(item)
item.events.set_data.disconnect(self._clean_cache)
item.events.extent.disconnect(self._clean_cache)
self._clean_cache()

def _clean_cache(self):
Expand Down Expand Up @@ -163,7 +163,7 @@ def insert(self, index: int, value: Layer):
new_layer = self._type_check(value)
new_layer.name = self._coerce_name(new_layer.name)
self._clean_cache()
new_layer.events.set_data.connect(self._clean_cache)
new_layer.events.extent.connect(self._clean_cache)
super().insert(index, new_layer)

def toggle_selected_visibility(self):
Expand Down
40 changes: 23 additions & 17 deletions napari/layers/base/base.py
Expand Up @@ -343,6 +343,7 @@ def __init__(
cursor_size=Event,
editable=Event,
loaded=Event,
extent=Event,
_ndisplay=Event,
select=WarningEmitter(
trans._(
Expand Down Expand Up @@ -551,7 +552,7 @@ def scale(self, scale):
if scale is None:
scale = [1] * self.ndim
self._transforms['data2physical'].scale = np.array(scale)
self._update_dims()
self._clear_extent()
self.events.scale()

@property
Expand All @@ -562,7 +563,7 @@ def translate(self):
@translate.setter
def translate(self, translate):
self._transforms['data2physical'].translate = np.array(translate)
self._update_dims()
self._clear_extent()
self.events.translate()

@property
Expand All @@ -573,7 +574,7 @@ def rotate(self):
@rotate.setter
def rotate(self, rotate):
self._transforms['data2physical'].rotate = rotate
self._update_dims()
self._clear_extent()
self.events.rotate()

@property
Expand All @@ -584,7 +585,7 @@ def shear(self):
@shear.setter
def shear(self, shear):
self._transforms['data2physical'].shear = shear
self._update_dims()
self._clear_extent()
self.events.shear()

@property
Expand All @@ -600,7 +601,7 @@ def affine(self, affine):
self._transforms[2] = coerce_affine(
affine, ndim=self.ndim, name='physical2world'
)
self._update_dims()
self._clear_extent()
self.events.affine()

@property
Expand Down Expand Up @@ -648,12 +649,8 @@ def _is_moving(self, value):
assert self._moving_coordinates is not None
self._private_is_moving = value

def _update_dims(self, event=None):
"""Update the dims model and clear the extent cache.
This function needs to be called whenever data or transform information
changes, and should be called before events get emitted.
"""
def _update_dims(self):
"""Update the dimensionality of transforms and slices when data changes."""
ndim = self._get_ndim()

old_ndim = self._ndim
Expand All @@ -667,10 +664,8 @@ def _update_dims(self, event=None):
self._slice_input = self._slice_input.with_ndim(ndim)

self._ndim = ndim
if 'extent' in self.__dict__:
del self.extent

self.refresh() # This call is need for invalidate cache of extent in LayerList. If you remove it pleas ad another workaround.
self._clear_extent()

@property
@abstractmethod
Expand Down Expand Up @@ -721,6 +716,18 @@ def extent(self) -> Extent:
step=abs(data_to_world.scale),
)

def _clear_extent(self):
"""Clears the cached extent.
This should be called whenever this data or transform information
changes, and should be called before any related events get emitted
so that they use the updated extent values.
"""
if 'extent' in self.__dict__:
del self.extent
self.events.extent()
self.refresh()

@property
def _slice_indices(self):
"""(D, ) array: Slice indices in data coordinates."""
Expand Down Expand Up @@ -919,8 +926,7 @@ def _slice_dims(self, point=None, ndisplay=2, order=None):
if old_ndisplay != ndisplay:
self.events._ndisplay()

# Update the point values
self._update_dims()
self.refresh()
self._set_editable()

def _make_slice_input(
Expand Down Expand Up @@ -1136,7 +1142,7 @@ def refresh(self, event=None):
"""Refresh all layer data based on current view slice."""
if self.visible:
self.set_view_slice()
self.events.set_data() # refresh is called in _update_dims which means that extent cache is invalidated. Then, base on this event extent cache in layerlist is invalidated.
self.events.set_data()
self._update_thumbnail()
self._set_highlight(force=True)

Expand Down
4 changes: 2 additions & 2 deletions napari/layers/image/image.py
Expand Up @@ -372,7 +372,7 @@ def __init__(
# where the intention here is to use the base setter, so we use the
# _set_colormap method. This is important for Labels layers, because
# we don't want to use get_color before set_view_slice has been
# triggered (self._update_dims(), below).
# triggered (self.refresh(), below).
self._set_colormap(colormap)
self.contrast_limits = self._contrast_limits
self._interpolation2d = Interpolation.NEAREST
Expand All @@ -386,7 +386,7 @@ def __init__(
connect_no_arg(self.plane.events, self.events, 'plane')

# Trigger generation of view slice and thumbnail
self._update_dims()
self.refresh()

def _new_empty_slice(self):
"""Initialize the current slice to an empty image."""
Expand Down
2 changes: 1 addition & 1 deletion napari/layers/labels/labels.py
Expand Up @@ -307,7 +307,7 @@ def __init__(
self._reset_history()

# Trigger generation of view slice and thumbnail
self._update_dims()
self.refresh()
self._set_editable()

@property
Expand Down
2 changes: 1 addition & 1 deletion napari/layers/points/points.py
Expand Up @@ -467,7 +467,7 @@ def __init__(
self.antialiasing = antialiasing

# Trigger generation of view slice and thumbnail
self._update_dims()
self.refresh()

@property
def data(self) -> np.ndarray:
Expand Down
2 changes: 1 addition & 1 deletion napari/layers/shapes/shapes.py
Expand Up @@ -558,7 +558,7 @@ def __init__(
)

# Trigger generation of view slice and thumbnail
self._update_dims()
self.refresh()

def _initialize_current_color_for_empty_layer(
self, color: ColorType, attribute: str
Expand Down
9 changes: 5 additions & 4 deletions napari/layers/surface/surface.py
Expand Up @@ -203,7 +203,7 @@ def __init__(
if len(data) not in (2, 3):
raise ValueError(
trans._(
'Surface data tuple must be 2 or 3, specifying verictes, faces, and optionally vertex values, instead got length {length}.',
'Surface data tuple must be 2 or 3, specifying vertices, faces, and optionally vertex values, instead got length {length}.',
deferred=True,
length=len(data),
)
Expand All @@ -230,7 +230,9 @@ def __init__(
self._view_faces = np.zeros((0, 3))
self._view_vertex_values = []

# Trigger generation of view slice and thumbnail
# Trigger generation of view slice and thumbnail.
# Use _update_dims instead of refresh here because _get_ndim is
# dependent on vertex_values as well as vertices.
self._update_dims()

# Shading mode
Expand Down Expand Up @@ -283,7 +285,6 @@ def vertices(self, vertices):
self._vertices = vertices

self._update_dims()
self.refresh()
self.events.data(value=self.data)
self._set_editable()

Expand All @@ -297,7 +298,7 @@ def vertex_values(self, vertex_values: np.ndarray):

self._vertex_values = vertex_values

self.refresh()
self._update_dims()
self.events.data(value=self.data)
self._set_editable()

Expand Down
2 changes: 1 addition & 1 deletion napari/layers/tracks/tracks.py
Expand Up @@ -195,7 +195,7 @@ def __init__(
self.color_by = color_by
self.colormap = colormap

self._update_dims()
self.refresh()

# reset the display before returning
self._current_displayed_dims = None
Expand Down
2 changes: 1 addition & 1 deletion napari/layers/utils/_link_layers.py
Expand Up @@ -188,7 +188,7 @@ def layers_linked(layers: Iterable[Layer], attributes: Iterable[str] = ()):

def _get_common_evented_attributes(
layers: Iterable[Layer],
exclude: set[str] = {'thumbnail', 'status', 'name', 'data'},
exclude: set[str] = {'thumbnail', 'status', 'name', 'data', 'extent'},
with_private=False,
) -> set[str]:
"""Get the set of common, non-private evented attributes in ``layers``.
Expand Down
2 changes: 1 addition & 1 deletion napari/layers/vectors/vectors.py
Expand Up @@ -245,7 +245,7 @@ def __init__(
self._view_alphas = []

# now that everything is set up, make the layer visible (if set to visible)
self._update_dims()
self.refresh()
self.visible = visible

@property
Expand Down

0 comments on commit 6cd7f78

Please sign in to comment.