Repository: napari/napari

Issue:
surface timeseries example regression
## 🐛 Bug
When I run the following `python examples/surface_timeseries.py` on main I get an error. Looks like some assumptions were made when we passed `view_direction` to `get_value`. We should fix this before next release

```python-traceback
(base) czirwc1macos2701:napari nsofroniew$ python examples/surface_timeseries.py
/Users/nsofroniew/opt/anaconda3/lib/python3.7/site-packages/nilearn/surface/surface.py:555: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
  return np.asarray([arr.data for arr in gifti_img.darrays]).T.squeeze()
Traceback (most recent call last):
  File "examples/surface_timeseries.py", line 36, in <module>
    contrast_limits=[-1.5, 3.5], name='timeseries')
  File "/Users/nsofroniew/GitHub/napari/napari/components/viewer_model.py", line 5, in add_surface
    import os
  File "/Users/nsofroniew/opt/anaconda3/lib/python3.7/_collections_abc.py", line 971, in append
    self.insert(len(self), value)
  File "/Users/nsofroniew/GitHub/napari/napari/components/layerlist.py", line 90, in insert
    super().insert(index, new_layer)
  File "/Users/nsofroniew/GitHub/napari/napari/utils/events/containers/_selectable_list.py", line 65, in insert
    super().insert(index, value)
  File "/Users/nsofroniew/GitHub/napari/napari/utils/events/containers/_evented_list.py", line 179, in insert
    self.events.inserted(index=index, value=value)
  File "/Users/nsofroniew/GitHub/napari/napari/utils/events/event.py", line 715, in __call__
    self._invoke_callback(cb, event if pass_event else None)
  File "/Users/nsofroniew/GitHub/napari/napari/utils/events/event.py", line 756, in _invoke_callback
    cb_event=(cb, event),
  File "/Users/nsofroniew/GitHub/napari/napari/utils/events/event.py", line 739, in _invoke_callback
    cb(event)
  File "/Users/nsofroniew/GitHub/napari/napari/components/viewer_model.py", line 462, in _on_add_layer
    self._on_layers_change()
  File "/Users/nsofroniew/GitHub/napari/napari/components/viewer_model.py", line 354, in _on_layers_change
    list(self.cursor.position) + [0] * dim_diff
  File "/Users/nsofroniew/GitHub/napari/napari/utils/events/evented_model.py", line 228, in __setattr__
    getattr(self.events, name)(value=after)  # emit event
  File "/Users/nsofroniew/GitHub/napari/napari/utils/events/event.py", line 715, in __call__
    self._invoke_callback(cb, event if pass_event else None)
  File "/Users/nsofroniew/GitHub/napari/napari/utils/events/event.py", line 756, in _invoke_callback
    cb_event=(cb, event),
  File "/Users/nsofroniew/GitHub/napari/napari/utils/events/event.py", line 741, in _invoke_callback
    cb()
  File "/Users/nsofroniew/GitHub/napari/napari/components/viewer_model.py", line 390, in _on_cursor_position_change
    world=True,
  File "/Users/nsofroniew/GitHub/napari/napari/layers/base/base.py", line 1586, in get_status
    world=world,
  File "/Users/nsofroniew/GitHub/napari/napari/layers/base/base.py", line 1062, in get_value
    list(view_direction)
TypeError: 'NoneType' object is not iterable
```


Discussion:

Resolving patch:
diff --git a/napari/layers/base/base.py b/napari/layers/base/base.py
--- a/napari/layers/base/base.py
+++ b/napari/layers/base/base.py
@@ -1049,7 +1049,7 @@ def get_value(
                     )
                 position = self.world_to_data(position)
 
-            if dims_displayed is not None:
+            if (dims_displayed is not None) and (view_direction is not None):
                 if len(dims_displayed) == 2 or self.ndim == 2:
                     value = self._get_value(position=tuple(position))
 


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
@@ -618,3 +618,23 @@ def test_qt_viewer_multscale_image_out_of_view(make_napari_viewer):
         shape_type=['polygon'],
     )
     viewer.add_image([np.eye(1024), np.eye(512), np.eye(256)])
+
+
+def test_surface_mixed_dim(make_napari_viewer):
+    """Test that adding a layer that changes the world ndim
+    when ndisplay=3 before the mouse cursor has been updated
+    doesn't raise an error.
+
+    See PR: https://github.com/napari/napari/pull/3881
+    """
+    viewer = make_napari_viewer(ndisplay=3)
+
+    verts = np.array([[0, 0, 0], [0, 20, 10], [10, 0, -10], [10, 10, -10]])
+    faces = np.array([[0, 1, 2], [1, 2, 3]])
+    values = np.linspace(0, 1, len(verts))
+    data = (verts, faces, values)
+    viewer.add_surface(data)
+
+    timeseries_values = np.vstack([values, values])
+    timeseries_data = (verts, faces, timeseries_values)
+    viewer.add_surface(timeseries_data)