24

I am having trouble displaying plots inside of Jupyter tab widgets. Consider the following snippet:

import matplotlib.pyplot as plt
import pandas as pd
import ipywidgets as widgets
import numpy as np

out1 = widgets.Output()
out2 = widgets.Output()
data1 = pd.DataFrame(np.random.normal(size = 50))
data2 = pd.DataFrame(np.random.normal(size = 100))

with out1:
    fig1, axes1 = plt.subplots()
    data1.hist(ax = axes1)
    display(fig1)

with out2:
    fig2, axes2 = plt.subplots()
    data2.hist(ax = axes2)
    display(fig2)

tab = widgets.Tab(children = [out1, out2])
tab.set_title(0, 'First')
tab.set_title(1, 'Second')
display(tab)

(I am running Python 3.5.2, Jupyter 4.4.0, ipywidgets 7.2.1 on Ubuntu 16.04 inside a virtual environment.)

If I put this code on the first row of the notebook and run it, I see a tab widget with two tabs, each one of which displays a string, but not the plot:

No plots

If I run it for a second time, or if I rerun it putting everything after the import of matplotlib in a second cell, I see a tab widget with one plot on each tab, but I get the two plots displayed a second time outside of the tabs.

Too many plots

I can get rid of the additional displays by wrapping my code inside calls to plt.ioff and plt.ion, but it has been suggested to me that this is a hack. And in any case, it does not make matplotlib display the plots in the first cell.

Question: What is the proper way of displaying plots inside tabs?

2 Answers 2

38

I added a couple of things to make your code work as you would like

  • Add %matplotlib inline at the top of the cell
  • Replace your display(fig) calls with plt.show(fig) calls.
%matplotlib inline
import matplotlib.pyplot as plt
import pandas as pd
import ipywidgets as widgets
import numpy as np

out1 = widgets.Output()
out2 = widgets.Output()
data1 = pd.DataFrame(np.random.normal(size = 50))
data2 = pd.DataFrame(np.random.normal(size = 100))

tab = widgets.Tab(children = [out1, out2])
tab.set_title(0, 'First')
tab.set_title(1, 'Second')
display(tab)

with out1:
    fig1, axes1 = plt.subplots()
    data1.hist(ax = axes1)
    plt.show(fig1)

with out2:
    fig2, axes2 = plt.subplots()
    data2.hist(ax = axes2)
    plt.show(fig2)
Sign up to request clarification or add additional context in comments.

8 Comments

What's the logic behind "Replace your display(fig) calls with plt.show(fig) calls" please?
Isn't display a method of ipywidget, which is not really compatible with matplotlib? I am not sure, but think.
I have used this for a related answer here. I'm linking it here because I have links there that launch active, temporary sessions served via MyBinder that should run just in your browser without installing anything.
@ILoveCoding, I think the reason for using plt.show() and not display is that in the OP example there were two plots getting made and you can channel the plt.show() generated output into each widget. So maybe the thinking there is it's simpler to use plt.show() & target the output to the tab rather than suppress the output that is made in the course of producing the plot in the first place and then display the associated figure again? If you go that route & use display(), you add another line of code to each with block ....
see part #1 example at the top here. (Go there and run all the cells first.) If you remove the plt.close() and display() lines from each and run the code fresh, you'll see the widgets get made without the plots and the two plots show up below the tab widget. You need plt.show() added there to channel it into the context manager that gets used in the widgets.Output(), it seems.
|
0

plt.show(fig) in the answer above from ac24 is now deprecated:

In [1]: import matplotlib.pyplot as plt                                                                                                                                   

In [2]: fig = plt.figure()                                                                                                                                                

In [3]: plt.show(fig)                                                                                                                                                     
<ipython-input-3-d1fd62acb551>:1: MatplotlibDeprecationWarning: Passing the 
block parameter of show() positionally is deprecated since Matplotlib 3.1; the 
parameter will become keyword-only in 3.3.
    plt.show(fig)

plt.show(block=True) (or plt.show(block=False)) is the keyword-only call.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.