napari icon indicating copy to clipboard operation
napari copied to clipboard

Auto-contrast continuous gives error toggling to 3D (and vice versa)

Open psobolewskiPhD opened this issue 1 year ago • 4 comments
trafficstars

🐛 Bug Report

If you open a stack, e.g. Brain and set auto contrast to continuous, then when you toggle to 3D you will get a traceback:

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
File ~/Dev/napari/napari/utils/action_manager.py:229, in ActionManager.bind_button.<locals>._trigger()
    228 def _trigger():
--> 229     self.trigger(name)
        name = 'napari:toggle_ndisplay'
        self = <napari.utils.action_manager.ActionManager object at 0x13103ebd0>

File ~/Dev/napari/napari/utils/action_manager.py:431, in ActionManager.trigger(self=<napari.utils.action_manager.ActionManager object>, name='napari:toggle_ndisplay')
    429 def trigger(self, name: str) -> Any:
    430     """Trigger the action `name`."""
--> 431     return self._actions[name].injected()
        self._actions[name].injected = <function toggle_ndisplay at 0x151509da0>
        self._actions[name] = Action(command=<function toggle_ndisplay at 0x134a48720>, description='Toggle 2D/3D view.', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False)
        self._actions = {'napari:orient_plane_normal_along_z': Action(command=<function orient_plane_normal_along_z at 0x131b2ede0>, description='Orient plane normal along z-axis', keymapprovider=<class 'napari.layers.image.image.Image'>, repeatable=False), 'napari:orient_plane_normal_along_y': Action(command=<function orient_plane_normal_along_y at 0x131b2ed40>, description='Orient plane normal along y-axis', keymapprovider=<class 'napari.layers.image.image.Image'>, repeatable=False), 'napari:orient_plane_normal_along_x': Action(command=<function orient_plane_normal_along_x at 0x131b2ee80>, description='Orient plane normal along x-axis', keymapprovider=<class 'napari.layers.image.image.Image'>, repeatable=False), 'napari:orient_plane_normal_along_view_direction': Action(command=<function orient_plane_normal_along_view_direction at 0x131b2ef20>, description='Orient plane normal along view direction\nHold down to have plane follow camera', keymapprovider=<class 'napari.layers.image.image.Image'>, repeatable=False), 'napari:orient_plane_normal_along_view_direction_no_gen': Action(command=<function orient_plane_normal_along_view_direction_no_gen at 0x131ac6700>, description='Orient plane normal along view direction button', keymapprovider=None, repeatable=False), 'napari:activate_image_transform_mode': Action(command=<function activate_image_transform_mode at 0x131b2f1a0>, description='Transform', keymapprovider=<class 'napari.layers.image.image.Image'>, repeatable=False), 'napari:activate_image_pan_zoom_mode': Action(command=<function activate_image_pan_zoom_mode at 0x131b2f2e0>, description='Pan/zoom', keymapprovider=<class 'napari.layers.image.image.Image'>, repeatable=False), 'napari:activate_labels_transform_mode': Action(command=<function activate_labels_transform_mode at 0x1321754e0>, description='Transform', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:activate_labels_pan_zoom_mode': Action(command=<function activate_labels_pan_zoom_mode at 0x132175620>, description='Pan/zoom', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:activate_labels_paint_mode': Action(command=<function activate_labels_paint_mode at 0x132175760>, description='Activate the paint brush', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:activate_labels_polygon_mode': Action(command=<function activate_labels_polygon_mode at 0x1321758a0>, description='Activate the polygon tool', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:activate_labels_fill_mode': Action(command=<function activate_labels_fill_mode at 0x1321759e0>, description='Activate the fill bucket', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:activate_labels_picker_mode': Action(command=<function activate_labels_picker_mode at 0x132175b20>, description='Pick mode', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:activate_labels_erase_mode': Action(command=<function activate_labels_erase_mode at 0x132175d00>, description='Activate the label eraser', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:new_label': Action(command=<function new_label at 0x132175c60>, description='Set the currently selected label to the largest used label plus one.', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:swap_selected_and_background_labels': Action(command=<function swap_selected_and_background_labels at 0x132175e40>, description='Swap between the selected label and the background label.', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:decrease_label_id': Action(command=<function decrease_label_id at 0x132175ee0>, description='Decrease the currently selected label by one.', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:increase_label_id': Action(command=<function increase_label_id at 0x132175f80>, description='Increase the currently selected label by one.', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:decrease_brush_size': Action(command=<function decrease_brush_size at 0x132176020>, description='Decrease the paint brush size by one.', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=True), 'napari:increase_brush_size': Action(command=<function increase_brush_size at 0x1321760c0>, description='Increase the paint brush size by one.', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=True), 'napari:toggle_preserve_labels': Action(command=<function toggle_preserve_labels at 0x1321762a0>, description='Toggle preserve labels', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:reset_polygon': Action(command=<function reset_polygon at 0x132176480>, description='Reset the current polygon', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:complete_polygon': Action(command=<function complete_polygon at 0x132176520>, description='Complete the current polygon', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:activate_points_transform_mode': Action(command=<function activate_points_transform_mode at 0x134016480>, description='Transform', keymapprovider=<class 'napari.layers.points.points.Points'>, repeatable=False), 'napari:activate_points_pan_zoom_mode': Action(command=<function activate_points_pan_zoom_mode at 0x1340165c0>, description='Pan/zoom', keymapprovider=<class 'napari.layers.points.points.Points'>, repeatable=False), 'napari:activate_points_add_mode': Action(command=<function activate_points_add_mode at 0x134016700>, description='Add points', keymapprovider=<class 'napari.layers.points.points.Points'>, repeatable=False), 'napari:activate_points_select_mode': Action(command=<function activate_points_select_mode at 0x134016840>, description='Select points', keymapprovider=<class 'napari.layers.points.points.Points'>, repeatable=False), 'napari:select_all_in_slice': Action(command=<function select_all_in_slice at 0x134016a20>, description='Select/Deselect all points in the current view slice.', keymapprovider=<class 'napari.layers.points.points.Points'>, repeatable=False), 'napari:select_all_data': Action(command=<function select_all_data at 0x134016ac0>, description='Select/Deselect all points in the layer.', keymapprovider=<class 'napari.layers.points.points.Points'>, repeatable=False), 'napari:delete_selected_points': Action(command=<function delete_selected_points at 0x134016b60>, description='Delete selected points', keymapprovider=<class 'napari.layers.points.points.Points'>, repeatable=False), 'napari:activate_shapes_transform_mode': Action(command=<function activate_shapes_transform_mode at 0x13494bf60>, description='Transform', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_shapes_pan_zoom_mode': Action(command=<function activate_shapes_pan_zoom_mode at 0x1349540e0>, description='Pan/zoom', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_add_rectangle_mode': Action(command=<function activate_add_rectangle_mode at 0x134954220>, description='Add rectangles', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_add_ellipse_mode': Action(command=<function activate_add_ellipse_mode at 0x134954360>, description='Add ellipses', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_add_line_mode': Action(command=<function activate_add_line_mode at 0x1349544a0>, description='Add lines', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_add_path_mode': Action(command=<function activate_add_path_mode at 0x1349545e0>, description='Add path', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_add_polygon_mode': Action(command=<function activate_add_polygon_mode at 0x134954720>, description='Add polygons', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_add_polygon_lasso_mode': Action(command=<function activate_add_polygon_lasso_mode at 0x134954860>, description='Add polygons lasso', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_direct_mode': Action(command=<function activate_direct_mode at 0x1349549a0>, description='Select vertices', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_select_mode': Action(command=<function activate_select_mode at 0x134954ae0>, description='Select shapes', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_vertex_insert_mode': Action(command=<function activate_vertex_insert_mode at 0x134954c20>, description='Insert vertex', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_vertex_remove_mode': Action(command=<function activate_vertex_remove_mode at 0x134954d60>, description='Remove vertex', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:copy_selected_shapes': Action(command=<function copy_selected_shapes at 0x134954cc0>, description='Copy any selected shapes', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:paste_shape': Action(command=<function paste_shape at 0x134954e00>, description='Paste any copied shapes', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:select_all_shapes': Action(command=<function select_all_shapes at 0x134954ea0>, description='Select all shapes in the current view slice', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:delete_selected_shapes': Action(command=<function delete_selected_shapes at 0x134954f40>, description='Delete any selected shapes', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:move_shapes_selection_to_front': Action(command=<function move_shapes_selection_to_front at 0x134954fe0>, description='Move to front', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:move_shapes_selection_to_back': Action(command=<function move_shapes_selection_to_back at 0x134955080>, description='Move to back', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:finish_drawing_shape': Action(command=<function finish_drawing_shape at 0x134955120>, description='Finish any drawing, for example when using the path or polygon tool.', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_surface_transform_mode': Action(command=<function activate_surface_transform_mode at 0x134a00b80>, description='Transform', keymapprovider=<class 'napari.layers.surface.surface.Surface'>, repeatable=False), 'napari:activate_surface_pan_zoom_mode': Action(command=<function activate_surface_pan_zoom_mode at 0x134a00cc0>, description='Pan/zoom', keymapprovider=<class 'napari.layers.surface.surface.Surface'>, repeatable=False), 'napari:activate_tracks_transform_mode': Action(command=<function activate_tracks_transform_mode at 0x134a00f40>, description='Transform', keymapprovider=<class 'napari.layers.tracks.tracks.Tracks'>, repeatable=False), 'napari:activate_tracks_pan_zoom_mode': Action(command=<function activate_tracks_pan_zoom_mode at 0x134a01080>, description='Pan/zoom', keymapprovider=<class 'napari.layers.tracks.tracks.Tracks'>, repeatable=False), 'napari:activate_vectors_transform_mode': Action(command=<function activate_vectors_transform_mode at 0x134a01760>, description='Transform', keymapprovider=<class 'napari.layers.vectors.vectors.Vectors'>, repeatable=False), 'napari:activate_vectors_pan_zoom_mode': Action(command=<function activate_vectors_pan_zoom_mode at 0x134a018a0>, description='Pan/zoom', keymapprovider=<class 'napari.layers.vectors.vectors.Vectors'>, repeatable=False), 'napari:reset_scroll_progress': Action(command=<function reset_scroll_progress at 0x134a48680>, description='Reset scroll.', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:toggle_ndisplay': Action(command=<function toggle_ndisplay at 0x134a48720>, description='Toggle 2D/3D view.', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:toggle_theme': Action(command=<function toggle_theme at 0x134a487c0>, description='Toggle current viewer theme.', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:reset_view': Action(command=<function reset_view at 0x134a48860>, description='Reset view to original state.', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:delete_selected_layers': Action(command=<function delete_selected_layers at 0x134a48900>, description='Delete selected layers.', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:increment_dims_left': Action(command=<function increment_dims_left at 0x134a489a0>, description='Increment dimensions slider to the left.', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=True), 'napari:increment_dims_right': Action(command=<function increment_dims_right at 0x134a48a40>, description='Increment dimensions slider to the right.', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=True), 'napari:focus_axes_up': Action(command=<function focus_axes_up at 0x134a48ae0>, description='Move focus of dimensions slider up.', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:focus_axes_down': Action(command=<function focus_axes_down at 0x134a48b80>, description='Move focus of dimensions slider down.', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:roll_axes': Action(command=<function roll_axes at 0x134a48c20>, description='Change order of the visible axes, e.g.\xa0[0,\xa01,\xa02]\xa0‑>\xa0[2,\xa00,\xa01].', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:transpose_axes': Action(command=<function transpose_axes at 0x134a48cc0>, description='Transpose order of the last two visible axes, e.g.\xa0[0,\xa01]\xa0‑>\xa0[1,\xa00].', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:toggle_grid': Action(command=<function toggle_grid at 0x134a48d60>, description='Toggle grid mode.', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:toggle_selected_visibility': Action(command=<function toggle_selected_visibility at 0x134a48e00>, description='Toggle visibility of selected layers', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:toggle_unselected_visibility': Action(command=<function toggle_unselected_visibility at 0x134a48ea0>, description='Toggle visibility of unselected layers', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:show_only_layer_above': Action(command=<function show_only_layer_above at 0x134a48f40>, description='Select and show only layer above.', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:show_only_layer_below': Action(command=<function show_only_layer_below at 0x134a48fe0>, description='Select and show only layer below.', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:toggle_console_visibility': Action(command=<function toggle_console_visibility at 0x134a49080>, description='Show/Hide IPython console (only available when napari started as standalone application)', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:hold_for_pan_zoom': Action(command=<function hold_for_pan_zoom at 0x134a49120>, description='Press and hold for pan/zoom mode', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:show_shortcuts': Action(command=<function show_shortcuts at 0x134a491c0>, description='Show all key bindings', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False)}
        name = 'napari:toggle_ndisplay'
        self = <napari.utils.action_manager.ActionManager object at 0x13103ebd0>

File ~/Dev/miniforge3/envs/napari-dev/lib/python3.12/site-packages/in_n_out/_store.py:804, in Store.inject.<locals>._inner.<locals>._exec(*args=(), **kwargs={})
    797 logger.debug(
    798     "  Calling %s with %r (injected %r)",
    799     _fname,
    800     bound.arguments,
    801     _injected_names,
    802 )
    803 try:
--> 804     result = func(**bound.arguments)
        bound = <BoundArguments (viewer=Viewer(camera=Camera(center=(4.5, 127.5, 127.5), zoom=np.float64(2.2191406249999996), angles=(np.float64(0.0), np.float64(0.0), np.float64(89.99999999999999)), perspective=0.0, mouse_pan=True, mouse_zoom=True), cursor=Cursor(position=(np.float64(4.499999999999993), np.float64(241.5081012432392), np.float64(116.00906557728582)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(4.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[<Image layer 'brain' at 0x315ead100>], help='use <2> for transform', status={'layer_name': 'brain', 'layer_base': 'brain', 'source_type': 'sample', 'plugin': 'napari builtins', 'coordinates': ' [4 242 116]'}, tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_over_canvas=True, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[], mouse_wheel_callbacks=[<function dims_scroll at 0x11348d580>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={}))>
        func = <function toggle_ndisplay at 0x134a48720>
        bound.arguments = {'viewer': Viewer(camera=Camera(center=(4.5, 127.5, 127.5), zoom=np.float64(2.2191406249999996), angles=(np.float64(0.0), np.float64(0.0), np.float64(89.99999999999999)), perspective=0.0, mouse_pan=True, mouse_zoom=True), cursor=Cursor(position=(np.float64(4.499999999999993), np.float64(241.5081012432392), np.float64(116.00906557728582)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(4.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[<Image layer 'brain' at 0x315ead100>], help='use <2> for transform', status={'layer_name': 'brain', 'layer_base': 'brain', 'source_type': 'sample', 'plugin': 'napari builtins', 'coordinates': ' [4 242 116]'}, tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_over_canvas=True, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[], mouse_wheel_callbacks=[<function dims_scroll at 0x11348d580>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})}
    805 except TypeError as e:
    806     if "missing" not in e.args[0]:

File ~/Dev/napari/napari/components/_viewer_key_bindings.py:63, in toggle_ndisplay(viewer=Viewer(camera=Camera(center=(4.5, 127.5, 127.5),...use_drag_gen={}, _mouse_wheel_gen={}, _keymap={}))
     60 @register_viewer_action(trans._('Toggle 2D/3D view.'))
     61 def toggle_ndisplay(viewer: Viewer):
     62     if viewer.dims.ndisplay == 2:
---> 63         viewer.dims.ndisplay = 3
        viewer = Viewer(camera=Camera(center=(4.5, 127.5, 127.5), zoom=np.float64(2.2191406249999996), angles=(np.float64(0.0), np.float64(0.0), np.float64(89.99999999999999)), perspective=0.0, mouse_pan=True, mouse_zoom=True), cursor=Cursor(position=(np.float64(4.499999999999993), np.float64(241.5081012432392), np.float64(116.00906557728582)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(4.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[<Image layer 'brain' at 0x315ead100>], help='use <2> for transform', status={'layer_name': 'brain', 'layer_base': 'brain', 'source_type': 'sample', 'plugin': 'napari builtins', 'coordinates': ' [4 242 116]'}, tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_over_canvas=True, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[], mouse_wheel_callbacks=[<function dims_scroll at 0x11348d580>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})
     64     else:
     65         viewer.dims.ndisplay = 2

File ~/Dev/napari/napari/utils/_proxies.py:146, in PublicOnlyProxy.__setattr__(self=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_l....float64(127.0), np.float64(127.0)), last_used=0), name='ndisplay', value=3)
    128 if isinstance(value, PublicOnlyProxy):
    129     # if we want to set an attribute on a PublicOnlyProxy *and* the
    130     # value that we want to set is itself a PublicOnlyProxy, we unwrap
   (...)
    142     # layer selection will not propagate the selection to the Viewer.
    143     # See https://github.com/napari/napari/issues/5767
    144     value = value.__wrapped__
--> 146 setattr(self.__wrapped__, name, value)
        name = 'ndisplay'
        value = 3
        self = Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(4.0), np.float64(127.0), np.float64(127.0)), last_used=0)
    147 return None

File ~/Dev/napari/napari/utils/events/evented_model.py:307, in EventedModel.__setattr__(self=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_l....float64(127.0), np.float64(127.0)), last_used=0), name='ndisplay', value=3)
    305     super().__setattr__(name, value)
    306     return
--> 307 with ComparisonDelayer(self):
        self = Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(4.0), np.float64(127.0), np.float64(127.0)), last_used=0)
    308     self._primary_changes.add(name)
    309     self._setattr_impl(name, value)

File ~/Dev/napari/napari/utils/events/evented_model.py:520, in ComparisonDelayer.__exit__(self=<napari.utils.events.evented_model.ComparisonDelayer object>, exc_type=None, exc_val=None, exc_tb=None)
    518 def __exit__(self, exc_type, exc_val, exc_tb):
    519     self._target._delay_check_semaphore -= 1
--> 520     self._target._check_if_values_changed_and_emit_if_needed()
        self._target = Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(4.0), np.float64(127.0), np.float64(127.0)), last_used=0)
        self = <napari.utils.events.evented_model.ComparisonDelayer object at 0x3181b6ab0>

File ~/Dev/napari/napari/utils/events/evented_model.py:345, in EventedModel._check_if_values_changed_and_emit_if_needed(self=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_l....float64(127.0), np.float64(127.0)), last_used=0))
    342 with ComparisonDelayer(self):
    343     # Again delay comparison to avoid having events caused by callback functions
    344     for name, new_value in to_emit:
--> 345         getattr(self.events, name)(value=new_value)
        name = 'ndisplay'
        self = Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(4.0), np.float64(127.0), np.float64(127.0)), last_used=0)
        new_value = 3

File ~/Dev/napari/napari/utils/events/event.py:764, in EventEmitter.__call__(self=<napari.utils.events.event.EventEmitter object>, *args=(), **kwargs={'value': 3})
    761     self._block_counter.update([cb])
    762     continue
--> 764 self._invoke_callback(cb, event if pass_event else None)
        event = <Event blocked=False handled=False native=None source=None sources=[] type='ndisplay'>
        self = <napari.utils.events.event.EventEmitter object at 0x136ebc170>
        cb = <bound method ViewerModel._update_layers of Viewer(camera=Camera(center=(4.5, 127.5, 127.5), zoom=np.float64(2.2191406249999996), angles=(np.float64(0.0), np.float64(0.0), np.float64(89.99999999999999)), perspective=0.0, mouse_pan=True, mouse_zoom=True), cursor=Cursor(position=(np.float64(4.499999999999993), np.float64(241.5081012432392), np.float64(116.00906557728582)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(4.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[<Image layer 'brain' at 0x315ead100>], help='use <2> for transform', status={'layer_name': 'brain', 'layer_base': 'brain', 'source_type': 'sample', 'plugin': 'napari builtins', 'coordinates': ' [4 242 116]'}, tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_over_canvas=True, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[], mouse_wheel_callbacks=[<function dims_scroll at 0x11348d580>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})>
        pass_event = False
    765 if event.blocked:
    766     break

File ~/Dev/napari/napari/utils/events/event.py:802, in EventEmitter._invoke_callback(self=<napari.utils.events.event.EventEmitter object>, cb=<bound method ViewerModel._update_layers of View...se_drag_gen={}, _mouse_wheel_gen={}, _keymap={})>, event=None)
    800     self.disconnect(cb)
    801     return
--> 802 _handle_exception(
        self = <napari.utils.events.event.EventEmitter object at 0x136ebc170>
        event = None
        cb = <bound method ViewerModel._update_layers of Viewer(camera=Camera(center=(4.5, 127.5, 127.5), zoom=np.float64(2.2191406249999996), angles=(np.float64(0.0), np.float64(0.0), np.float64(89.99999999999999)), perspective=0.0, mouse_pan=True, mouse_zoom=True), cursor=Cursor(position=(np.float64(4.499999999999993), np.float64(241.5081012432392), np.float64(116.00906557728582)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(4.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[<Image layer 'brain' at 0x315ead100>], help='use <2> for transform', status={'layer_name': 'brain', 'layer_base': 'brain', 'source_type': 'sample', 'plugin': 'napari builtins', 'coordinates': ' [4 242 116]'}, tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_over_canvas=True, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[], mouse_wheel_callbacks=[<function dims_scroll at 0x11348d580>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})>
        (cb, event) = (<bound method ViewerModel._update_layers of Viewer(camera=Camera(center=(4.5, 127.5, 127.5), zoom=np.float64(2.2191406249999996), angles=(np.float64(0.0), np.float64(0.0), np.float64(89.99999999999999)), perspective=0.0, mouse_pan=True, mouse_zoom=True), cursor=Cursor(position=(np.float64(4.499999999999993), np.float64(241.5081012432392), np.float64(116.00906557728582)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(4.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[<Image layer 'brain' at 0x315ead100>], help='use <2> for transform', status={'layer_name': 'brain', 'layer_base': 'brain', 'source_type': 'sample', 'plugin': 'napari builtins', 'coordinates': ' [4 242 116]'}, tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_over_canvas=True, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[], mouse_wheel_callbacks=[<function dims_scroll at 0x11348d580>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})>, None)
    803     self.ignore_callback_errors,
    804     self.print_callback_errors,
    805     self,
    806     cb_event=(cb, event),
    807 )

File ~/Dev/napari/napari/utils/events/event.py:791, in EventEmitter._invoke_callback(self=<napari.utils.events.event.EventEmitter object>, cb=<bound method ViewerModel._update_layers of View...se_drag_gen={}, _mouse_wheel_gen={}, _keymap={})>, event=None)
    789         cb(event)
    790     else:
--> 791         cb()
        cb = <bound method ViewerModel._update_layers of Viewer(camera=Camera(center=(4.5, 127.5, 127.5), zoom=np.float64(2.2191406249999996), angles=(np.float64(0.0), np.float64(0.0), np.float64(89.99999999999999)), perspective=0.0, mouse_pan=True, mouse_zoom=True), cursor=Cursor(position=(np.float64(4.499999999999993), np.float64(241.5081012432392), np.float64(116.00906557728582)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(4.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[<Image layer 'brain' at 0x315ead100>], help='use <2> for transform', status={'layer_name': 'brain', 'layer_base': 'brain', 'source_type': 'sample', 'plugin': 'napari builtins', 'coordinates': ' [4 242 116]'}, tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_over_canvas=True, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[], mouse_wheel_callbacks=[<function dims_scroll at 0x11348d580>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})>
    792 except Exception as e:  # noqa: BLE001
    793     # dead Qt object with living python pointer. not importing Qt
    794     # here... but this error is consistent across backends
    795     if (
    796         isinstance(e, RuntimeError)
    797         and 'C++' in str(e)
    798         and str(e).endswith(('has been deleted', 'already deleted.'))
    799     ):

File ~/Dev/napari/napari/components/viewer_model.py:471, in ViewerModel._update_layers(self=Viewer(camera=Camera(center=(4.5, 127.5, 127.5),...use_drag_gen={}, _mouse_wheel_gen={}, _keymap={}), layers=[<Image layer 'brain' at 0x315ead100>])
    463 """Updates the contained layers.
    464 
    465 Parameters
   (...)
    468     List of layers to update. If none provided updates all.
    469 """
    470 layers = layers or self.layers
--> 471 self._layer_slicer.submit(layers=layers, dims=self.dims)
        layers = [<Image layer 'brain' at 0x315ead100>]
        self = Viewer(camera=Camera(center=(4.5, 127.5, 127.5), zoom=np.float64(2.2191406249999996), angles=(np.float64(0.0), np.float64(0.0), np.float64(89.99999999999999)), perspective=0.0, mouse_pan=True, mouse_zoom=True), cursor=Cursor(position=(np.float64(4.499999999999993), np.float64(241.5081012432392), np.float64(116.00906557728582)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(4.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[<Image layer 'brain' at 0x315ead100>], help='use <2> for transform', status={'layer_name': 'brain', 'layer_base': 'brain', 'source_type': 'sample', 'plugin': 'napari builtins', 'coordinates': ' [4 242 116]'}, tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_over_canvas=True, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[], mouse_wheel_callbacks=[<function dims_scroll at 0x11348d580>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})
        self._layer_slicer = <napari.components._layer_slicer._LayerSlicer object at 0x136ebe0f0>
        self.dims = Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(4.0), np.float64(127.0), np.float64(127.0)), last_used=0)
    472 # If the currently selected layer is sliced asynchronously, then the value
    473 # shown with this position may be incorrect. See the discussion for more details:
    474 # https://github.com/napari/napari/pull/5377#discussion_r1036280855
    475 position = list(self.cursor.position)

File ~/Dev/napari/napari/components/_layer_slicer.py:246, in _LayerSlicer.submit(self=<napari.components._layer_slicer._LayerSlicer object>, layers=[<Image layer 'brain' at 0x315ead100>], dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_l....float64(127.0), np.float64(127.0)), last_used=0), force=False)
    244 # Then execute sync slicing tasks to run concurrent with async ones.
    245 for layer in sync_layers:
--> 246     layer._slice_dims(
        layer = <Image layer 'brain' at 0x315ead100>
        dims = Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(4.0), np.float64(127.0), np.float64(127.0)), last_used=0)
        force = False
    247         dims=dims,
    248         force=force,
    249     )
    251 return task

File ~/Dev/napari/napari/layers/base/base.py:1291, in Layer._slice_dims(self=<Image layer 'brain'>, dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_l....float64(127.0), np.float64(127.0)), last_used=0), force=False)
   1289 if force or (self._slice_input != slice_input):
   1290     self._slice_input = slice_input
-> 1291     self._refresh_sync()
        self = <Image layer 'brain' at 0x315ead100>

File ~/Dev/napari/napari/layers/base/base.py:1534, in Layer._refresh_sync(self=<Image layer 'brain'>, event=None)
   1532 logger.debug('Layer._refresh_sync: %s', self)
   1533 if self.visible:
-> 1534     self.set_view_slice()
        self = <Image layer 'brain' at 0x315ead100>
   1535     self.events.set_data()
   1536     self._update_thumbnail()

File ~/Dev/napari/napari/layers/base/base.py:1259, in Layer.set_view_slice(self=<Image layer 'brain'>)
   1257 def set_view_slice(self) -> None:
   1258     with self.dask_optimized_slicing():
-> 1259         self._set_view_slice()
        self = <Image layer 'brain' at 0x315ead100>

File ~/Dev/napari/napari/layers/_scalar_field/scalar_field.py:489, in ScalarFieldBase._set_view_slice(self=<Image layer 'brain'>)
    483 request = self._make_slice_request_internal(
    484     slice_input=self._slice_input,
    485     data_slice=self._data_slice,
    486     dask_indexer=nullcontext,
    487 )
    488 response = request()
--> 489 self._update_slice_response(response)
        response = _ImageSliceResponse(slice_input=_SliceInput(ndisplay=3, world_slice=_ThickNDSlice(point=(np.float64(4.0), np.float64(127.0), np.float64(127.0)), margin_left=(np.float64(0.0), np.float64(0.0), np.float64(0.0)), margin_right=(np.float64(0.0), np.float64(0.0), np.float64(0.0))), order=(np.int64(0), np.int64(1), np.int64(2))), request_id=131, empty=False)
        self = <Image layer 'brain' at 0x315ead100>

File ~/Dev/napari/napari/layers/image/image.py:403, in Image._update_slice_response(self=<Image layer 'brain'>, response=_ImageSliceResponse(slice_input=_SliceInput(ndis...4(1), np.int64(2))), request_id=131, empty=False))
    401     data = response.image.raw
    402     input_data = data[-1] if self.multiscale else data
--> 403     self.contrast_limits = calc_data_range(input_data, rgb=self.rgb)
        self = <Image layer 'brain' at 0x315ead100>
        input_data = array([[[4, 4, ..., 4, 4],
        [4, 4, ..., 4, 4],
        ...,
        [4, 4, ..., 4, 4],
        [4, 4, ..., 4, 4]],

       [[4, 4, ..., 4, 4],
        [4, 4, ..., 4, 4],
        ...,
        [4, 4, ..., 4, 4],
        [4, 4, ..., 4, 4]],

       ...,

       [[4, 4, ..., 4, 4],
        [4, 4, ..., 4, 4],
        ...,
        [4, 4, ..., 4, 4],
        [4, 4, ..., 4, 4]],

       [[4, 4, ..., 4, 4],
        [4, 4, ..., 4, 4],
        ...,
        [4, 4, ..., 4, 4],
        [4, 4, ..., 4, 4]]], dtype=uint16)
        self.rgb = False
    405 super()._update_slice_response(response)
    407 # Maybe reset the contrast limits based on the new slice.

File ~/Dev/napari/napari/layers/image/image.py:681, in Image.contrast_limits(self=<Image layer 'brain'>, contrast_limits=(0.0, 51076.0))
    679 @IntensityVisualizationMixin.contrast_limits.setter  # type: ignore [attr-defined]
    680 def contrast_limits(self, contrast_limits):
--> 681     IntensityVisualizationMixin.contrast_limits.fset(self, contrast_limits)
        self = <Image layer 'brain' at 0x315ead100>
        contrast_limits = (0.0, 51076.0)
    682     if not np.allclose(
    683         _coerce_contrast_limits(self.contrast_limits).contrast_limits,
    684         self.contrast_limits,
    685     ):
    686         prev = self._keep_auto_contrast

File ~/Dev/napari/napari/layers/intensity_mixin.py:111, in IntensityVisualizationMixin.contrast_limits(self=<Image layer 'brain'>, contrast_limits=(0.0, 51076.0))
    109 newrange[1] = max(newrange[1], contrast_limits[1])
    110 self.contrast_limits_range = newrange
--> 111 self._update_thumbnail()
        self = <Image layer 'brain' at 0x315ead100>
    112 self.events.contrast_limits()

File ~/Dev/napari/napari/layers/image/image.py:611, in Image._update_thumbnail(self=<Image layer 'brain'>)
    609         colormapped = np.concatenate([downsampled, alpha], axis=2)
    610 else:
--> 611     downsampled = ndi.zoom(
        ndi = <module 'scipy.ndimage' from '/Users/piotrsobolewski/Dev/miniforge3/envs/napari-dev/lib/python3.12/site-packages/scipy/ndimage/__init__.py'>
        image = array([ 36, 121, ...,  36,  25], dtype=uint16)
        zoom_factor = (np.float64(0.125), np.float64(0.125))
    612         image, zoom_factor, prefilter=False, order=0
    613     )
    614     low, high = self.contrast_limits
    615     if np.issubdtype(downsampled.dtype, np.integer):

File ~/Dev/miniforge3/envs/napari-dev/lib/python3.12/site-packages/scipy/ndimage/_interpolation.py:813, in zoom(input=array([ 36, 121, ...,  36,  25], dtype=uint16), zoom=(np.float64(0.125), np.float64(0.125)), output=None, order=0, mode='constant', cval=0.0, prefilter=False, grid_mode=False)
    811 if input.ndim < 1:
    812     raise RuntimeError('input and output rank must be > 0')
--> 813 zoom = _ni_support._normalize_sequence(zoom, input.ndim)
        input = array([ 36, 121, ...,  36,  25], dtype=uint16)
        zoom = (np.float64(0.125), np.float64(0.125))
        _ni_support = <module 'scipy.ndimage._ni_support' from '/Users/piotrsobolewski/Dev/miniforge3/envs/napari-dev/lib/python3.12/site-packages/scipy/ndimage/_ni_support.py'>
    814 output_shape = tuple(
    815         [int(round(ii * jj)) for ii, jj in zip(input.shape, zoom)])
    816 complex_output = np.iscomplexobj(input)

File ~/Dev/miniforge3/envs/napari-dev/lib/python3.12/site-packages/scipy/ndimage/_ni_support.py:68, in _normalize_sequence(input=(np.float64(0.125), np.float64(0.125)), rank=1)
     66     if len(normalized) != rank:
     67         err = "sequence argument must have length equal to input rank"
---> 68         raise RuntimeError(err)
        err = 'sequence argument must have length equal to input rank'
     69 else:
     70     normalized = [input] * rank

RuntimeError: sequence argument must have length equal to input rank

A similar traceback occurs if you start in 3D, set continuous, and then toggle to 2D, except that it will be spammed when moving the slider.

Appears to be triggered by updating the thumbnail. It does appear to be mostly harmless, but annoying.

💡 Steps to Reproduce

Open a 3D image. In 2D mode set continuous auto contrast, then toggle to 3D In 3D mode set continuous auto contrast, then toggle to 2D, move the slider.

💡 Expected Behavior

No traceback.

🌎 Environment

napari: 0.5.0a2.dev359+g0907fdad5 Platform: macOS-14.5-arm64-arm-64bit System: MacOS 14.5 Python: 3.12.4 | packaged by conda-forge | (main, Jun 17 2024, 10:13:44) [Clang 16.0.6 ] Qt: 6.7.1 PyQt6: NumPy: 2.0.1 SciPy: 1.14.0 Dask: 2024.7.1 VisPy: 0.14.3 magicgui: 0.8.3 superqt: 0.6.7 in-n-out: 0.2.1 app-model: 0.2.8 npe2: 0.7.7

OpenGL:

  • GL version: 2.1 Metal - 88.1
  • MAX_TEXTURE_SIZE: 16384
  • GL_MAX_3D_TEXTURE_SIZE: 2048

Screens:

  • screen 1: resolution 1680x1050, scale 2.0

Optional:

  • numba: 0.60.0
  • triangle not installed
  • napari-plugin-manager: 0.1.0a3.dev189+gc48deb2

Settings path:

  • /Users/piotrsobolewski/Library/Application Support/napari/napari-dev_a1eb8b76ba95fa16ad06e26097b46b8455dfbf0b/settings.yaml

💡 Additional Context

No response

psobolewskiPhD avatar Aug 03 '24 18:08 psobolewskiPhD

Bisect points to 65e5d38f658a3da3df85b868051ec28b26a8c5c4

psobolewskiPhD avatar Aug 04 '24 03:08 psobolewskiPhD

btw #6537 should have been a bugfix, not maintenance. 😉

jni avatar Aug 05 '24 02:08 jni

(but no point changing the label now)

jni avatar Aug 05 '24 02:08 jni

(but no point changing the label now)

Still may regenerate release notes with proper labeling.,

Also such change will impact the dashboard.

Czaki avatar Aug 05 '24 07:08 Czaki

Just bumping that this is still an issue. Here is the current traceback, with slightly more info than OP:

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
File ~\Documents\GitHub\napari\src\napari\utils\action_manager.py:230, in ActionManager.bind_button.<locals>._trigger()
    229 def _trigger():
--> 230     self.trigger(name)
        name = 'napari:toggle_ndisplay'
        self = <napari.utils.action_manager.ActionManager object at 0x000001C22DBCAF30>
File ~\Documents\GitHub\napari\src\napari\utils\action_manager.py:432, in ActionManager.trigger(self=<napari.utils.action_manager.ActionManager object>, name='napari:toggle_ndisplay')
    430 def trigger(self, name: str) -> Any:
    431     """Trigger the action `name`."""
--> 432     return self._actions[name].injected()
        self._actions[name].injected = <function toggle_ndisplay at 0x000001C23EE94D60>
        self._actions[name] = Action(command=<function toggle_ndisplay at 0x000001C22F105260>, description='Toggle 2D/3D view', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False)
        self._actions = {'napari:orient_plane_normal_along_z': Action(command=<function orient_plane_normal_along_z at 0x000001C22DD66AC0>, description='Orient plane normal along z-axis', keymapprovider=<class 'napari.layers.image.image.Image'>, repeatable=False), 'napari:orient_plane_normal_along_y': Action(command=<function orient_plane_normal_along_y at 0x000001C22DD66A20>, description='Orient plane normal along y-axis', keymapprovider=<class 'napari.layers.image.image.Image'>, repeatable=False), 'napari:orient_plane_normal_along_x': Action(command=<function orient_plane_normal_along_x at 0x000001C22DD66B60>, description='Orient plane normal along x-axis', keymapprovider=<class 'napari.layers.image.image.Image'>, repeatable=False), 'napari:orient_plane_normal_along_view_direction': Action(command=<function orient_plane_normal_along_view_direction at 0x000001C22DD66C00>, description='Orient plane normal along view direction\nHold down to have plane follow camera', keymapprovider=<class 'napari.layers.image.image.Image'>, repeatable=False), 'napari:orient_plane_normal_along_view_direction_no_gen': Action(command=<function orient_plane_normal_along_view_direction_no_gen at 0x000001C22DCF3F60>, description='Orient plane normal along view direction button', keymapprovider=None, repeatable=False), 'napari:activate_image_transform_mode': Action(command=<function activate_image_transform_mode at 0x000001C22DD66E80>, description='Transform', keymapprovider=<class 'napari.layers.image.image.Image'>, repeatable=False), 'napari:activate_image_pan_zoom_mode': Action(command=<function activate_image_pan_zoom_mode at 0x000001C22DD66FC0>, description='Move camera', keymapprovider=<class 'napari.layers.image.image.Image'>, repeatable=False), 'napari:activate_shapes_transform_mode': Action(command=<function activate_shapes_transform_mode at 0x000001C22F0AE7A0>, description='Transform', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_shapes_pan_zoom_mode': Action(command=<function activate_shapes_pan_zoom_mode at 0x000001C22F0AE8E0>, description='Move camera', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_add_rectangle_mode': Action(command=<function activate_add_rectangle_mode at 0x000001C22F0AEA20>, description='Add rectangles', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_add_ellipse_mode': Action(command=<function activate_add_ellipse_mode at 0x000001C22F0AEB60>, description='Add ellipses', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_add_line_mode': Action(command=<function activate_add_line_mode at 0x000001C22F0AECA0>, description='Add lines', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_add_polyline_mode': Action(command=<function activate_add_polyline_mode at 0x000001C22F0AEDE0>, description='Add polylines', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_add_path_mode': Action(command=<function activate_add_path_mode at 0x000001C22F0AEFC0>, description='Add path', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_add_polygon_mode': Action(command=<function activate_add_polygon_mode at 0x000001C22F0AF1A0>, description='Add polygons', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_add_polygon_lasso_mode': Action(command=<function activate_add_polygon_lasso_mode at 0x000001C22F0AF2E0>, description='Add polygons lasso', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_direct_mode': Action(command=<function activate_direct_mode at 0x000001C22F0AF420>, description='Select vertices', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_select_mode': Action(command=<function activate_select_mode at 0x000001C22F0AF560>, description='Select shapes', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_vertex_insert_mode': Action(command=<function activate_vertex_insert_mode at 0x000001C22F0AF6A0>, description='Insert vertex', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_vertex_remove_mode': Action(command=<function activate_vertex_remove_mode at 0x000001C22F0AF7E0>, description='Remove vertex', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:copy_selected_shapes': Action(command=<function copy_selected_shapes at 0x000001C22F0AF880>, description='Copy any selected shapes', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:paste_shape': Action(command=<function paste_shape at 0x000001C22F0AF920>, description='Paste any copied shapes', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:select_all_shapes': Action(command=<function select_all_shapes at 0x000001C22F0AF9C0>, description='Select/Deselect all shapes in the current view slice', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:delete_selected_shapes': Action(command=<function delete_selected_shapes at 0x000001C22F0AFA60>, description='Delete any selected shapes', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:move_shapes_selection_to_front': Action(command=<function move_shapes_selection_to_front at 0x000001C22F0AFB00>, description='Move to front', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:move_shapes_selection_to_back': Action(command=<function move_shapes_selection_to_back at 0x000001C22F0AFBA0>, description='Move to back', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:finish_drawing_shape': Action(command=<function finish_drawing_shape at 0x000001C22F0AFC40>, description='Finish any drawing, for example when using the path or polygon tool', keymapprovider=<class 'napari.layers.shapes.shapes.Shapes'>, repeatable=False), 'napari:activate_labels_transform_mode': Action(command=<function activate_labels_transform_mode at 0x000001C22F114360>, description='Transform', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:activate_labels_pan_zoom_mode': Action(command=<function activate_labels_pan_zoom_mode at 0x000001C22F1144A0>, description='Move camera', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:activate_labels_paint_mode': Action(command=<function activate_labels_paint_mode at 0x000001C22F1145E0>, description='Activate the paint brush', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:activate_labels_polygon_mode': Action(command=<function activate_labels_polygon_mode at 0x000001C22F114720>, description='Activate the polygon tool', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:activate_labels_fill_mode': Action(command=<function activate_labels_fill_mode at 0x000001C22F114860>, description='Activate the fill bucket', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:activate_labels_picker_mode': Action(command=<function activate_labels_picker_mode at 0x000001C22F1149A0>, description='Pick mode', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:activate_labels_erase_mode': Action(command=<function activate_labels_erase_mode at 0x000001C22F114AE0>, description='Activate the label eraser', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:new_label': Action(command=<function new_label at 0x000001C22F114B80>, description='Set the currently selected label to the largest used label plus one', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:swap_selected_and_background_labels': Action(command=<function swap_selected_and_background_labels at 0x000001C22F114C20>, description='Swap between the selected label and the background label', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:decrease_label_id': Action(command=<function decrease_label_id at 0x000001C22F114CC0>, description='Decrease the currently selected label by one', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:increase_label_id': Action(command=<function increase_label_id at 0x000001C22F114D60>, description='Increase the currently selected label by one', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:decrease_brush_size': Action(command=<function decrease_brush_size at 0x000001C22F114E00>, description='Decrease the paint brush size by one', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=True), 'napari:increase_brush_size': Action(command=<function increase_brush_size at 0x000001C22F114EA0>, description='Increase the paint brush size by one', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=True), 'napari:toggle_preserve_labels': Action(command=<function toggle_preserve_labels at 0x000001C22F114FE0>, description='Toggle preserve labels', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:reset_polygon': Action(command=<function reset_polygon at 0x000001C22F115260>, description='Reset the current polygon', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:complete_polygon': Action(command=<function complete_polygon at 0x000001C22F115300>, description='Complete the current polygon', keymapprovider=<class 'napari.layers.labels.labels.Labels'>, repeatable=False), 'napari:activate_points_transform_mode': Action(command=<function activate_points_transform_mode at 0x000001C23072FBA0>, description='Transform', keymapprovider=<class 'napari.layers.points.points.Points'>, repeatable=False), 'napari:activate_points_pan_zoom_mode': Action(command=<function activate_points_pan_zoom_mode at 0x000001C23072FCE0>, description='Move camera', keymapprovider=<class 'napari.layers.points.points.Points'>, repeatable=False), 'napari:activate_points_add_mode': Action(command=<function activate_points_add_mode at 0x000001C23072FE20>, description='Add points', keymapprovider=<class 'napari.layers.points.points.Points'>, repeatable=False), 'napari:activate_points_select_mode': Action(command=<function activate_points_select_mode at 0x000001C23072FF60>, description='Select points', keymapprovider=<class 'napari.layers.points.points.Points'>, repeatable=False), 'napari:select_all_in_slice': Action(command=<function select_all_in_slice at 0x000001C230734180>, description='Select/Deselect all points in the current view slice', keymapprovider=<class 'napari.layers.points.points.Points'>, repeatable=False), 'napari:select_all_data': Action(command=<function select_all_data at 0x000001C230734220>, description='Select/Deselect all points in the layer', keymapprovider=<class 'napari.layers.points.points.Points'>, repeatable=False), 'napari:delete_selected_points': Action(command=<function delete_selected_points at 0x000001C2307342C0>, description='Delete selected points', keymapprovider=<class 'napari.layers.points.points.Points'>, repeatable=False), 'napari:activate_surface_transform_mode': Action(command=<function activate_surface_transform_mode at 0x000001C2307D0FE0>, description='Transform', keymapprovider=<class 'napari.layers.surface.surface.Surface'>, repeatable=False), 'napari:activate_surface_pan_zoom_mode': Action(command=<function activate_surface_pan_zoom_mode at 0x000001C2307D1120>, description='Move camera', keymapprovider=<class 'napari.layers.surface.surface.Surface'>, repeatable=False), 'napari:activate_tracks_transform_mode': Action(command=<function activate_tracks_transform_mode at 0x000001C2307D1440>, description='Transform', keymapprovider=<class 'napari.layers.tracks.tracks.Tracks'>, repeatable=False), 'napari:activate_tracks_pan_zoom_mode': Action(command=<function activate_tracks_pan_zoom_mode at 0x000001C2307D1580>, description='Move camera', keymapprovider=<class 'napari.layers.tracks.tracks.Tracks'>, repeatable=False), 'napari:activate_vectors_transform_mode': Action(command=<function activate_vectors_transform_mode at 0x000001C2307D1D00>, description='Transform', keymapprovider=<class 'napari.layers.vectors.vectors.Vectors'>, repeatable=False), 'napari:activate_vectors_pan_zoom_mode': Action(command=<function activate_vectors_pan_zoom_mode at 0x000001C2307D1E40>, description='Move camera', keymapprovider=<class 'napari.layers.vectors.vectors.Vectors'>, repeatable=False), 'napari:toggle_ndisplay': Action(command=<function toggle_ndisplay at 0x000001C22F105260>, description='Toggle 2D/3D view', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:toggle_theme': Action(command=<function toggle_theme at 0x000001C22F105300>, description='Toggle current viewer theme', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:reset_view': Action(command=<function reset_view at 0x000001C22F1053A0>, description='Reset view to original state', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:delete_selected_layers': Action(command=<function delete_selected_layers at 0x000001C22F105440>, description='Delete selected layers', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:increment_dims_left': Action(command=<function increment_dims_left at 0x000001C22F1054E0>, description='Increment dimensions slider to the left', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=True), 'napari:increment_dims_right': Action(command=<function increment_dims_right at 0x000001C22F105580>, description='Increment dimensions slider to the right', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=True), 'napari:focus_axes_up': Action(command=<function focus_axes_up at 0x000001C22F105620>, description='Move focus of dimensions slider up', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:focus_axes_down': Action(command=<function focus_axes_down at 0x000001C22F1056C0>, description='Move focus of dimensions slider down', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:roll_axes': Action(command=<function roll_axes at 0x000001C22F105760>, description='Change order of the visible axes, e.g.\xa0[0,\xa01,\xa02]\xa0‑>\xa0[2,\xa00,\xa01]', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:transpose_axes': Action(command=<function transpose_axes at 0x000001C22F105800>, description='Transpose order of the last two visible axes, e.g.\xa0[0,\xa01]\xa0‑>\xa0[1,\xa00]', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:rotate_layers': Action(command=<function rotate_layers at 0x000001C22F1058A0>, description='Rotate layers 90 degrees counter-clockwise', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:toggle_grid': Action(command=<function toggle_grid at 0x000001C22F105940>, description='Toggle grid mode', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:toggle_selected_visibility': Action(command=<function toggle_selected_visibility at 0x000001C22F1059E0>, description='Toggle visibility of selected layers', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:toggle_unselected_visibility': Action(command=<function toggle_unselected_visibility at 0x000001C22F105A80>, description='Toggle visibility of unselected layers', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:show_only_layer_above': Action(command=<function show_only_layer_above at 0x000001C22F105B20>, description='Select and show only layer above', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:show_only_layer_below': Action(command=<function show_only_layer_below at 0x000001C22F105BC0>, description='Select and show only layer below', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:toggle_console_visibility': Action(command=<function toggle_console_visibility at 0x000001C22F105C60>, description='Show/Hide IPython console (only available when napari started as standalone application)', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:hold_for_pan_zoom': Action(command=<function hold_for_pan_zoom at 0x000001C22F105D00>, description='Press and hold for move camera mode', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False), 'napari:show_shortcuts': Action(command=<function show_shortcuts at 0x000001C22F105DA0>, description='Show all key bindings', keymapprovider=<class 'napari.components.viewer_model.ViewerModel'>, repeatable=False)}        
        name = 'napari:toggle_ndisplay'
        self = <napari.utils.action_manager.ActionManager object at 0x000001C22DBCAF30>
File ~\Documents\GitHub\napari\.venv\Lib\site-packages\in_n_out\_store.py:804, in Store.inject.<locals>._inner.<locals>._exec(*args=(), **kwargs={})
    797 logger.debug(
    798     "  Calling %s with %r (injected %r)",
    799     _fname,
    800     bound.arguments,
    801     _injected_names,
    802 )
    803 try:
--> 804     result = func(**bound.arguments)
        bound = <BoundArguments (viewer=Viewer(camera=Camera(center=(0.0, np.float64(132.8894736842105), np.float64(103.69649122807014)), zoom=np.float64(2.2265625), angles=(0.0, 0.0, 90.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(<DepthAxisOrientation.TOWARDS: 'towards'>, <VerticalAxisOrientation.DOWN: 'down'>, <HorizontalAxisOrientation.RIGHT: 'right'>)), cursor=Cursor(position=(np.float64(3.0), np.float64(224.0614035087719), np.float64(90.22280701754384)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[<Image layer 'brain' at 0x1c247bcaa80>], help='use <2> for transform', status='', tooltip=Tooltip(visible=True, text=''), theme='dark', title='napari', mouse_over_canvas=False, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[<function double_click_to_zoom at 0x000001C230773920>], mouse_wheel_callbacks=[<function dims_scroll at 0x000001C230773880>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={}))>
        func = <function toggle_ndisplay at 0x000001C22F105260>
        bound.arguments = {'viewer': Viewer(camera=Camera(center=(0.0, np.float64(132.8894736842105), np.float64(103.69649122807014)), zoom=np.float64(2.2265625), angles=(0.0, 0.0, 90.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(<DepthAxisOrientation.TOWARDS: 'towards'>, <VerticalAxisOrientation.DOWN: 'down'>, <HorizontalAxisOrientation.RIGHT: 'right'>)), cursor=Cursor(position=(np.float64(3.0), np.float64(224.0614035087719), np.float64(90.22280701754384)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[<Image layer 'brain' at 0x1c247bcaa80>], help='use <2> for transform', status='', tooltip=Tooltip(visible=True, text=''), theme='dark', title='napari', mouse_over_canvas=False, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[<function double_click_to_zoom at 0x000001C230773920>], mouse_wheel_callbacks=[<function dims_scroll at 0x000001C230773880>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})}    805 except TypeError as e:
    806     if "missing" not in e.args[0]:

File ~\Documents\GitHub\napari\src\napari\components\_viewer_key_bindings.py:53, in toggle_ndisplay(viewer=Viewer(camera=Camera(center=(0.0, np.float64(132...use_drag_gen={}, _mouse_wheel_gen={}, _keymap={}))
     50 @register_viewer_action(trans._('Toggle 2D/3D view'))
     51 def toggle_ndisplay(viewer: Viewer):
     52     if viewer.dims.ndisplay == 2:
---> 53         viewer.dims.ndisplay = 3
        viewer = Viewer(camera=Camera(center=(0.0, np.float64(132.8894736842105), np.float64(103.69649122807014)), zoom=np.float64(2.2265625), angles=(0.0, 0.0, 90.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(<DepthAxisOrientation.TOWARDS: 'towards'>, <VerticalAxisOrientation.DOWN: 'down'>, <HorizontalAxisOrientation.RIGHT: 'right'>)), cursor=Cursor(position=(np.float64(3.0), np.float64(224.0614035087719), np.float64(90.22280701754384)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[<Image layer 'brain' at 0x1c247bcaa80>], help='use <2> for transform', status='', tooltip=Tooltip(visible=True, text=''), theme='dark', title='napari', mouse_over_canvas=False, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[<function double_click_to_zoom at 0x000001C230773920>], mouse_wheel_callbacks=[<function dims_scroll at 0x000001C230773880>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})     54     else:        
     55         viewer.dims.ndisplay = 2

File ~\Documents\GitHub\napari\src\napari\utils\_proxies.py:149, in PublicOnlyProxy.__setattr__(self=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_l....float64(127.0), np.float64(127.0)), last_used=0), name='ndisplay', value=3)
    131 if isinstance(value, PublicOnlyProxy):
    132     # if we want to set an attribute on a PublicOnlyProxy *and* the
    133     # value that we want to set is itself a PublicOnlyProxy, we unwrap
   (...)    145     # layer selection will not propagate the selection to the Viewer.
    146     # See https://github.com/napari/napari/issues/5767
    147     value = value.__wrapped__
--> 149 setattr(self.__wrapped__, name, value)
        name = 'ndisplay'
        value = 3
        self = Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0)    150 return None

File ~\Documents\GitHub\napari\src\napari\utils\events\evented_model.py:308, in EventedModel.__setattr__(self=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_l....float64(127.0), np.float64(127.0)), last_used=0), name='ndisplay', value=3)       
    306     super().__setattr__(name, value)
    307     return
--> 308 with ComparisonDelayer(self):
        self = Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0)    309     self._primary_changes.add(name)
    310     self._setattr_impl(name, value)

File ~\Documents\GitHub\napari\src\napari\utils\events\evented_model.py:521, in ComparisonDelayer.__exit__(self=<napari.utils.events.evented_model.ComparisonDelayer object>, exc_type=None, exc_val=None, exc_tb=None)
    519 def __exit__(self, exc_type, exc_val, exc_tb):
    520     self._target._delay_check_semaphore -= 1
--> 521     self._target._check_if_values_changed_and_emit_if_needed()
        self._target = Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0)
        self = <napari.utils.events.evented_model.ComparisonDelayer object at 0x000001C24A42A0C0>
File ~\Documents\GitHub\napari\src\napari\utils\events\evented_model.py:346, in EventedModel._check_if_values_changed_and_emit_if_needed(self=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_l....float64(127.0), np.float64(127.0)), last_used=0)) 
    343 with ComparisonDelayer(self):
    344     # Again delay comparison to avoid having events caused by callback functions
    345     for name, new_value in to_emit:
--> 346         getattr(self.events, name)(value=new_value)
        name = 'ndisplay'
        self = Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0)
        new_value = 3
File ~\Documents\GitHub\napari\src\napari\utils\events\event.py:753, in EventEmitter.__call__(self=<napari.utils.events.event.EventEmitter object>, *args=(), **kwargs={'value': 3})
    750     self._block_counter.update([cb])
    751     continue
--> 753 self._invoke_callback(cb, event if pass_event else None)
        event = <Event blocked=False handled=False native=None source=None sources=[] type='ndisplay'>
        self = <napari.utils.events.event.EventEmitter object at 0x000001C230F59D60>
        cb = <bound method ViewerModel._update_layers of Viewer(camera=Camera(center=(0.0, np.float64(132.8894736842105), np.float64(103.69649122807014)), zoom=np.float64(2.2265625), angles=(0.0, 0.0, 90.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(<DepthAxisOrientation.TOWARDS: 'towards'>, <VerticalAxisOrientation.DOWN: 'down'>, <HorizontalAxisOrientation.RIGHT: 'right'>)), cursor=Cursor(position=(np.float64(3.0), np.float64(224.0614035087719), np.float64(90.22280701754384)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[<Image layer 'brain' at 0x1c247bcaa80>], help='use <2> for transform', status='', tooltip=Tooltip(visible=True, text=''), theme='dark', title='napari', mouse_over_canvas=False, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[<function double_click_to_zoom at 0x000001C230773920>], mouse_wheel_callbacks=[<function dims_scroll at 0x000001C230773880>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})>
        pass_event = False    754 if event.blocked:
    755     break

File ~\Documents\GitHub\napari\src\napari\utils\events\event.py:791, in EventEmitter._invoke_callback(self=<napari.utils.events.event.EventEmitter object>, cb=<bound method ViewerModel._update_layers of View...se_drag_gen={}, _mouse_wheel_gen={}, _keymap={})>, event=None)
    789     self.disconnect(cb)
    790     return
--> 791 _handle_exception(
        self = <napari.utils.events.event.EventEmitter object at 0x000001C230F59D60>
        event = None
        cb = <bound method ViewerModel._update_layers of Viewer(camera=Camera(center=(0.0, np.float64(132.8894736842105), np.float64(103.69649122807014)), zoom=np.float64(2.2265625), angles=(0.0, 0.0, 90.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(<DepthAxisOrientation.TOWARDS: 'towards'>, <VerticalAxisOrientation.DOWN: 'down'>, <HorizontalAxisOrientation.RIGHT: 'right'>)), cursor=Cursor(position=(np.float64(3.0), np.float64(224.0614035087719), np.float64(90.22280701754384)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[<Image layer 'brain' at 0x1c247bcaa80>], help='use <2> for transform', status='', tooltip=Tooltip(visible=True, text=''), theme='dark', title='napari', mouse_over_canvas=False, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[<function double_click_to_zoom at 0x000001C230773920>], mouse_wheel_callbacks=[<function dims_scroll at 0x000001C230773880>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})>
        (cb, event) = (<bound method ViewerModel._update_layers of Viewer(camera=Camera(center=(0.0, np.float64(132.8894736842105), np.float64(103.69649122807014)), zoom=np.float64(2.2265625), angles=(0.0, 0.0, 90.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(<DepthAxisOrientation.TOWARDS: 'towards'>, <VerticalAxisOrientation.DOWN: 'down'>, <HorizontalAxisOrientation.RIGHT: 'right'>)), cursor=Cursor(position=(np.float64(3.0), np.float64(224.0614035087719), np.float64(90.22280701754384)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[<Image layer 'brain' at 0x1c247bcaa80>], help='use <2> for transform', status='', tooltip=Tooltip(visible=True, text=''), theme='dark', title='napari', mouse_over_canvas=False, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[<function double_click_to_zoom at 0x000001C230773920>], mouse_wheel_callbacks=[<function dims_scroll at 0x000001C230773880>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})>, None)    792     self.ignore_callback_errors,
    793     self.print_callback_errors,
    794     self,
    795     cb_event=(cb, event),
    796 )

File ~\Documents\GitHub\napari\src\napari\utils\events\event.py:780, in EventEmitter._invoke_callback(self=<napari.utils.events.event.EventEmitter object>, cb=<bound method ViewerModel._update_layers of View...se_drag_gen={}, _mouse_wheel_gen={}, _keymap={})>, event=None)
    778         cb(event)
    779     else:
--> 780         cb()
        cb = <bound method ViewerModel._update_layers of Viewer(camera=Camera(center=(0.0, np.float64(132.8894736842105), np.float64(103.69649122807014)), zoom=np.float64(2.2265625), angles=(0.0, 0.0, 90.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(<DepthAxisOrientation.TOWARDS: 'towards'>, <VerticalAxisOrientation.DOWN: 'down'>, <HorizontalAxisOrientation.RIGHT: 'right'>)), cursor=Cursor(position=(np.float64(3.0), np.float64(224.0614035087719), np.float64(90.22280701754384)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[<Image layer 'brain' at 0x1c247bcaa80>], help='use <2> for transform', status='', tooltip=Tooltip(visible=True, text=''), theme='dark', title='napari', mouse_over_canvas=False, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[<function double_click_to_zoom at 0x000001C230773920>], mouse_wheel_callbacks=[<function dims_scroll at 0x000001C230773880>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})>    781 except Exception as e:  # noqa: BLE001
    782     # dead Qt object with living python pointer. not importing Qt
    783     # here... but this error is consistent across backends
    784     if (
    785         isinstance(e, RuntimeError)
    786         and 'C++' in str(e)
    787         and str(e).endswith(('has been deleted', 'already deleted.'))
    788     ):

File ~\Documents\GitHub\napari\src\napari\components\viewer_model.py:619, in ViewerModel._update_layers(self=Viewer(camera=Camera(center=(0.0, np.float64(132...use_drag_gen={}, _mouse_wheel_gen={}, _keymap={}), layers=[<Image layer 'brain' at 0x1c247bcaa80>])
    611 """Updates the contained layers.
    612
    613 Parameters
   (...)    616     List of layers to update. If none provided updates all.
    617 """
    618 layers = layers or self.layers
--> 619 self._layer_slicer.submit(layers=layers, dims=self.dims)
        layers = [<Image layer 'brain' at 0x1c247bcaa80>]
        self = Viewer(camera=Camera(center=(0.0, np.float64(132.8894736842105), np.float64(103.69649122807014)), zoom=np.float64(2.2265625), angles=(0.0, 0.0, 90.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(<DepthAxisOrientation.TOWARDS: 'towards'>, <VerticalAxisOrientation.DOWN: 'down'>, <HorizontalAxisOrientation.RIGHT: 'right'>)), cursor=Cursor(position=(np.float64(3.0), np.float64(224.0614035087719), np.float64(90.22280701754384)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[<Image layer 'brain' at 0x1c247bcaa80>], help='use <2> for transform', status='', tooltip=Tooltip(visible=True, text=''), theme='dark', title='napari', mouse_over_canvas=False, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[<function double_click_to_zoom at 0x000001C230773920>], mouse_wheel_callbacks=[<function dims_scroll at 0x000001C230773880>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})
        self._layer_slicer = <napari.components._layer_slicer._LayerSlicer object at 0x000001C230F5BC50>
        self.dims = Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0)    620 # If the currently selected layer is sliced asynchronously, then the value
    621 # shown with this position may be incorrect. See the discussion for more details:
    622 # https://github.com/napari/napari/pull/5377#discussion_r1036280855
    623 position = list(self.cursor.position)

File ~\Documents\GitHub\napari\src\napari\components\_layer_slicer.py:245, in _LayerSlicer.submit(self=<napari.components._layer_slicer._LayerSlicer object>, layers=[<Image layer 'brain' at 0x1c247bcaa80>], dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_l....float64(127.0), np.float64(127.0)), last_used=0), force=False)
    243 # Then execute sync slicing tasks to run concurrent with async ones.
    244 for layer in sync_layers:
--> 245     layer._slice_dims(
        layer = <Image layer 'brain' at 0x1c247bcaa80>
        dims = Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0)
        force = False    246         dims=dims,
    247         force=force,
    248     )
    250 return task

File ~\Documents\GitHub\napari\src\napari\layers\base\base.py:1268, in Layer._slice_dims(self=<Image layer 'brain'>, dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_l....float64(127.0), np.float64(127.0)), last_used=0), force=False)        
   1266 if force or (self._slice_input != slice_input):
   1267     self._slice_input = slice_input
-> 1268     self._refresh_sync(
        self = <Image layer 'brain' at 0x1c247bcaa80>   1269         data_displayed=True,
   1270         thumbnail=True,
   1271         highlight=True,
   1272         extent=True,
   1273     )

File ~\Documents\GitHub\napari\src\napari\layers\base\base.py:1543, in Layer._refresh_sync(self=<Image layer 'brain'>, thumbnail=True, data_displayed=True, highlight=True, extent=True, force=False)
   1541     self._clear_extent()
   1542 if data_displayed:
-> 1543     self.set_view_slice()
        self = <Image layer 'brain' at 0x1c247bcaa80>   1544     self.events.set_data()
   1545 if thumbnail:

File ~\Documents\GitHub\napari\src\napari\layers\base\base.py:1236, in Layer.set_view_slice(self=<Image layer 'brain'>)   
   1234 def set_view_slice(self) -> None:
   1235     with self.dask_optimized_slicing():
-> 1236         self._set_view_slice()
        self = <Image layer 'brain' at 0x1c247bcaa80>
File ~\Documents\GitHub\napari\src\napari\layers\_scalar_field\scalar_field.py:500, in ScalarFieldBase._set_view_slice(self=<Image layer 'brain'>)
    494 request = self._make_slice_request_internal(
    495     slice_input=self._slice_input,
    496     data_slice=self._data_slice,
    497     dask_indexer=nullcontext,
    498 )
    499 response = request()
--> 500 self._update_slice_response(response)
        response = _ImageSliceResponse(slice_input=_SliceInput(ndisplay=3, world_slice=_ThickNDSlice(point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), margin_left=(np.float64(0.0), np.float64(0.0), np.float64(0.0)), margin_right=(np.float64(0.0), np.float64(0.0), np.float64(0.0))), order=(np.int64(0), np.int64(1), np.int64(2))), request_id=40, empty=False)
        self = <Image layer 'brain' at 0x1c247bcaa80>
File ~\Documents\GitHub\napari\src\napari\layers\image\image.py:396, in Image._update_slice_response(self=<Image layer 'brain'>, response=_ImageSliceResponse(slice_input=_SliceInput(ndis...64(1), np.int64(2))), request_id=40, empty=False))     
    394     data = response.image.raw
    395     input_data = data[-1] if self.multiscale else data
--> 396     self.contrast_limits = calc_data_range(
        self = <Image layer 'brain' at 0x1c247bcaa80>
        input_data = array([[[4, 4, ..., 4, 4],
        [4, 4, ..., 4, 4],
        ...,
        [4, 4, ..., 4, 4],
        [4, 4, ..., 4, 4]],

       [[4, 4, ..., 4, 4],
        [4, 4, ..., 4, 4],
        ...,
        [4, 4, ..., 4, 4],
        [4, 4, ..., 4, 4]],

       ...,

       [[4, 4, ..., 4, 4],
        [4, 4, ..., 4, 4],
        ...,
        [4, 4, ..., 4, 4],
        [4, 4, ..., 4, 4]],

       [[4, 4, ..., 4, 4],
        [4, 4, ..., 4, 4],
        ...,
        [4, 4, ..., 4, 4],
        [4, 4, ..., 4, 4]]], shape=(10, 256, 256), dtype=uint16)
        LayerDataProtocol = <class 'napari.layers._data_protocols.LayerDataProtocol'>
        self.rgb = False    397         typing.cast(LayerDataProtocol, input_data), rgb=self.rgb
    398     )
    400 super()._update_slice_response(response)
    402 # Maybe reset the contrast limits based on the new slice.

File ~\Documents\GitHub\napari\src\napari\layers\image\image.py:615, in Image.contrast_limits(self=<Image layer 'brain'>, contrast_limits=(0.0, 51076.0))
    613 @IntensityVisualizationMixin.contrast_limits.setter  # type: ignore [attr-defined]
    614 def contrast_limits(self, contrast_limits):
--> 615     IntensityVisualizationMixin.contrast_limits.fset(self, contrast_limits)
        self = <Image layer 'brain' at 0x1c247bcaa80>
        contrast_limits = (0.0, 51076.0)    616     if not np.allclose(
    617         _coerce_contrast_limits(self.contrast_limits).contrast_limits,
    618         self.contrast_limits,
    619     ):
    620         prev = self._keep_auto_contrast

File ~\Documents\GitHub\napari\src\napari\layers\intensity_mixin.py:112, in IntensityVisualizationMixin.contrast_limits(self=<Image layer 'brain'>, contrast_limits=(0.0, 51076.0))
    110 newrange[1] = max(newrange[1], contrast_limits[1])
    111 self.contrast_limits_range = newrange
--> 112 self._update_thumbnail()
        self = <Image layer 'brain' at 0x1c247bcaa80>    113 self.events.contrast_limits()

File ~\Documents\GitHub\napari\src\napari\layers\image\image.py:545, in Image._update_thumbnail(self=<Image layer 'brain'>)
    543         colormapped = np.concatenate([downsampled, alpha], axis=2)
    544 else:
--> 545     downsampled = ndi.zoom(
        ndi = <module 'scipy.ndimage' from 'C:\\Users\\timmo\\Documents\\GitHub\\napari\\.venv\\Lib\\site-packages\\scipy\\ndimage\\__init__.py'>
        image = array([ 49, 121, ...,  36,  16], shape=(256,), dtype=uint16)
        zoom_factor = (np.float64(0.125), np.float64(0.125))    546         image, zoom_factor, prefilter=False, order=0  
    547     )
    548     low, high = self.contrast_limits
    549     if np.issubdtype(downsampled.dtype, np.integer):

File ~\Documents\GitHub\napari\.venv\Lib\site-packages\scipy\ndimage\_interpolation.py:815, in zoom(input=array([ 49, 121, ...,  36,  16], shape=(256,), dtype=uint16), zoom=(np.float64(0.125), np.float64(0.125)), output=None, order=0, mode='constant', cval=0.0, prefilter=False, grid_mode=False)
    813 if input.ndim < 1:
    814     raise RuntimeError('input and output rank must be > 0')
--> 815 zoom = _ni_support._normalize_sequence(zoom, input.ndim)
        input = array([ 49, 121, ...,  36,  16], shape=(256,), dtype=uint16)
        zoom = (np.float64(0.125), np.float64(0.125))
        _ni_support = <module 'scipy.ndimage._ni_support' from 'C:\\Users\\timmo\\Documents\\GitHub\\napari\\.venv\\Lib\\site-packages\\scipy\\ndimage\\_ni_support.py'>    816 output_shape = tuple(
    817         [int(round(ii * jj)) for ii, jj in zip(input.shape, zoom)])
    818 complex_output = np.iscomplexobj(input)

File ~\Documents\GitHub\napari\.venv\Lib\site-packages\scipy\ndimage\_ni_support.py:72, in _normalize_sequence(input=(np.float64(0.125), np.float64(0.125)), rank=1)
     70     if len(normalized) != rank:
     71         err = "sequence argument must have length equal to input rank"
---> 72         raise RuntimeError(err)
        err = 'sequence argument must have length equal to input rank'     73 else:
     74     normalized = [input] * rank

RuntimeError: sequence argument must have length equal to input rank
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
File ~\Documents\GitHub\napari\src\napari\_qt\threads\status_checker.py:126, in StatusChecker.calculate_status(self=<napari._qt.threads.status_checker.StatusChecker object>)
    122     return
    124 try:
    125     # Calculate the status change from cursor's movement
--> 126     res = viewer._calc_status_from_cursor()
        viewer = Viewer(camera=Camera(center=(0.0, np.float64(132.8894736842105), np.float64(103.69649122807014)), zoom=np.float64(2.2265625), angles=(0.0, 0.0, 90.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(<DepthAxisOrientation.TOWARDS: 'towards'>, <VerticalAxisOrientation.DOWN: 'down'>, <HorizontalAxisOrientation.RIGHT: 'right'>)), cursor=Cursor(position=(np.float64(5.5826706546344075e-15), np.float64(224.06140437510487), np.float64(80.79122650987819)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[<Image layer 'brain' at 0x1c247bcaa80>], help='use <2> for transform', status='Ready', tooltip=Tooltip(visible=True, text=''), theme='dark', title='napari', mouse_over_canvas=True, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[<function double_click_to_zoom at 0x000001C230773920>], mouse_wheel_callbacks=[<function dims_scroll at 0x000001C230773880>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})    127 except Exception as e:  # pragma: no cover # noqa: BLE001
    128     # Our codebase is not threadsafe. It is possible that an
    129     # ViewerModel or Layer state is changed while we are trying to
   (...)    132     # from crashing the thread. The exception is logged
    133     # and a notification is sent.
    134     notification_manager.dispatch(Notification.from_exception(e))

File ~\Documents\GitHub\napari\src\napari\components\viewer_model.py:722, in ViewerModel._calc_status_from_cursor(self=Viewer(camera=Camera(center=(0.0, np.float64(132...use_drag_gen={}, _mouse_wheel_gen={}, _keymap={}))
    719 # If there is an active layer and a single selection, calculate status using "the classic way".
    720 # Then return the status and the tooltip.
    721 if active is not None and active._loaded and len(selection) < 2:
--> 722     status = active.get_status(
        active = <Image layer 'brain' at 0x1c247bcaa80>
        self = Viewer(camera=Camera(center=(0.0, np.float64(132.8894736842105), np.float64(103.69649122807014)), zoom=np.float64(2.2265625), angles=(0.0, 0.0, 90.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(<DepthAxisOrientation.TOWARDS: 'towards'>, <VerticalAxisOrientation.DOWN: 'down'>, <HorizontalAxisOrientation.RIGHT: 'right'>)), cursor=Cursor(position=(np.float64(5.5826706546344075e-15), np.float64(224.06140437510487), np.float64(80.79122650987819)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[<Image layer 'brain' at 0x1c247bcaa80>], help='use <2> for transform', status='Ready', tooltip=Tooltip(visible=True, text=''), theme='dark', title='napari', mouse_over_canvas=True, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[<function double_click_to_zoom at 0x000001C230773920>], mouse_wheel_callbacks=[<function dims_scroll at 0x000001C230773880>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})   
        self.cursor.position = (np.float64(5.5826706546344075e-15), np.float64(224.06140437510487), np.float64(80.79122650987819))
        self.cursor = Cursor(position=(np.float64(5.5826706546344075e-15), np.float64(224.06140437510487), np.float64(80.79122650987819)), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0)
        self.cursor._view_direction = array([-1.00000e+00,  1.06156e-14, -3.72772e-15])
        self.dims = Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('0', '1', '2'), rollable=(True, True, True), range=(RangeTuple(start=np.float64(0.0), stop=np.float64(9.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0)), RangeTuple(start=np.float64(0.0), stop=np.float64(255.0), step=np.float64(1.0))), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(np.float64(3.0), np.float64(127.0), np.float64(127.0)), last_used=0)    723         self.cursor.position,
    724         view_direction=self.cursor._view_direction,
    725         dims_displayed=list(self.dims.displayed),
    726         world=True,
    727     )
    728     return status, tooltip_text
    730 # Otherwise, return the layer status of multiple selected layers
    731 # or gridded layers as well as the tooltip.

File ~\Documents\GitHub\napari\src\napari\layers\base\base.py:2167, in Layer.get_status(self=<Image layer 'brain'>, position=array([5.58267e-15, 2.24061e+02, 8.07912e+01]), view_direction=array([-1.00000e+00,  1.06156e-14, -3.72772e-15]), dims_displayed=[0, 1, 2], world=True, value=None)
   2165 if position is not None:
   2166     position = np.asarray(position)
-> 2167     value = self.get_value(
        value = None
        self = <Image layer 'brain' at 0x1c247bcaa80>
        position = array([5.58267e-15, 2.24061e+02, 8.07912e+01])
        view_direction = array([-1.00000e+00,  1.06156e-14, -3.72772e-15])
        dims_displayed = [0, 1, 2]
        world = True   2168         position,
   2169         view_direction=view_direction,
   2170         dims_displayed=dims_displayed,
   2171         world=world,
   2172     )
   2173     coords_str, value_str = generate_layer_status_strings(
   2174         position[-self.ndim :],
   2175         value,
   2176     )
   2177 else:

File ~\Documents\GitHub\napari\src\napari\layers\base\base.py:1384, in Layer.get_value(self=<Image layer 'brain'>, position=array([5.58267e-15, 2.24061e+02, 8.07912e+01]), view_direction=array([-1.00000e+00,  1.06156e-14, -3.72772e-15]), dims_displayed=[np.int64(0), np.int64(1), np.int64(2)], world=True)
   1377         view_direction = self._world_to_data_ray(view_direction)
   1378         start_point, end_point = self.get_ray_intersections(
   1379             position=position,
   1380             view_direction=view_direction,
   1381             dims_displayed=dims_displayed,
   1382             world=False,
   1383         )
-> 1384         value = self._get_value_3d(
        self = <Image layer 'brain' at 0x1c247bcaa80>
        start_point = array([ 10.     , 224.5614 ,  81.29123])
        end_point = array([  0.     , 224.5614 ,  81.29123])
        dims_displayed = [np.int64(0), np.int64(1), np.int64(2)]   1385             start_point=start_point,
   1386             end_point=end_point,
   1387             dims_displayed=dims_displayed,
   1388         )
   1389 else:
   1390     value = self._get_value(position)

File ~\Documents\GitHub\napari\src\napari\layers\_scalar_field\scalar_field.py:697, in ScalarFieldBase._get_value_3d(self=<Image layer 'brain'>, start_point=array([ 10.     , 224.5614 ,  81.29123]), end_point=array([  0.     , 224.5614 ,  81.29123]), dims_displayed=[np.int64(0), np.int64(1), np.int64(2)])
    673 def _get_value_3d(
    674     self,
    675     start_point: np.ndarray | None,
    676     end_point: np.ndarray | None,
    677     dims_displayed: list[int],
    678 ) -> int | None | tuple[int, int | None]:
    679     """Get the first non-background value encountered along a ray.
    680
    681     Parameters
   (...)    695         If multiscale is True, returns a tuple of (data_level, value).
    696     """
--> 697     value = self._get_value_ray(
        self = <Image layer 'brain' at 0x1c247bcaa80>
        start_point = array([ 10.     , 224.5614 ,  81.29123])
        end_point = array([  0.     , 224.5614 ,  81.29123])
        dims_displayed = [np.int64(0), np.int64(1), np.int64(2)]    698         start_point=start_point,
    699         end_point=end_point,
    700         dims_displayed=dims_displayed,
    701     )
    703     if self.multiscale and value is not None:
    704         return self.data_level, value

File ~\Documents\GitHub\napari\src\napari\layers\_scalar_field\scalar_field.py:664, in ScalarFieldBase._get_value_ray(self=<Image layer 'brain'>, start_point=array([ 10.     , 224.5614 ,  81.29123]), end_point=array([  0.     , 224.5614 ,  81.29123]), dims_displayed=[np.int64(0), np.int64(1), np.int64(2)])
    658     bounding_box[:, 1] += 1
    660     clamped = clamp_point_to_bounding_box(
    661         sample_points,
    662         bounding_box,
    663     ).astype(int)
--> 664     values = im_slice[tuple(clamped.T)]
        im_slice = array([[4, 4, ..., 4, 4],
       [4, 4, ..., 4, 4],
       ...,
       [4, 4, ..., 4, 4],
       [4, 4, ..., 4, 4]], shape=(256, 256), dtype=uint16)
        clamped = array([[  9, 224,  81],
       [  9, 224,  81],
       ...,
       [  0, 224,  81],
       [  0, 224,  81]], shape=(20, 3))    665     return self._calculate_value_from_ray(values)
    667 return None

IndexError: too many indices for array: array is 2-dimensional, but 3 were indexed

TimMonko avatar Jun 30 '25 21:06 TimMonko

Interestingly, everything works fine if the layer is 4D.

Edit: in fact, I can't reproduce this anymore, so it seems like it's been fixed?

Edit2: I checked back to 0.5.6 and it seems fixed there too? But Tim ran into this in June of this year?

Edit3: because it involves slicing I checked and this bug occurs only with NAPARI_ASYNC=0 and I mostly by default have async on.

psobolewskiPhD avatar Oct 11 '25 15:10 psobolewskiPhD