napari / napari-animation

A napari plugin for making animations
https://napari.github.io/napari-animation/
Other
74 stars 27 forks source link

Animation crashes if hidden `Labels` layer present in viewer #184

Closed bentaculum closed 7 months ago

bentaculum commented 8 months ago

Thanks a lot for developing this nice plugin :)

I just noticed the following: If there is a hidden Labels layer present in the viewer, Animation.animate crashes while trying to update some layer thumbnail. This looks like a bug to me, it didn't occur to me that I'm not allowed to have some hidden layers floating around when creating an animation.

Here is a minimal example. The first animation is written fine, after adding the Labels layer with visible=False I get the error below.

import numpy as np
import napari
from napari_animation import Animation

size = (10, 20, 20, 20)
x = np.random.randint(0, 2, size=size)

viewer = napari.Viewer()
viewer.dims.ndisplay = 3

def animate(v, name):
    v.dims.set_current_step(0, 0)
    a = Animation(v)
    a.capture_keyframe()
    v.dims.set_current_step(0, v.layers[0].data.shape[0] - 1)
    a.capture_keyframe()
    a.animate(f"{name}.mp4", canvas_only=True)

viewer.add_labels(x)
animate(viewer, "only_visible_labels")

viewer.add_labels(x, visible=False)
animate(viewer, "hidden_labels")

Error message:

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
File ~/code/track_transformer/scripts/animation_bug.py:25
     22 animate(viewer, "only_visible_labels")
     24 viewer.add_labels(x, visible=False)
---> 25 animate(viewer, "hidden_labels")

File ~/code/track_transformer/scripts/animation_bug.py:19, in animate(v, name)
     17 v.dims.set_current_step(0, v.layers[0].data.shape[0] - 1)
     18 a.capture_keyframe()
---> 19 a.animate(f"{name}.mp4", canvas_only=True)

File ~/micromamba/envs/trackastra/lib/python3.10/site-packages/napari_animation/animation.py:225, in Animation.animate(self, filename, fps, quality, format, canvas_only, scale_factor)
    223 sleep(0.05)
    224 with tqdm(total=n_frames) as pbar:
--> 225     for frame_index, image in enumerate(frame_generator):
    226         if save_as_folder is True:
    227             frame_filename = (
    228                 folder_path / f"{file_path.stem}_{frame_index:06d}.png"
    229             )

File ~/micromamba/envs/trackastra/lib/python3.10/site-packages/napari_animation/frame_sequence.py:152, in FrameSequence.iter_frames(self, viewer, canvas_only, scale_factor)
    150 """Iterate over interpolated viewer states, and yield rendered frames."""
    151 for i, state in enumerate(self):
--> 152     frame = state.render(viewer, canvas_only=canvas_only)
    153     if scale_factor not in (None, 1):
    154         from scipy import ndimage as ndi

File ~/micromamba/envs/trackastra/lib/python3.10/site-packages/napari_animation/viewer_state.py:79, in ViewerState.render(self, viewer, canvas_only)
     61 def render(
     62     self, viewer: napari.viewer.Viewer, canvas_only: bool = True
     63 ) -> np.ndarray:
     64     """Render this ViewerState to an image.
     65 
     66     Parameters
   (...)
     77         An RGBA image of shape (h, w, 4).
     78     """
---> 79     self.apply(viewer)
     80     return viewer.screenshot(canvas_only=canvas_only, flash=False)

File ~/micromamba/envs/trackastra/lib/python3.10/site-packages/napari_animation/viewer_state.py:59, in ViewerState.apply(self, viewer)
     57 # Only set if value differs to avoid expensive redraws
     58 if not np.array_equal(original_value, value):
---> 59     setattr(layer, attribute_name, value)

File ~/micromamba/envs/trackastra/lib/python3.10/site-packages/napari/layers/labels/labels.py:556, in Labels.color(self, color)
    553 else:
    554     color_mode = LabelColorMode.DIRECT
--> 556 self.color_mode = color_mode

File ~/micromamba/envs/trackastra/lib/python3.10/site-packages/napari/layers/labels/labels.py:685, in Labels.color_mode(self, color_mode)
    683 elif color_mode == LabelColorMode.AUTO:
    684     self._label_color_index = {}
--> 685     super()._set_colormap(self._random_colormap)
    687 else:
    688     raise ValueError(trans._("Unsupported Color Mode"))

File ~/micromamba/envs/trackastra/lib/python3.10/site-packages/napari/layers/intensity_mixin.py:71, in IntensityVisualizationMixin._set_colormap(self, colormap)
     69 def _set_colormap(self, colormap):
     70     self._colormap = ensure_colormap(colormap)
---> 71     self._update_thumbnail()
     72     self.events.colormap()

File ~/micromamba/envs/trackastra/lib/python3.10/site-packages/napari/layers/image/image.py:953, in _ImageBase._update_thumbnail(self)
    951         colormapped = np.concatenate([downsampled, alpha], axis=2)
    952 else:
--> 953     downsampled = ndi.zoom(
    954         image, zoom_factor, prefilter=False, order=0
    955     )
    956     low, high = self.contrast_limits
    957     downsampled = np.clip(downsampled, low, high)

File ~/micromamba/envs/trackastra/lib/python3.10/site-packages/scipy/ndimage/_interpolation.py:770, in zoom(input, zoom, output, order, mode, cval, prefilter, grid_mode)
    768 if input.ndim < 1:
    769     raise RuntimeError('input and output rank must be > 0')
--> 770 zoom = _ni_support._normalize_sequence(zoom, input.ndim)
    771 output_shape = tuple(
    772         [int(round(ii * jj)) for ii, jj in zip(input.shape, zoom)])
    773 complex_output = numpy.iscomplexobj(input)

File ~/micromamba/envs/trackastra/lib/python3.10/site-packages/scipy/ndimage/_ni_support.py:68, in _normalize_sequence(input, rank)
     66     if len(normalized) != rank:
     67         err = "sequence argument must have length equal to input rank"
---> 68         raise RuntimeError(err)
     69 else:
     70     normalized = [input] * rank

RuntimeError: sequence argument must have length equal to input rank

python: 3.10.12 napari: 0.4.18 napari-animation: 0.0.7

alisterburt commented 8 months ago

Hey @bentaculum

Thanks for the nice bug report! I haven't had a chance to take a look yet, I want to help but to set expectations I just moved to a new continent and started a new job so am pretty low bandwidth right now. If you're capable of finding the bug/submitting a pull request I'm very happy to get a fix merged but not sure when I can take a look myself right now.

Many thanks!

Alister

psobolewskiPhD commented 7 months ago

Could you post full output of napari --info? I have a different issue with Labels animations, see: https://github.com/napari/napari-animation/issues/180 so it's interesting that you say the visible Labels works for you.

Anyhow I have a fix PR (https://github.com/napari/napari-animation/pull/181) for labels (and other layer types) and with that branch I can replicate the issue. I'll try and take a look at the root cause of this issue too, because it involves the same lines of code (the storing of the viewer state)

psobolewskiPhD commented 7 months ago

There was an issue with https://github.com/napari/napari-animation/pull/181 that was spotted by a user on image.sc (https://forum.image.sc/t/issue-saving-animations-in-napari-animation/88868/8?u=psobolewskiphd). After fixing, I can no longer reproduce this issue, so I think #181 solves this! 🎉

bentaculum commented 7 months ago

Hi @psobolewskiPhD, thanks for looking into this. Here's my napari --info in case still needed:

napari --info
napari: 0.4.18
Platform: macOS-12.7-arm64-arm-64bit
System: MacOS 12.7
Python: 3.10.12 | packaged by conda-forge | (main, Jun 23 2023, 22:41:52) [Clang 15.0.7 ]
Qt: 5.15.8
PyQt5: 5.15.9
NumPy: 1.23.5
SciPy: 1.11.2
Dask: 2023.9.2
VisPy: 0.12.2
magicgui: 0.7.3
superqt: 0.5.4
in-n-out: 0.1.8
app-model: 0.2.1
npe2: 0.7.2

OpenGL:
  - GL version:  2.1 Metal - 76.3
  - MAX_TEXTURE_SIZE: 16384

Screens:
  - screen 1: resolution 1728x1117, scale 2.0

Settings path:
  - /Users/gallusse/Library/Application Support/napari/trackastra_0d3c3869e2a7fdacd6ade9a31c9f813beb43b53b/settings.yaml
Plugins:
  - napari: 0.4.18 (77 contributions)
  - napari-animation: 0.0.7 (2 contributions)
  - napari-console: 0.0.8 (0 contributions)
  - napari-manual-transforms: 0.0.3 (2 contributions)
  - napari-open-ctc: 0.1.dev2+geee37b4.d20231030 (2 contributions)
  - napari-svg: 0.1.10 (2 contributions)
  - trackastra: 0.1.0 (2 contributions)