How can I get access to the image view for custom GUI elements?

Hello, this is an amazing project! I’m using it for an analysis pipeline I’m writing for my lab.

For our analysis, we need to manually manipulate a spline with control points. I have a GUI for that manipulation working with pyqtgraph, but I’d like to use napari for this. Is there any way I can get ahold of the imageview object for the current layer so i can draw custom GUI elements over it?

I know supporting custom GUI elements out of the box is something downstream for you guys in later releases, but I’m willing to dive into the code to make it work in a hackier way for now.


Hi @sean_johnsen , glad you are finding it useful!

I don’t have experience with pyqtgraph, but it looks like their ImageView object is a QWidget… so I gather you’re looking for a handle to a useful QWidget in napari?
It really depends on exactly what you’re looking to do… but if you’re just looking to get at a top level canvas widget in napari that behave’s something like an ImageView, you might be looking for viewer.window.qt_viewer.canvas.native

here’s some code that will hopefully help to start:

import napari

# use napari.gui_qt() if you don't already have a Qt loop
viewer = napari.Viewer()

# the QtViewer is one of the most important classes to look at

# among other things, it contains a "canvas" object that comes from vispy

# it has a "native" attribute that is a QWidget
from qtpy.QtWidgets import QWidget
assert isinstance(viewer.window.qt_viewer.canvas.native, QWidget)

I haven’t yet tried hacking around and overlaying new QtWidgets on that area, so let us know if run into snags in doing so.

I’m also assuming from the wording of your question that you need your custom GUI element to be literally superimposed on the image. If that’s not the case, note that you can add any custom gui elements to the viewer using viewer.window.add_dock_widget(widget) … where “widget” is any instance of a QWidget.

I’ll also note that we don’t construct individual QWidgets for each layer. Instead, they are added as vispy.scene.Visuals to a vispy.SceneCanvas