Issues running Napari in Jupyter/IPython

I’m encountering a weird issue when trying to run Napari from a Jupyter notebook. If I run %gui qt immediately before creating a Viewer object, napari will complain that I don’t have a Qt event loop set up and thus fail to launch.

Here is a minimal but verifyable example:
screenshot-2020-11-10-11:59:41

When I click the “Restart and run all cells” button, I get the following output from the third cell:

If I instead run the cells one-by-one, adding a pause of approximately 2 seconds between the second and third cells, napari launches correctly and I get this output:
screenshot-2020-11-10-12:02:01

I also tried adding a time.sleep(10) call in a cell in between the second and third cells, but that did not help (despite the fact that the sleep is several times longer than my manual pause):

This was verified with Napari 0.2.12, 0.3.8, and the current latest master branch (0.4.1a1).

Is this just a limitation of Jupyter/Qt/Napari? Is there something I am doing wrong?

Thanks,
Arjun

Hi @Arjun.Vikram, sorry you’re running into these problems!!

This approach should work, that we can look into that DPI warning, but it might be harmless. Do you see anything visibly wrong?

The other approaches unfortunately I don’t think will work, even the sleep call as that sleep is blocking the python execution needed. @GenevieveBuckley might have a way around this, so curious if she knows more?

Thanks for the response!

The DPI warning does seem to be harmless, it has always popped up when I use Napari in a script. I suspect it is because I am running Napari inside an LXC container (Singularity) running on an HPC cluster over VNC, so one of these links may be interfering with X11’s DPI calculations :slight_smile:.

I am more concerned about the needed pause between %gui qt and Napari’s initialization. I am writing some utility methods for my lab, so they can visualize slides and classifier outputs directly from their code. Ideally, they would call viewer = lab_utils.napari_visualize(slide, classifer_output) in a single cell of their code, and that method would handle setting up the event loop and launching napari all together. I don’t want to use the napari.gui_qt() context manager because that makes the napari viewer blocking.

I am interested to see if @GenevieveBuckley has a solution to this!

1 Like

Hi Arjun, I’ve also run into this problem - I think you just can’t restart and run all cells if there is an async magic in there (eg: %gui qt).

Why do you want to restart and run all? Is it to test the notebooks periodically and make sure they all work? If that’s what you’re trying to achieve, you could use the nbval pytest plugin https://github.com/computationalmodelling/nbval

I also agree that the DPI warning is not something to worry about, unless you’ve noticed something obviously weird about the napari display. It sounds like that’s not the case, so no problems here.

1 Like

I’ve filed an issue over at the jupyter project: https://github.com/jupyter/jupyter_core/issues/207

I don’t think this is desirable or expected behaviour, but it seems like a pretty tricky one to untangle.

1 Like

Thanks for filing an issue for this! I’ll be sure to track it.

I should probably clarify my use-case a bit more. The Jupyter notebook example I gave at the beginning was more for demonstration purposes and doesn’t match my lab’s workflow. We write our code as python files with “code cells” delimited by # %%. Our IDEs have support for running cells one at a time in an ipython kernel. We often run all the cells in a file from top to bottom when working on adding new functionality to the code. This also lets non-technical collaborators run the file from top to bottom when they want to view the visualizations we create.

Because I’m writing this inside a utility function for our lab, I don’t mind adding “hacky” workarounds, since they will be transparent to end users who just add a viewer = lab_utils.napari_visualize(slide, classifer_output) line to their code. I’m currently looking into how IPython sets up event loops and trying to replicate that manually.

Also, I noticed this issue in which you mentioned that adding a time.sleep(5) call resolved the issue. Any idea why the sleep didn’t work here?

My best guess is, the sleep trick didn’t work here because “Restart & Run All” doesn’t actually seem to run each notebook cell sequentially one by one. When you click restart and run all, then ALL of the cells are given an “in progress” indicator like this [*]. I think they all get initialized at once, and then tries to execute the content one by one.

I am by no means an expert on jupyter related stuff, fyi

Does your IDE support “Run all below” specific cells, like you can do from the jupyterlab menu? That might be another option for you:

  1. Restart kernel and clear output
  2. Manually run the %gui qt cell
  3. “Run all below” for the remaining cells

Or alternatively, can you sidestep this whole problem by setting the gui qt stuff when the ipython kernel is launched (instead of in a cell in the notebook). You can do this when you launch ipython from the terminal with ipython --gui qt