Подтвердить что ты не робот

Размещение интерактивных участков в виджетах ipython

У меня есть два сюжета, которые я хотел бы сделать интерактивными с виджетами ipython. Код ниже является упрощенным образцом того, что я пытаюсь сделать.

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])

Первая проблема заключается в том, что она сначала отображает все виджеты, и два графика один за другим в конце:

title1
widget1
title2
widget2
plot1
plot2

Я бы хотел:

title1
widget1
plot1    
title2
widget2
plot2

Также кажется, что весь вывод будет перезаписан, как только я коснусь любого из слайдеров, и отобразит только один сюжет (тот, который я меняю).

Как исправить эту проблему? (Я могу это сделать, если я разберу их на две разные ячейки, однако я планирую сделать что-то более сложное и в конечном итоге должен быть в одной ячейке)

4b9b3361

Ответ 1

IPython Notebook отображает виджеты перед любым выходом. Единственное, что вы можете сделать, это разместить ваши сюжеты внутри HTML-виджета. Это можно поместить в любую позицию относительно других виджетов.

Если вы это сделаете, вам нужно явно разместить свой сюжет в HTML-виджетах. Это может быть немного сложно, но быстрым решением было бы сохранить байтовую строку графика в буфер, а затем поместить байтовую строку в тег изображения.

Вот пример (Gist здесь):

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 перенесены на IPython.html; обновил код соответственно.

EDIT 2: использование widgets.interactive в соответствии с последней документацией по виджетам IPython; обновить местоположение виджетов IPython; добавление ASCII-кодирования