Q:

Interactive plots placement in ipython notebook widget

I've got two plots which I'd like to make interactive with ipython notebook widgets. The code below is a simplified sample of what I'm trying to do.
import matplotlib.pyplot as plt
import IPython.html.widgets as wdg

def displayPlot1(rngMax = 10):
    plt.figure(0)
    plt.plot([x for x in range(0, rngMax)])

wdg1 = wdg.interactive(displayPlot1, rngMax = wdg.IntSlider(20))

def displayPlot2(rngMax = 10):
    plt.figure(1)
    plt.plot([x**2 for x in range(0, rngMax)])

wdg2 = wdg.interactive(displayPlot2, rngMax = wdg.IntSlider(10))

wdg.ContainerWidget([wdg.HTML("""<h1>First Plot</h1>"""),
                     wdg1, 
                     wdg.HTML("""<h1>Second Plot</h1>"""), 
                     wdg2])

The first problem is that it displays all the widgets first, and two plots one after another at the end:
title1
widget1
title2
widget2
plot1
plot2

I'd like to have:
title1
widget1
plot1    
title2
widget2
plot2

Also it seems the whole output gets overwritten as soon as I touch any of the sliders, and displays one plot only (the one I'm changing). 
How do I fix this problem? (I potentially can do it if I separate them into two different cells, however I'm planning to do something more complex and it needs to be in one cell eventually)

A:

IPython Notebook displays widgets before any output. One thing you can do is to place your plots inside an HTML widget. This can be placed in any position relative to other widgets.
If you do this however, you need to explicitly need to place your plot within the HTML widget. This can be a bit tricky, but a quick solution would be to save the byte string of the plot to a buffer and then put the byte string in an image tag.
Here's an example (Gist here):
import base64
import io
import matplotlib.pyplot as plt
import ipywidgets as widgets
from IPython.display import display

def handle_input1(slope):
    plt.figure()
    plt.plot([x * slope for x in range(0, 11)])
    plt.ylim((0,10))
    output1HTML.value = plot_to_html()
    plt.close()

def handle_input2(curvature):
    plt.figure()
    plt.plot([x * x * curvature for x in range(0, 11)])
    plt.ylim((0,100))
    output2HTML.value = plot_to_html()
    plt.close()

def plot_to_html():
    # write image data to a string buffer and get the PNG image bytes
    buf = io.BytesIO()
    plt.savefig(buf, format='png')
    buf.seek(0)
    return """<img src='data:image/png;base64,{}'/>""".format(base64.b64encode(buf.getvalue()).decode('ascii'))

plt.ioff()

heading1HTML = widgets.HTML("""<h1>Slope</h1>""")
input1Float = widgets.FloatSlider(value=0.5, min=0.0, max=1.0, step=0.01, description="slope: ")
widgets.interactive(handle_input1, slope=input1Float)
output1HTML = widgets.HTML()

heading2HTML = widgets.HTML("""<h1>Curvature</h1>""")
input2Float = widgets.FloatSlider(value=0.5, min=0.0, max=1.0, step=0.01, description="curvature: ")
widgets.interactive(handle_input2, curvature=input2Float)
output2HTML = widgets.HTML()

display(widgets.Box([heading1HTML, input1Float, output1HTML, heading2HTML, input2Float, output2HTML]))

handle_input1(input1Float.value)
handle_input2(input2Float.value)

EDIT 1: IPython widgets have been moved to IPython.html; updated the code accordingly.
EDIT 2: Using widgets.interactive as per the latest IPython widgets documentation; updating IPython widget location once more; adding ASCII encoding

