39

I am using Jupyter Notebook for plotting piechart figures.

In first cell with my code I have a magic command %matplotlib inline and after this magic command I run my code, everything works fine and my figure renders.

But in second cell when I set %matplotlib notebook for interactive plotting my figure won't render after running this second cell.

I need to restart kernel and run cell with %matplotlib notebook again and cannot run %matplotlib inline command before that.

Here is my code for first cell with %matplotlib inline, which renders fine:

import matplotlib.pyplot as plt

%matplotlib inline

labels = "No", "Yes"
sizes = [100, 50]

fig, ax = plt.subplots(figsize=(6, 6))

_, texts, autotexts = ax.pie(sizes, explode=explode, labels=labels, colors=colors, autopct='%1.1f%%',
             shadow=False, startangle=90)

ax.axis('equal')

After that I have second cell with same code, just %matplotlib inline is changed to %matplotlib notebook. Figure won't render after I run this cell and I need to restart kernel and run this cell again.

Why?

PeterB
  • 2,234
  • 6
  • 24
  • 43
  • Load and using library change/store more class and variables, use copy+rename module class as external module. Single import single usage... – dsgdfg Apr 21 '17 at 14:59

3 Answers3

48

You just have the wrong order of your commands. A backend should be set before importing pyplot in jupyter. Or in other words, after changing the backend, pyplot needs to be imported again.

Therefore call %matplotlib ... prior to importing pyplot.

In first cell:

%matplotlib inline
import matplotlib.pyplot as plt
plt.plot([1,1.6,3])

In second cell:

%matplotlib notebook
#calling it a second time may prevent some graphics errors
%matplotlib notebook  
import matplotlib.pyplot as plt
plt.plot([1,1.6,3])

BSMP
  • 4,596
  • 8
  • 33
  • 44
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • 6
    "A backend must be set before importing pyplot." I don't believe that's true. For years, I've always used "%matplotlib inline" *after* importing pyplot, with no problem. I just tried your code, moving the magics to after the pyplot imports, and it ran correctly (I did need the 2nd "%matplotlib notebook" command; thanks for that tip). Note also that you can't put a comment after "%matplotlib notebook". You may be confusing requirements of the "use()" command; see #3 here: https://matplotlib.org/2.2.3/tutorials/introductory/usage.html#id3 – Tom Loredo Oct 05 '18 at 04:59
  • Thanks for commenting. Changing the backend via the magic commands does not work reliably, but you can circumvent that by setting the backend before the pyplot import. If you never experienced any problems with the inverse, that's probably lucky. I modified the sentence above to be more accurate though. – ImportanceOfBeingErnest Oct 05 '18 at 11:33
  • 2
    Part of why I was skeptical was the suggestion to re-import pyplot after setting/changing the backend. Importing an already-imported module in Python normally does nothing (if the module is already imported, `import` normally only does name binding to the already-imported module; see http://effbot.org/zone/import-confusion.htm). Does pyplot have some special import behavior? – Tom Loredo Oct 07 '18 at 16:08
  • You might be right about the reimport not being necessary. At the time of writing this solution it seemed required, but as of today, I cannot reproduce this anymore (newer jupyter/ipython/matplotlib versions in use). – ImportanceOfBeingErnest Oct 08 '18 at 02:54
  • 3
    Why does this answer has so many upvotes when it is based on completely wrong assumption? As Tom Loredo noted, the second `import matplotlib.pyplot as plt` does nothing. This is just some python101 stuff(https://stackoverflow.com/questions/437589/how-do-i-unload-reload-a-module) –  Apr 21 '20 at 03:13
  • @bombs The key is that the backend needs to be set before importing pyplot and that if you want to use the notebook backend you need to state that twice. Reimporting is not necessary, as shown in the discussion above, but that is only tangential to the problem. Feel free to edit the answer if it contains errors. – ImportanceOfBeingErnest Apr 22 '20 at 08:14
  • @bombs: The second import is indeed required to switch backends in Jupyter Lab. So the answer is correct there and _not_ based on wrong assumptions. – Alexander May 11 '20 at 14:07
  • @Alexander I cannot reproduce that in my jupyter lab (0.32.1). And I think if you indeed want to reload the module you should run `import importlib;importlib.reload(plt)` –  May 12 '20 at 00:58
  • 2
    @ImportanceOfBeingErnest It seems the backend doesn't need to be set before importing pyplot. At least in my jupyter notebook. –  May 12 '20 at 01:11
  • @bombs: Thanks for checking, on 2.1.2 the second import is required. I totally agree that this is not pythonic and maybe connected to some brittle magic in matplotlib or the backend-specific bits. – Alexander May 12 '20 at 07:34
  • The interplay between IPython and Matplotlib can be brittle. And tbh I don't know much about how JupyterLab (as opposed to Jupyter notebook) solves some of the bits and pieces. Really, the only thing I can tell for sure that at the time this answer was written it was the only working solution. – ImportanceOfBeingErnest May 12 '20 at 15:10
  • For your information, seeing this retrospect after years would make me skeptical as well. I hope by now they "fixed" or changed the behavior so that this answer is not even necessary anymore. The fact is that I do not use Jupyter at work anymore, so I do not know about potential updates. Please feel free to edit my answer to fix any issues you find with it. – Diego Jan 16 '21 at 01:29
  • On jupyterlab==3.3.4 and matplotlib==3.5.2, it is possible to switch backend (back and forth) by just prefixing the cell with the magic command %matplotlib. Neither multiple magic calls nor a new matplotlib import are necessary. In the meanwhile `notebook` has been renamed to `widget`. – Eric M. May 09 '22 at 08:50
6

Edit: turns out that you can in fact change backends dynamically on jupyter. Still leaving the answer here because I think it's relevant and explains some matplotlib magic that can pop out sometimes.

The magic command, as seen in the source code, is calling matplotlib.pyplot.switch_backend(newbackend) to change the backend. As stated in matplotlib's docs:

matplotlib.pyplot.switch_backend(newbackend)

Switch the default backend. This feature is experimental, and is only expected to work switching to an image backend. e.g., if you have a bunch of PostScript scripts that you want to run from an interactive ipython session, you may want to switch to the PS backend before running them to avoid having a bunch of GUI windows popup. If you try to interactively switch from one GUI backend to another, you will explode..

So you really have to restart the kernel each time you switch backends, because matplotlib has a problem to switch the backend after being used.

This problem is mainly due to incompatibilities between different main-loops of the GUI backend. Because normally each backend is also taking care of threads and user input you can't run Qt and Tkinter side-by-side. So that limitation is carried over to jupyter.

Also see this question: How to switch backends in matplotlib / Python

Community
  • 1
  • 1
unddoch
  • 5,790
  • 1
  • 24
  • 37
-1

In Jupyter notebook, you have to enter matplotlib notebook in the same line as the one you want to run. Even if you enter "inline" then followed by "notebook", it still won't work. It has to be on the same line as the code you want to render.