Display 3D skeletons in napari#
There are two ways to display 3D skeletons in napari. First, we demonstrate how to use the napari Shapes layer to draw Paths for each skeleton path. As of napari 0.4.14, however, 3D interactivity in the Shapes layer is not ideal, so we also demonstrate how to use the Labels layer.
Using the Shapes layer#
The napari Shapes layer allows displaying of 2D and 3D paths, and coloring them by tabular properties, which makes it ideal for displaying skeletons, and the measurements provided by skan.
import napari
import numpy as np
import skan
from skimage.data import binary_blobs
from skimage.morphology import skeletonize
import scipy.ndimage as ndi
Note
We use synthetic data here. If you have a cool 3D skeleton dataset that you’d like to show off in these docs, let us know!
blobs = binary_blobs(64, volume_fraction=0.3, n_dim=3)
binary_skeleton = skeletonize(blobs)
skeleton = skan.Skeleton(binary_skeleton)
all_paths = [
skeleton.path_coordinates(i)
for i in range(skeleton.n_paths)
]
paths_table = skan.summarize(skeleton)
paths_table['path-id'] = np.arange(skeleton.n_paths)
First, we color by random path ID, showing each path in a distinct color using the matplotlib “tab10” qualitative palette. (Coloring by path ID directly results in “bands” of nearby paths receiving the same color.)
paths_table['random-path-id'] = np.random.default_rng().permutation(skeleton.n_paths)
viewer = napari.Viewer(ndisplay=3)
skeleton_layer = viewer.add_shapes(
all_paths,
shape_type='path',
properties=paths_table,
edge_width=0.5,
edge_color='random-path-id',
edge_colormap='tab10',
)
WARNING: QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-runner'
We can also demonstrate that most of these branches are in one skeleton, with a few stragglers around the edges, by coloring by skeleton ID:
skeleton_layer.edge_color = 'skeleton-id'
# for now, we need to set the face color as well
skeleton_layer.face_color = 'skeleton-id'
Finally, we can color the paths by a numerical property, such as their length.
skeleton_layer.edge_color = 'branch-distance'
skeleton_layer.edge_colormap = 'viridis'
# for now, we need to set the face color as well
skeleton_layer.face_color = 'branch-distance'
skeleton_layer.face_colormap = 'viridis'
Using the Labels layer#
We can also visualize the pixels of the skeleton as a Labels layer, with each path ID appearing as a different label. The downside with this approach is that junction pixels are arbitrarily assigned to one of the branches incident on that junction. Therefore, removing that branch would cause the junction pixel to be removed, which could incorrectly disconnect the skeleton at that point.
However, the rich 3D interactivity of the labels layer does allow prunning of branches in 3D, which could be extremely useful for manual curation of the skeleton, as long as propert care is taken in downstream processing of the edits.
labels = np.asarray(skeleton)
viewer2 = napari.view_labels(
labels,
properties=paths_table,
opacity=1,
ndisplay=3,
)
WARNING: Error drawing visual <Volume at 0x7fca20d29f40>
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/app/backends/_qt.py:903, in CanvasBackendDesktop.paintGL(self)
901 # (0, 0, self.width(), self.height()))
902 self._vispy_canvas.set_current()
--> 903 self._vispy_canvas.events.draw(region=None)
905 # Clear the alpha channel with QOpenGLWidget (Qt >= 5.4), otherwise the
906 # window is translucent behind non-opaque objects.
907 # Reference: MRtrix3/mrtrix3#266
908 if QT5_NEW_API or PYSIDE6_API or PYQT6_API:
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/util/event.py:453, in EventEmitter.__call__(self, *args, **kwargs)
450 if self._emitting > 1:
451 raise RuntimeError('EventEmitter loop detected!')
--> 453 self._invoke_callback(cb, event)
454 if event.blocked:
455 break
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/util/event.py:471, in EventEmitter._invoke_callback(self, cb, event)
469 cb(event)
470 except Exception:
--> 471 _handle_exception(self.ignore_callback_errors,
472 self.print_callback_errors,
473 self, cb_event=(cb, event))
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/util/event.py:469, in EventEmitter._invoke_callback(self, cb, event)
467 def _invoke_callback(self, cb, event):
468 try:
--> 469 cb(event)
470 except Exception:
471 _handle_exception(self.ignore_callback_errors,
472 self.print_callback_errors,
473 self, cb_event=(cb, event))
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/canvas.py:218, in SceneCanvas.on_draw(self, event)
215 # Now that a draw event is going to be handled, open up the
216 # scheduling of further updates
217 self._update_pending = False
--> 218 self._draw_scene()
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/canvas.py:277, in SceneCanvas._draw_scene(self, bgcolor)
275 bgcolor = self._bgcolor
276 self.context.clear(color=bgcolor, depth=True)
--> 277 self.draw_visual(self.scene)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/canvas.py:315, in SceneCanvas.draw_visual(self, visual, event)
313 else:
314 if hasattr(node, 'draw'):
--> 315 node.draw()
316 prof.mark(str(node))
317 else:
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/visuals.py:103, in VisualNode.draw(self)
101 if self.picking and not self.interactive:
102 return
--> 103 self._visual_superclass.draw(self)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/visuals/visual.py:451, in Visual.draw(self)
449 self._configure_gl_state()
450 try:
--> 451 self._program.draw(self._vshare.draw_mode,
452 self._vshare.index_buffer)
453 except Exception:
454 logger.warning("Error drawing visual %r" % self)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/visuals/shaders/program.py:102, in ModularProgram.draw(self, *args, **kwargs)
100 self.build_if_needed()
101 self.update_variables()
--> 102 Program.draw(self, *args, **kwargs)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/program.py:526, in Program.draw(self, mode, indices, check_error)
522 raise TypeError("Invalid index: %r (must be IndexBuffer)" %
523 indices)
525 # Process GLIR commands
--> 526 canvas.context.flush_commands()
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/context.py:172, in GLContext.flush_commands(self, event)
170 fbo = 0
171 self.shared.parser.parse([('CURRENT', 0, fbo)])
--> 172 self.glir.flush(self.shared.parser)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:582, in GlirQueue.flush(self, parser)
580 def flush(self, parser):
581 """Flush all current commands to the GLIR interpreter."""
--> 582 self._shared.flush(parser)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:504, in _GlirQueueShare.flush(self, parser)
502 show = self._verbose if isinstance(self._verbose, str) else None
503 self.show(show)
--> 504 parser.parse(self._filter(self.clear(), parser))
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:822, in GlirParser.parse(self, commands)
819 self._objects.pop(id_)
821 for command in commands:
--> 822 self._parse(command)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:792, in GlirParser._parse(self, command)
790 ob.set_attribute(*args)
791 elif cmd == 'DATA': # VertexBuffer, IndexBuffer, Texture, Shader
--> 792 ob.set_data(*args)
793 elif cmd == 'SIZE': # VertexBuffer, IndexBuffer,
794 ob.set_size(*args) # Texture[1D, 2D, 3D], RenderBuffer
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:931, in GlirShader.set_data(self, offset, code)
929 errors = gl.glGetShaderInfoLog(self._handle)
930 errormsg = self._get_error(code, errors, 4)
--> 931 raise RuntimeError("Shader compilation error in %s:\n%s" %
932 (self._target, errormsg))
RuntimeError: Shader compilation error in GL_FRAGMENT_SHADER:
on line 201: warning: `view_ray' used uninitialized
vec3 V = normalize(view_ray);
on line 240: warning: `view_ray' used uninitialized
vec3 L = normalize(view_ray); //lightDirs[i];
on line 331: warning: `view_ray' used uninitialized
vec3 V = normalize(view_ray);
on line 371: warning: `view_ray' used uninitialized
vec3 L = normalize(view_ray); //lightDirs[i];
on line 494: error: `surface_point' undeclared
surface_point = iloc * u_shape;
on line 494: error: value of type vec3 cannot be assigned to variable of type error
surface_point = iloc * u_shape;
on line 495: error: `surface_found' undeclared
surface_found = true;
on line 495: error: value of type bool cannot be assigned to variable of type error
surface_found = true;
on line 514: error: `surface_found' undeclared
if (surface_found == false) {
on line 514: error: operands of `==' must have the same type
if (surface_found == false) {
WARNING: Error drawing visual <Volume at 0x7fca20d29f40>
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/app/backends/_qt.py:903, in CanvasBackendDesktop.paintGL(self)
901 # (0, 0, self.width(), self.height()))
902 self._vispy_canvas.set_current()
--> 903 self._vispy_canvas.events.draw(region=None)
905 # Clear the alpha channel with QOpenGLWidget (Qt >= 5.4), otherwise the
906 # window is translucent behind non-opaque objects.
907 # Reference: MRtrix3/mrtrix3#266
908 if QT5_NEW_API or PYSIDE6_API or PYQT6_API:
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/util/event.py:453, in EventEmitter.__call__(self, *args, **kwargs)
450 if self._emitting > 1:
451 raise RuntimeError('EventEmitter loop detected!')
--> 453 self._invoke_callback(cb, event)
454 if event.blocked:
455 break
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/util/event.py:471, in EventEmitter._invoke_callback(self, cb, event)
469 cb(event)
470 except Exception:
--> 471 _handle_exception(self.ignore_callback_errors,
472 self.print_callback_errors,
473 self, cb_event=(cb, event))
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/util/event.py:469, in EventEmitter._invoke_callback(self, cb, event)
467 def _invoke_callback(self, cb, event):
468 try:
--> 469 cb(event)
470 except Exception:
471 _handle_exception(self.ignore_callback_errors,
472 self.print_callback_errors,
473 self, cb_event=(cb, event))
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/canvas.py:218, in SceneCanvas.on_draw(self, event)
215 # Now that a draw event is going to be handled, open up the
216 # scheduling of further updates
217 self._update_pending = False
--> 218 self._draw_scene()
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/canvas.py:277, in SceneCanvas._draw_scene(self, bgcolor)
275 bgcolor = self._bgcolor
276 self.context.clear(color=bgcolor, depth=True)
--> 277 self.draw_visual(self.scene)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/canvas.py:315, in SceneCanvas.draw_visual(self, visual, event)
313 else:
314 if hasattr(node, 'draw'):
--> 315 node.draw()
316 prof.mark(str(node))
317 else:
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/visuals.py:103, in VisualNode.draw(self)
101 if self.picking and not self.interactive:
102 return
--> 103 self._visual_superclass.draw(self)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/visuals/visual.py:451, in Visual.draw(self)
449 self._configure_gl_state()
450 try:
--> 451 self._program.draw(self._vshare.draw_mode,
452 self._vshare.index_buffer)
453 except Exception:
454 logger.warning("Error drawing visual %r" % self)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/visuals/shaders/program.py:102, in ModularProgram.draw(self, *args, **kwargs)
100 self.build_if_needed()
101 self.update_variables()
--> 102 Program.draw(self, *args, **kwargs)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/program.py:526, in Program.draw(self, mode, indices, check_error)
522 raise TypeError("Invalid index: %r (must be IndexBuffer)" %
523 indices)
525 # Process GLIR commands
--> 526 canvas.context.flush_commands()
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/context.py:172, in GLContext.flush_commands(self, event)
170 fbo = 0
171 self.shared.parser.parse([('CURRENT', 0, fbo)])
--> 172 self.glir.flush(self.shared.parser)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:582, in GlirQueue.flush(self, parser)
580 def flush(self, parser):
581 """Flush all current commands to the GLIR interpreter."""
--> 582 self._shared.flush(parser)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:504, in _GlirQueueShare.flush(self, parser)
502 show = self._verbose if isinstance(self._verbose, str) else None
503 self.show(show)
--> 504 parser.parse(self._filter(self.clear(), parser))
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:822, in GlirParser.parse(self, commands)
819 self._objects.pop(id_)
821 for command in commands:
--> 822 self._parse(command)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:778, in GlirParser._parse(self, command)
776 if ob is None:
777 if id_ not in self._invalid_objects:
--> 778 raise RuntimeError('Cannot %s object %i because it '
779 'does not exist' % (cmd, id_))
780 return
781 # Triage over command. Order of commands is set so most
782 # common ones occur first.
RuntimeError: Cannot SIZE object 118 because it does not exist
WARNING: Error drawing visual <Volume at 0x7fca20d29f40>
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/app/backends/_qt.py:903, in CanvasBackendDesktop.paintGL(self)
901 # (0, 0, self.width(), self.height()))
902 self._vispy_canvas.set_current()
--> 903 self._vispy_canvas.events.draw(region=None)
905 # Clear the alpha channel with QOpenGLWidget (Qt >= 5.4), otherwise the
906 # window is translucent behind non-opaque objects.
907 # Reference: MRtrix3/mrtrix3#266
908 if QT5_NEW_API or PYSIDE6_API or PYQT6_API:
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/util/event.py:453, in EventEmitter.__call__(self, *args, **kwargs)
450 if self._emitting > 1:
451 raise RuntimeError('EventEmitter loop detected!')
--> 453 self._invoke_callback(cb, event)
454 if event.blocked:
455 break
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/util/event.py:471, in EventEmitter._invoke_callback(self, cb, event)
469 cb(event)
470 except Exception:
--> 471 _handle_exception(self.ignore_callback_errors,
472 self.print_callback_errors,
473 self, cb_event=(cb, event))
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/util/event.py:469, in EventEmitter._invoke_callback(self, cb, event)
467 def _invoke_callback(self, cb, event):
468 try:
--> 469 cb(event)
470 except Exception:
471 _handle_exception(self.ignore_callback_errors,
472 self.print_callback_errors,
473 self, cb_event=(cb, event))
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/canvas.py:218, in SceneCanvas.on_draw(self, event)
215 # Now that a draw event is going to be handled, open up the
216 # scheduling of further updates
217 self._update_pending = False
--> 218 self._draw_scene()
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/canvas.py:277, in SceneCanvas._draw_scene(self, bgcolor)
275 bgcolor = self._bgcolor
276 self.context.clear(color=bgcolor, depth=True)
--> 277 self.draw_visual(self.scene)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/canvas.py:315, in SceneCanvas.draw_visual(self, visual, event)
313 else:
314 if hasattr(node, 'draw'):
--> 315 node.draw()
316 prof.mark(str(node))
317 else:
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/visuals.py:103, in VisualNode.draw(self)
101 if self.picking and not self.interactive:
102 return
--> 103 self._visual_superclass.draw(self)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/visuals/visual.py:451, in Visual.draw(self)
449 self._configure_gl_state()
450 try:
--> 451 self._program.draw(self._vshare.draw_mode,
452 self._vshare.index_buffer)
453 except Exception:
454 logger.warning("Error drawing visual %r" % self)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/visuals/shaders/program.py:102, in ModularProgram.draw(self, *args, **kwargs)
100 self.build_if_needed()
101 self.update_variables()
--> 102 Program.draw(self, *args, **kwargs)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/program.py:526, in Program.draw(self, mode, indices, check_error)
522 raise TypeError("Invalid index: %r (must be IndexBuffer)" %
523 indices)
525 # Process GLIR commands
--> 526 canvas.context.flush_commands()
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/context.py:172, in GLContext.flush_commands(self, event)
170 fbo = 0
171 self.shared.parser.parse([('CURRENT', 0, fbo)])
--> 172 self.glir.flush(self.shared.parser)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:582, in GlirQueue.flush(self, parser)
580 def flush(self, parser):
581 """Flush all current commands to the GLIR interpreter."""
--> 582 self._shared.flush(parser)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:504, in _GlirQueueShare.flush(self, parser)
502 show = self._verbose if isinstance(self._verbose, str) else None
503 self.show(show)
--> 504 parser.parse(self._filter(self.clear(), parser))
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:822, in GlirParser.parse(self, commands)
819 self._objects.pop(id_)
821 for command in commands:
--> 822 self._parse(command)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:778, in GlirParser._parse(self, command)
776 if ob is None:
777 if id_ not in self._invalid_objects:
--> 778 raise RuntimeError('Cannot %s object %i because it '
779 'does not exist' % (cmd, id_))
780 return
781 # Triage over command. Order of commands is set so most
782 # common ones occur first.
RuntimeError: Cannot SIZE object 118 because it does not exist
WARNING: Error drawing visual <Volume at 0x7fca20d29f40>
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/app/backends/_qt.py:903, in CanvasBackendDesktop.paintGL(self)
901 # (0, 0, self.width(), self.height()))
902 self._vispy_canvas.set_current()
--> 903 self._vispy_canvas.events.draw(region=None)
905 # Clear the alpha channel with QOpenGLWidget (Qt >= 5.4), otherwise the
906 # window is translucent behind non-opaque objects.
907 # Reference: MRtrix3/mrtrix3#266
908 if QT5_NEW_API or PYSIDE6_API or PYQT6_API:
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/util/event.py:453, in EventEmitter.__call__(self, *args, **kwargs)
450 if self._emitting > 1:
451 raise RuntimeError('EventEmitter loop detected!')
--> 453 self._invoke_callback(cb, event)
454 if event.blocked:
455 break
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/util/event.py:471, in EventEmitter._invoke_callback(self, cb, event)
469 cb(event)
470 except Exception:
--> 471 _handle_exception(self.ignore_callback_errors,
472 self.print_callback_errors,
473 self, cb_event=(cb, event))
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/util/event.py:469, in EventEmitter._invoke_callback(self, cb, event)
467 def _invoke_callback(self, cb, event):
468 try:
--> 469 cb(event)
470 except Exception:
471 _handle_exception(self.ignore_callback_errors,
472 self.print_callback_errors,
473 self, cb_event=(cb, event))
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/canvas.py:218, in SceneCanvas.on_draw(self, event)
215 # Now that a draw event is going to be handled, open up the
216 # scheduling of further updates
217 self._update_pending = False
--> 218 self._draw_scene()
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/canvas.py:277, in SceneCanvas._draw_scene(self, bgcolor)
275 bgcolor = self._bgcolor
276 self.context.clear(color=bgcolor, depth=True)
--> 277 self.draw_visual(self.scene)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/canvas.py:315, in SceneCanvas.draw_visual(self, visual, event)
313 else:
314 if hasattr(node, 'draw'):
--> 315 node.draw()
316 prof.mark(str(node))
317 else:
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/visuals.py:103, in VisualNode.draw(self)
101 if self.picking and not self.interactive:
102 return
--> 103 self._visual_superclass.draw(self)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/visuals/visual.py:451, in Visual.draw(self)
449 self._configure_gl_state()
450 try:
--> 451 self._program.draw(self._vshare.draw_mode,
452 self._vshare.index_buffer)
453 except Exception:
454 logger.warning("Error drawing visual %r" % self)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/visuals/shaders/program.py:102, in ModularProgram.draw(self, *args, **kwargs)
100 self.build_if_needed()
101 self.update_variables()
--> 102 Program.draw(self, *args, **kwargs)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/program.py:526, in Program.draw(self, mode, indices, check_error)
522 raise TypeError("Invalid index: %r (must be IndexBuffer)" %
523 indices)
525 # Process GLIR commands
--> 526 canvas.context.flush_commands()
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/context.py:172, in GLContext.flush_commands(self, event)
170 fbo = 0
171 self.shared.parser.parse([('CURRENT', 0, fbo)])
--> 172 self.glir.flush(self.shared.parser)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:582, in GlirQueue.flush(self, parser)
580 def flush(self, parser):
581 """Flush all current commands to the GLIR interpreter."""
--> 582 self._shared.flush(parser)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:504, in _GlirQueueShare.flush(self, parser)
502 show = self._verbose if isinstance(self._verbose, str) else None
503 self.show(show)
--> 504 parser.parse(self._filter(self.clear(), parser))
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:822, in GlirParser.parse(self, commands)
819 self._objects.pop(id_)
821 for command in commands:
--> 822 self._parse(command)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:778, in GlirParser._parse(self, command)
776 if ob is None:
777 if id_ not in self._invalid_objects:
--> 778 raise RuntimeError('Cannot %s object %i because it '
779 'does not exist' % (cmd, id_))
780 return
781 # Triage over command. Order of commands is set so most
782 # common ones occur first.
RuntimeError: Cannot SIZE object 118 because it does not exist
WARNING: Error drawing visual <Volume at 0x7fca20d29f40>
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/app/backends/_qt.py:903, in CanvasBackendDesktop.paintGL(self)
901 # (0, 0, self.width(), self.height()))
902 self._vispy_canvas.set_current()
--> 903 self._vispy_canvas.events.draw(region=None)
905 # Clear the alpha channel with QOpenGLWidget (Qt >= 5.4), otherwise the
906 # window is translucent behind non-opaque objects.
907 # Reference: MRtrix3/mrtrix3#266
908 if QT5_NEW_API or PYSIDE6_API or PYQT6_API:
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/util/event.py:453, in EventEmitter.__call__(self, *args, **kwargs)
450 if self._emitting > 1:
451 raise RuntimeError('EventEmitter loop detected!')
--> 453 self._invoke_callback(cb, event)
454 if event.blocked:
455 break
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/util/event.py:471, in EventEmitter._invoke_callback(self, cb, event)
469 cb(event)
470 except Exception:
--> 471 _handle_exception(self.ignore_callback_errors,
472 self.print_callback_errors,
473 self, cb_event=(cb, event))
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/util/event.py:469, in EventEmitter._invoke_callback(self, cb, event)
467 def _invoke_callback(self, cb, event):
468 try:
--> 469 cb(event)
470 except Exception:
471 _handle_exception(self.ignore_callback_errors,
472 self.print_callback_errors,
473 self, cb_event=(cb, event))
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/canvas.py:218, in SceneCanvas.on_draw(self, event)
215 # Now that a draw event is going to be handled, open up the
216 # scheduling of further updates
217 self._update_pending = False
--> 218 self._draw_scene()
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/canvas.py:277, in SceneCanvas._draw_scene(self, bgcolor)
275 bgcolor = self._bgcolor
276 self.context.clear(color=bgcolor, depth=True)
--> 277 self.draw_visual(self.scene)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/canvas.py:315, in SceneCanvas.draw_visual(self, visual, event)
313 else:
314 if hasattr(node, 'draw'):
--> 315 node.draw()
316 prof.mark(str(node))
317 else:
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/scene/visuals.py:103, in VisualNode.draw(self)
101 if self.picking and not self.interactive:
102 return
--> 103 self._visual_superclass.draw(self)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/visuals/visual.py:451, in Visual.draw(self)
449 self._configure_gl_state()
450 try:
--> 451 self._program.draw(self._vshare.draw_mode,
452 self._vshare.index_buffer)
453 except Exception:
454 logger.warning("Error drawing visual %r" % self)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/visuals/shaders/program.py:102, in ModularProgram.draw(self, *args, **kwargs)
100 self.build_if_needed()
101 self.update_variables()
--> 102 Program.draw(self, *args, **kwargs)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/program.py:526, in Program.draw(self, mode, indices, check_error)
522 raise TypeError("Invalid index: %r (must be IndexBuffer)" %
523 indices)
525 # Process GLIR commands
--> 526 canvas.context.flush_commands()
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/context.py:172, in GLContext.flush_commands(self, event)
170 fbo = 0
171 self.shared.parser.parse([('CURRENT', 0, fbo)])
--> 172 self.glir.flush(self.shared.parser)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:582, in GlirQueue.flush(self, parser)
580 def flush(self, parser):
581 """Flush all current commands to the GLIR interpreter."""
--> 582 self._shared.flush(parser)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:504, in _GlirQueueShare.flush(self, parser)
502 show = self._verbose if isinstance(self._verbose, str) else None
503 self.show(show)
--> 504 parser.parse(self._filter(self.clear(), parser))
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:822, in GlirParser.parse(self, commands)
819 self._objects.pop(id_)
821 for command in commands:
--> 822 self._parse(command)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/vispy/gloo/glir.py:778, in GlirParser._parse(self, command)
776 if ob is None:
777 if id_ not in self._invalid_objects:
--> 778 raise RuntimeError('Cannot %s object %i because it '
779 'does not exist' % (cmd, id_))
780 return
781 # Triage over command. Order of commands is set so most
782 # common ones occur first.
RuntimeError: Cannot SIZE object 118 because it does not exist