Closed odinsbane closed 1 day ago
I forgot the traceback.
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
File ~/linux-desktop/napari/napari-venv/lib/python3.10/site-packages/vispy/app/backends/_qt.py:928, in CanvasBackendDesktop.paintGL(self=<vispy.app.backends._qt.CanvasBackendDesktop object>)
926 # (0, 0, self.width(), self.height()))
927 self._vispy_canvas.set_current()
--> 928 self._vispy_canvas.events.draw(region=None)
self._vispy_canvas = <NapariSceneCanvas (PyQt5) at 0x7f9be9bf0d60>
self._vispy_canvas.events.draw = <vispy.util.event.EventEmitter object at 0x7f9be9bf2800>
self = <vispy.app.backends._qt.CanvasBackendDesktop object at 0x7f9be9bdfc70>
self._vispy_canvas.events = <vispy.util.event.EmitterGroup object at 0x7f9be9bf2740>
930 # Clear the alpha channel with QOpenGLWidget (Qt >= 5.4), otherwise the
931 # window is translucent behind non-opaque objects.
932 # Reference: MRtrix3/mrtrix3#266
933 if QT5_NEW_API or PYSIDE6_API or PYQT6_API:
File ~/linux-desktop/napari/napari-venv/lib/python3.10/site-packages/vispy/util/event.py:453, in EventEmitter.__call__(self=<vispy.util.event.EventEmitter object>, *args=(), **kwargs={'region': None})
450 if self._emitting > 1:
451 raise RuntimeError('EventEmitter loop detected!')
--> 453 self._invoke_callback(cb, event)
event = <DrawEvent blocked=False handled=False native=None region=None source=None sources=[] type=draw>
self = <vispy.util.event.EventEmitter object at 0x7f9be9bf2800>
cb = <bound method VispyCamera.on_draw of <napari._vispy.camera.VispyCamera object at 0x7f9be9bf0d00>>
454 if event.blocked:
455 break
File ~/linux-desktop/napari/napari-venv/lib/python3.10/site-packages/vispy/util/event.py:471, in EventEmitter._invoke_callback(self=<vispy.util.event.EventEmitter object>, cb=<bound method VispyCamera.on_draw of <napari._vispy.camera.VispyCamera object>>, event=<DrawEvent blocked=False handled=False native=None region=None source=None sources=[] type=draw>)
469 cb(event)
470 except Exception:
--> 471 _handle_exception(self.ignore_callback_errors,
self = <vispy.util.event.EventEmitter object at 0x7f9be9bf2800>
cb = <bound method VispyCamera.on_draw of <napari._vispy.camera.VispyCamera object at 0x7f9be9bf0d00>>
event = <DrawEvent blocked=False handled=False native=None region=None source=None sources=[] type=draw>
(cb, event) = (<bound method VispyCamera.on_draw of <napari._vispy.camera.VispyCamera object at 0x7f9be9bf0d00>>, <DrawEvent blocked=False handled=False native=None region=None source=None sources=[] type=draw>)
472 self.print_callback_errors,
473 self, cb_event=(cb, event))
File ~/linux-desktop/napari/napari-venv/lib/python3.10/site-packages/vispy/util/event.py:469, in EventEmitter._invoke_callback(self=<vispy.util.event.EventEmitter object>, cb=<bound method VispyCamera.on_draw of <napari._vispy.camera.VispyCamera object>>, event=<DrawEvent blocked=False handled=False native=None region=None source=None sources=[] type=draw>)
467 def _invoke_callback(self, cb, event):
468 try:
--> 469 cb(event)
cb = <bound method VispyCamera.on_draw of <napari._vispy.camera.VispyCamera object at 0x7f9be9bf0d00>>
event = <DrawEvent blocked=False handled=False native=None region=None source=None sources=[] type=draw>
470 except Exception:
471 _handle_exception(self.ignore_callback_errors,
472 self.print_callback_errors,
473 self, cb_event=(cb, event))
File ~/linux-desktop/napari/napari-repo/napari/_vispy/camera.py:188, in VispyCamera.on_draw(self=<napari._vispy.camera.VispyCamera object>, _event=<DrawEvent blocked=False handled=False native=None region=None source=None sources=[] type=draw>)
183 """Called whenever the canvas is drawn.
184
185 Update camera model angles, center, and zoom.
186 """
187 with self._camera.events.angles.blocker(self._on_angles_change):
--> 188 self._camera.angles = self.angles
self._camera.angles = (0.4350144751843147, 2.893990661923638, 86.80650786529637)
self._camera = Camera(center=(5.0, 10.0, 0.0), zoom=40.232499999999995, angles=(0.4350144751843147, 2.893990661923638, 86.80650786529637), perspective=0.0, mouse_pan=True, mouse_zoom=True)
self = <napari._vispy.camera.VispyCamera object at 0x7f9be9bf0d00>
189 with self._camera.events.center.blocker(self._on_center_change):
190 self._camera.center = self.center
File ~/linux-desktop/napari/napari-repo/napari/utils/events/evented_model.py:307, in EventedModel.__setattr__(self=Camera(center=(5.0, 10.0, 0.0), zoom=40.23249999...perspective=0.0, mouse_pan=True, mouse_zoom=True), name='angles', value=(0.14731901486049193, 0.4556950725660273, 89.40443463136077))
305 super().__setattr__(name, value)
306 return
--> 307 with ComparisonDelayer(self):
self = Camera(center=(5.0, 10.0, 0.0), zoom=40.232499999999995, angles=(0.4350144751843147, 2.893990661923638, 86.80650786529637), perspective=0.0, mouse_pan=True, mouse_zoom=True)
308 self._primary_changes.add(name)
309 self._setattr_impl(name, value)
File ~/linux-desktop/napari/napari-repo/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 = Camera(center=(5.0, 10.0, 0.0), zoom=40.232499999999995, angles=(0.4350144751843147, 2.893990661923638, 86.80650786529637), perspective=0.0, mouse_pan=True, mouse_zoom=True)
self = <napari.utils.events.evented_model.ComparisonDelayer object at 0x7f9b5ab7e530>
File ~/linux-desktop/napari/napari-repo/napari/utils/events/evented_model.py:345, in EventedModel._check_if_values_changed_and_emit_if_needed(self=Camera(center=(5.0, 10.0, 0.0), zoom=40.23249999...perspective=0.0, mouse_pan=True, mouse_zoom=True))
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 = 'angles'
self = Camera(center=(5.0, 10.0, 0.0), zoom=40.232499999999995, angles=(0.4350144751843147, 2.893990661923638, 86.80650786529637), perspective=0.0, mouse_pan=True, mouse_zoom=True)
new_value = (0.14731901486049193, 0.4556950725660273, 89.40443463136077)
File ~/linux-desktop/napari/napari-repo/napari/utils/events/event.py:764, in EventEmitter.__call__(self=<napari.utils.events.event.EventEmitter object>, *args=(), **kwargs={'value': (0.14731901486049193, 0.4556950725660273, 89.40443463136077)})
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='angles'>
self = <napari.utils.events.event.EventEmitter object at 0x7f9be269dd20>
cb = <bound method VispySurfaceLayer._on_camera_move of <napari._vispy.layers.surface.VispySurfaceLayer object at 0x7f9b604e0970>>
pass_event = True
765 if event.blocked:
766 break
File ~/linux-desktop/napari/napari-repo/napari/utils/events/event.py:802, in EventEmitter._invoke_callback(self=<napari.utils.events.event.EventEmitter object>, cb=<bound method VispySurfaceLayer._on_camera_move ...._vispy.layers.surface.VispySurfaceLayer object>>, event=<Event blocked=False handled=False native=None source=None sources=[] type='angles'>)
800 self.disconnect(cb)
801 return
--> 802 _handle_exception(
self = <napari.utils.events.event.EventEmitter object at 0x7f9be269dd20>
event = <Event blocked=False handled=False native=None source=None sources=[] type='angles'>
cb = <bound method VispySurfaceLayer._on_camera_move of <napari._vispy.layers.surface.VispySurfaceLayer object at 0x7f9b604e0970>>
(cb, event) = (<bound method VispySurfaceLayer._on_camera_move of <napari._vispy.layers.surface.VispySurfaceLayer object at 0x7f9b604e0970>>, <Event blocked=False handled=False native=None source=None sources=[] type='angles'>)
803 self.ignore_callback_errors,
804 self.print_callback_errors,
805 self,
806 cb_event=(cb, event),
807 )
File ~/linux-desktop/napari/napari-repo/napari/utils/events/event.py:789, in EventEmitter._invoke_callback(self=<napari.utils.events.event.EventEmitter object>, cb=<bound method VispySurfaceLayer._on_camera_move ...._vispy.layers.surface.VispySurfaceLayer object>>, event=<Event blocked=False handled=False native=None source=None sources=[] type='angles'>)
787 try:
788 if event is not None:
--> 789 cb(event)
event = <Event blocked=False handled=False native=None source=None sources=[] type='angles'>
cb = <bound method VispySurfaceLayer._on_camera_move of <napari._vispy.layers.surface.VispySurfaceLayer object at 0x7f9b604e0970>>
790 else:
791 cb()
File ~/linux-desktop/napari/napari-repo/napari/_vispy/layers/surface.py:207, in VispySurfaceLayer._on_camera_move(self=<napari._vispy.layers.surface.VispySurfaceLayer object>, event=<Event blocked=False handled=False native=None source=None sources=[] type='angles'>)
205 # combine to get light behind the camera on the top right
206 self._light_direction = view - up + np.cross(up, view)
--> 207 self.node.shading_filter.light_dir = self._light_direction
self._light_direction = <class 'numpy.ndarray'> (3,) float64
self = <napari._vispy.layers.surface.VispySurfaceLayer object at 0x7f9b604e0970>
self.node.shading_filter = <vispy.visuals.filters.mesh.ShadingFilter object at 0x7f9b5ac13130>
self.node = <SurfaceVisual at 0x7f9b604a3220>
File ~/linux-desktop/napari/napari-venv/lib/python3.10/site-packages/vispy/visuals/filters/mesh.py:460, in ShadingFilter.light_dir(self=<vispy.visuals.filters.mesh.ShadingFilter object>, direction=<class 'numpy.ndarray'> (3,) float64)
458 raise ValueError('Invalid direction %s' % direction)
459 self._light_dir = tuple(direction)
--> 460 self._update_data()
self = <vispy.visuals.filters.mesh.ShadingFilter object at 0x7f9b5ac13130>
File ~/linux-desktop/napari/napari-venv/lib/python3.10/site-packages/vispy/visuals/filters/mesh.py:552, in ShadingFilter._update_data(self=<vispy.visuals.filters.mesh.ShadingFilter object>)
547 self.fshader['flat_shading'] = 1 if self._shading == 'flat' else 0
548 self.fshader['shading_enabled'] = (
549 1 if self._enabled and self._shading is not None else 0
550 )
--> 552 normals = self._visual.mesh_data.get_vertex_normals(indexed='faces')
self = <vispy.visuals.filters.mesh.ShadingFilter object at 0x7f9b5ac13130>
self._visual = <SurfaceVisual at 0x7f9b604a3220>
553 self._normals.set_data(normals, convert=True)
File ~/linux-desktop/napari/napari-venv/lib/python3.10/site-packages/vispy/geometry/meshdata.py:380, in MeshData.get_vertex_normals(self=<vispy.geometry.meshdata.MeshData object>, indexed='faces')
377 raise ValueError("Invalid indexing mode. Accepts: None, 'faces'")
379 if self._vertex_normals is None:
--> 380 face_normals = self.get_face_normals()
self = <vispy.geometry.meshdata.MeshData object at 0x7f9b60406080>
381 faces = self.get_faces()
382 vertices = self.get_vertices()
File ~/linux-desktop/napari/napari-venv/lib/python3.10/site-packages/vispy/geometry/meshdata.py:351, in MeshData.get_face_normals(self=<vispy.geometry.meshdata.MeshData object>, indexed=None)
349 if self._face_normals is None:
350 vertices = self.get_vertices(indexed='faces')
--> 351 self._face_normals = _compute_face_normals(vertices)
self._face_normals = None
vertices = None
self = <vispy.geometry.meshdata.MeshData object at 0x7f9b60406080>
353 if indexed == 'faces' and self._face_normals_indexed_by_faces is None:
354 self._face_normals_indexed_by_faces = \
355 _repeat_face_normals_on_corners(self._face_normals)
File ~/linux-desktop/napari/napari-venv/lib/python3.10/site-packages/vispy/geometry/meshdata.py:23, in _compute_face_normals(vertices=None)
22 def _compute_face_normals(vertices):
---> 23 if vertices.shape[1:] != (3, 3):
vertices = None
24 raise ValueError("Expected (N, 3, 3) array of vertices repeated on"
25 f" the triangle corners, got {vertices.shape}.")
26 edges1 = vertices[:, 1] - vertices[:, 0]
AttributeError: 'NoneType' object has no attribute 'shape'
Fixed by #6874
🐛 Bug Report
This is related to the previous bug I submitted https://github.com/napari/napari/issues/6870 and can be demonstrated from that example.
💡 Steps to Reproduce
Run the example in the other bug: https://github.com/napari/napari/issues/6870 select time frame 1 then select another time frame where the second mesh doesn't exist. Rotate the mesh, and the error will occur.
💡 Expected Behavior
I expect no errors, and only one mesh gets shown.
🌎 Environment
WSL2 Ubuntu using Windows 10 on the napari main branch.
💡 Additional Context
The issue appears to happen due in napari/_vispy/layers/surface.py once the mesh gets shown the first time, it has a shading_filter, then when view rotates, it tries to calculate a normal for a mesh without any vertexes. I changed line 207 to
And the problem goes away.