brainglobe / brainglobe/brainrender-napari
[BUG] In 3d mode atlas loading is broken
- Dominant language
- Python
- Stars
- 24
- Forks
- 22
- Avg merge
- 15h 3m
- Merged PRs (30d)
- 1
Description
**Describe the bug**
in napari, if you switch to 3d mode atlas loading does not work. it errors if you select an atlas. This then totally breaks the plugin and prevents you from loading any atlases even if you switch back to 2D mode.
**To Reproduce**
https://github.com/user-attachments/assets/8b00118e-728e-49ce-b43e-5e65eda053f5
**Log file**
```python
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
File ~\anaconda3\envs\niu-bg\Lib\site-packages\brainrender_napari\brainrender_viewer_widget.py:149, in BrainrenderViewerWidget._on_add_atlas_requested(self=, atlas_name='allen_mouse_25um')
145 selected_atlas = BrainGlobeAtlas(atlas_name=atlas_name)
146 selected_atlas_representation = NapariAtlasRepresentation(
147 bg_atlas=selected_atlas, viewer=self._viewer
148 )
--> 149 selected_atlas_representation.add_to_viewer()
selected_atlas_representation = NapariAtlasRepresentation(bg_atlas=allen mouse atlas (res. 25um), viewer=Viewer(mouse_move_callbacks=[], mouse_wheel_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[], camera=Camera(center=(263.5, 159.5, 227.5), zoom=1.0604166666666666, angles=(0.0, 0.0, 0.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(, , )), cursor=Cursor(position=(0.0, 0.0, 0.0), viewbox=(0, 0), scaled=True, size=1.0, style=), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('-3', '-2', '-1'), rollable=(True, True, True), range=(RangeTuple(start=0.0, stop=527.0, step=1.0), RangeTuple(start=0.0, stop=319.0, step=1.0), RangeTuple(start=0.0, stop=455.0, step=1.0)), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(263.0, 159.0, 227.0), units=(, , ), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[], help='', status='', tooltip=Tooltip(visible=True, text=''), theme='dark', title='napari', mouse_over_canvas=False), mesh_opacity=0.4, mesh_blending='translucent_no_depth')
File ~\anaconda3\envs\niu-bg\Lib\site-packages\brainrender_napari\napari_atlas_representation.py:42, in NapariAtlasRepresentation.add_to_viewer(self=NapariAtlasRepresentation(bg_atlas=allen mouse a...pacity=0.4, mesh_blending='translucent_no_depth'))
36 def add_to_viewer(self) -> None:
37 """Adds the reference and annotation images as layers to the viewer.
38
39 The layers are connected to the mouse move callback to set tooltip.
40 The reference image's visibility is off, the annotation's is on.
41 """
---> 42 reference = self.viewer.add_image(
self.viewer = Viewer(mouse_move_callbacks=[], mouse_wheel_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[], camera=Camera(center=(263.5, 159.5, 227.5), zoom=1.0604166666666666, angles=(0.0, 0.0, 0.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(, , )), cursor=Cursor(position=(0.0, 0.0, 0.0), viewbox=(0, 0), scaled=True, size=1.0, style=), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('-3', '-2', '-1'), rollable=(True, True, True), range=(RangeTuple(start=0.0, stop=527.0, step=1.0), RangeTuple(start=0.0, stop=319.0, step=1.0), RangeTuple(start=0.0, stop=455.0, step=1.0)), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(263.0, 159.0, 227.0), units=(, , ), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[], help='', status='', tooltip=Tooltip(visible=True, text=''), theme='dark', title='napari', mouse_over_canvas=False)
self = NapariAtlasRepresentation(bg_atlas=allen mouse atlas (res. 25um), viewer=Viewer(mouse_move_callbacks=[], mouse_wheel_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[], camera=Camera(center=(263.5, 159.5, 227.5), zoom=1.0604166666666666, angles=(0.0, 0.0, 0.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(, , )), cursor=Cursor(position=(0.0, 0.0, 0.0), viewbox=(0, 0), scaled=True, size=1.0, style=), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('-3', '-2', '-1'), rollable=(True, True, True), range=(RangeTuple(start=0.0, stop=527.0, step=1.0), RangeTuple(start=0.0, stop=319.0, step=1.0), RangeTuple(start=0.0, stop=455.0, step=1.0)), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(263.0, 159.0, 227.0), units=(, , ), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[], help='', status='', tooltip=Tooltip(visible=True, text=''), theme='dark', title='napari', mouse_over_canvas=False), mesh_opacity=0.4, mesh_blending='translucent_no_depth')
self.bg_atlas = allen mouse atlas (res. 25um)
self.bg_atlas.atlas_name = 'allen_mouse_25um' 43 self.bg_atlas.reference,
44 name=f"{self.bg_atlas.atlas_name}_reference",
45 visible=False,
46 )
48 annotation = self.viewer.add_labels(
49 self.bg_atlas.annotation,
50 name=f"{self.bg_atlas.atlas_name}_annotation",
51 )
53 annotation.mouse_move_callbacks.append(self._on_mouse_move)
File ~\anaconda3\envs\niu-bg\Lib\site-packages\napari\components\viewer_model.py:1245, in ViewerModel.add_image(self=Viewer(mouse_move_callbacks=[], mouse_wheel_call...='dark', title='napari', mouse_over_canvas=False), data=array([[[0, 0, ..., 0, 0],
[0, 0, ..., 0....., 0, 0]]], shape=(528, 320, 456), dtype=uint16), channel_axis=None, affine=None, axis_labels=None, attenuation=0.05, blending=None, cache=True, colormap=None, contrast_limits=None, custom_interpolation_kernel_2d=None, depiction='volume', experimental_clipping_planes=None, gamma=1.0, interpolation2d='nearest', interpolation3d='linear', iso_threshold=None, metadata=None, multiscale=None, name='allen_mouse_25um_reference', opacity=1.0, plane=None, projection_mode='mean', rendering='mip', rgb=None, rotate=None, scale=None, shear=None, translate=None, units=None, visible=False)
1237 raise TypeError(
1238 trans._(
1239 "Received sequence for argument '{argument}', did you mean to specify a 'channel_axis'? ",
(...) 1242 )
1243 )
1244 layer = Image(data, **kwargs)
-> 1245 self.layers.append(layer)
layer =
self.layers = []
self = Viewer(mouse_move_callbacks=[], mouse_wheel_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[], camera=Camera(center=(263.5, 159.5, 227.5), zoom=1.0604166666666666, angles=(0.0, 0.0, 0.0), perspective=0.0, mouse_pan=True, mouse_zoom=True, orientation=(, , )), cursor=Cursor(position=(0.0, 0.0, 0.0), viewbox=(0, 0), scaled=True, size=1.0, style=), dims=Dims(ndim=3, ndisplay=3, order=(0, 1, 2), axis_labels=('-3', '-2', '-1'), rollable=(True, True, True), range=(RangeTuple(start=0.0, stop=527.0, step=1.0), RangeTuple(start=0.0, stop=319.0, step=1.0), RangeTuple(start=0.0, stop=455.0, step=1.0)), margin_left=(0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0), point=(263.0, 159.0, 227.0), units=(, , ), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False, spacing=0.0), layers=[], help='', status='', tooltip=Tooltip(visible=True, text=''), theme='dark', title='napari', mouse_over_canvas=False) 1247 return layer
1249 layerdata_list = split_channels(data, channel_axis, **kwargs)
File :1130, in MutableSequence.append(self=[], value=
)
1128 'Could not get source, probably due dynamically evaluated source code.'
File ~\anaconda3\envs\niu-bg\Lib\site-packages\napari\components\layerlist.py:271, in LayerList.insert(self=[], index=0, value=
)
267 new_layer.events._extent_augmented.connect(self._clean_cache)
268 new_layer.events.data.connect(
269 self._trigger_check_ndim_and_maybe_clean_units
270 )
--> 271 super().insert(index, new_layer)
new_layer =
index = 0 272 self._check_ndim_and_maybe_clean_units(new_layer.ndim)
File ~\anaconda3\envs\niu-bg\Lib\site-packages\napari\utils\events\containers\_selectable_list.py:68, in SelectableEventedList.insert(self=[], index=0, value=
)
67 def insert(self, index: int, value: _T) -> None:
---> 68 super().insert(index, value)
index = 0
value = 69 if self._activate_on_insert:
70 # Make layer selected and unselect all others
71 self.selection.active = value
File ~\anaconda3\envs\niu-bg\Lib\site-packages\napari\utils\events\containers\_evented_list.py:197, in EventedList.insert(self=[], index=0, value=
)
195 self.events.inserting(index=index)
196 super().insert(index, value)
--> 197 self.events.inserted(index=index, value=value)
index = 0
value =
self.events.inserted =
self.events =
self = [] 198 self._connect_child_emitters(value)
File ~\anaconda3\envs\niu-bg\Lib\site-packages\napari\utils\events\event.py:752, in EventEmitter.__call__(self=, *args=(), **kwargs={'index': 0, 'value': })
749 self._block_counter.update([cb])
750 continue
--> 752 self._invoke_callback(cb, event if pass_event else None)
event =
self =
cb = >
pass_event = True 753 if event.blocked:
754 break
File ~\anaconda3\envs\niu-bg\Lib\site-packages\napari\utils\events\event.py:790, in EventEmitter._invoke_callback(self=, cb=>, event=)
788 self.disconnect(cb)
789 return
--> 790 _handle_exception(
self =
event =
cb = >
(cb, event) = (>, ) 791 self.ignore_callback_errors,
792 self.print_callback_errors,
793 self,
794 cb_event=(cb, event),
795 )
File ~\anaconda3\envs\niu-bg\Lib\site-packages\napari\utils\events\event.py:777, in EventEmitter._invoke_callback(self=, cb=>, event=)
775 try:
776 if event is not None:
--> 777 cb(event)
event =
cb = > 778 else:
779 cb()
File ~\anaconda3\envs\niu-bg\Lib\site-packages\napari\_qt\qt_viewer.py:647, in QtViewer._on_add_layer_change(self=, event=)
639 """When a layer is added, set its parent and order.
640
641 Parameters
(...) 644 The napari event that triggered this method.
645 """
646 layer = event.value
--> 647 self._add_layer(layer)
layer =
self =
File ~\anaconda3\envs\niu-bg\Lib\site-packages\napari\_qt\qt_viewer.py:693, in QtViewer._add_layer(self=, layer=)
685 def _add_layer(self, layer):
686 """When a layer is added, set its parent and order.
687
688 Parameters
(...) 691 Layer to be added.
692 """
--> 693 vispy_layer = create_vispy_layer(layer)
layer = 695 # QtPoll is experimental.
696 if self._qt_poll is not None:
697 # QtPoll will call VipyBaseImage._on_poll() when the camera
698 # moves or the timer goes off.
File ~\anaconda3\envs\niu-bg\Lib\site-packages\napari\_vispy\utils\visual.py:108, in create_vispy_layer(layer=, *args=(), **kwargs={})
106 for cls in layer.__class__.mro():
107 if cls in layer_to_visual:
--> 108 return layer_to_visual[cls](layer, *args, **kwargs)
cls =
layer_to_visual = {: , : , : , : , : , : , : }
layer =
args = ()
kwargs = {} 110 raise TypeError(
111 trans._(
112 'Could not find VispyLayer for layer of type {dtype}',
(...) 115 )
116 )
File ~\anaconda3\envs\niu-bg\Lib\site-packages\napari\_vispy\layers\image.py:136, in VispyImageLayer.__init__(self=, layer=, node=None, texture_format='auto', layer_node_class=)
126 def __init__(
127 self,
128 layer: Image,
(...) 132 ) -> None:
133 # Track order to detect transpose/roll. Needs to be set before super().__init__()
134 self._last_order = None
--> 136 super().__init__(
layer =
node = None
texture_format = 'auto'
layer_node_class = 137 layer,
138 node=node,
139 texture_format=texture_format,
140 layer_node_class=layer_node_class,
141 )
143 self.layer.events.interpolation2d.connect(
144 self._on_interpolation_change
145 )
146 self.layer.events.interpolation3d.connect(
147 self._on_interpolation_change
148 )
File ~\anaconda3\envs\niu-bg\Lib\site-packages\napari\_vispy\layers\scalar_field.py:76, in VispyScalarFieldBaseLayer.__init__(self=, layer=, node=None, texture_format='auto', layer_node_class=)
74 self._on_display_change()
75 self.reset()
---> 76 self._on_data_change()
self =
File ~\anaconda3\envs\niu-bg\Lib\site-packages\napari\_vispy\layers\scalar_field.py:143, in VispyScalarFieldBaseLayer._on_data_change(self=)
141 self._on_display_change(data)
142 else:
--> 143 node.set_data(data)
data = array([[0]], dtype=uint16)
node = 144 node.visible = not self.layer._slice.empty and self.layer.visible
146 # Call to update order of translation values with new dims:
File ~\anaconda3\envs\niu-bg\Lib\site-packages\vispy\visuals\volume.py:852, in VolumeVisual.set_data(self=, vol=array([[0]], dtype=uint16), clim=None, copy=True)
850 raise ValueError('Volume visual needs a numpy array.')
851 if not ((vol.ndim == 3) or (vol.ndim == 4 and vol.shape[-1] > 1)):
--> 852 raise ValueError('Volume visual needs a 3D array.')
853 if isinstance(self._texture, GPUScaledTextured3D):
854 copy = False
ValueError: Volume visual needs a 3D array.
---------------------------------------------------------------------------
```
**Computer used (please complete the following information):**
- OS:Windows
Contributor guide
Research direction
Start in brainrender_viewer_widget.py at _on_add_atlas_requested and follow the call into napari_atlas_representation.py at add_to_viewer, where the traceback shows the failure during viewer.add_image. Reproduce atlas loading after switching to 3D, then verify that the atlas loads successfully in 3D and remains usable after returning to 2D.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- computer-graphics
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100