Repository: napari/napari

Issue:
Removing and readding a 3D image layer is broken
## 🐛 Bug

Re-adding a previously removed 3D image layer results in the following error and a failure to add the layer:

```python
ValueError: interpolation must be one of bessel, bicubic, bilinear, blackman, catrom, gaussian, hamming, hanning, hermite, kaiser, lanczos, mitchell, nearest, quadric, sinc, spline16, spline36
```

This only happens with *3D images*. 2D images are fine.

As appropriate, `git bisect` tells me that it was a regression introduced by *me*, over at #3333 :P

## To Reproduce

```python
import napari
import numpy as np

v = napari.Viewer(ndisplay=3)
img = np.random.rand(100, 100, 100)
il = napari.layers.Image(img)
v.add_layer(il)
# everything is fine so far
```
```python
v.layers.remove(il)
v.add_layer(il)
# error!
```
Removing and readding a 3D image layer is broken
## 🐛 Bug

Re-adding a previously removed 3D image layer results in the following error and a failure to add the layer:

```python
ValueError: interpolation must be one of bessel, bicubic, bilinear, blackman, catrom, gaussian, hamming, hanning, hermite, kaiser, lanczos, mitchell, nearest, quadric, sinc, spline16, spline36
```

This only happens with *3D images*. 2D images are fine.

As appropriate, `git bisect` tells me that it was a regression introduced by *me*, over at #3333 :P

## To Reproduce

```python
import napari
import numpy as np

v = napari.Viewer(ndisplay=3)
img = np.random.rand(100, 100, 100)
il = napari.layers.Image(img)
v.add_layer(il)
# everything is fine so far
```
```python
v.layers.remove(il)
v.add_layer(il)
# error!
```


Discussion:

Resolving patch:
diff --git a/napari/_vispy/layers/image.py b/napari/_vispy/layers/image.py
--- a/napari/_vispy/layers/image.py
+++ b/napari/_vispy/layers/image.py
@@ -64,18 +64,21 @@ def __init__(self, layer, node=None):
             self._on_experimental_slicing_plane_normal_change
         )
 
+        # display_change is special (like data_change) because it requires a self.reset()
+        # this means that we have to call it manually. Also, it must be called before reset
+        # in order to set the appropriate node first
+        self._on_display_change()
         self.reset()
         self._on_data_change()
 
     def _on_display_change(self, data=None):
-
         parent = self.node.parent
         self.node.parent = None
 
         self.node = self._layer_node.get_node(self.layer._ndisplay)
 
         if data is None:
-            data = np.zeros((1,) * self.layer._ndisplay)
+            data = np.zeros((1,) * self.layer._ndisplay, dtype=np.float32)
 
         if self.layer._empty:
             self.node.visible = False


Test patch:
diff --git a/napari/_qt/_tests/test_qt_viewer.py b/napari/_qt/_tests/test_qt_viewer.py
--- a/napari/_qt/_tests/test_qt_viewer.py
+++ b/napari/_qt/_tests/test_qt_viewer.py
@@ -556,3 +556,16 @@ def test_mixed_2d_and_3d_layers(make_napari_viewer, multiscale):
     viewer.dims.order = (1, 2, 0)
     viewer.window.qt_viewer.on_draw(None)
     assert np.all(img_multi_layer.corner_pixels == expected_corner_pixels)
+
+
+def test_remove_add_image_3D(make_napari_viewer):
+    """
+    Test that adding, removing and readding an image layer in 3D does not cause issues
+    due to the vispy node change. See https://github.com/napari/napari/pull/3670
+    """
+    viewer = make_napari_viewer(ndisplay=3)
+    img = np.ones((10, 10, 10))
+
+    layer = viewer.add_image(img)
+    viewer.layers.remove(layer)
+    viewer.layers.append(layer)