2015-08-10 17 views
11

Ho due grafici che vorrei rendere interattivi con i widget del taccuino ipython. Il codice seguente è un esempio semplificato di ciò che sto cercando di fare.Posizionamento di grafici interattivi nel widget del taccuino 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]) 

Il primo problema è che visualizza tutti i widget prima, e due lotti uno dopo l'altro alla fine:

title1 
widget1 
title2 
widget2 
plot1 
plot2 

Mi piacerebbe avere:

title1 
widget1 
plot1  
title2 
widget2 
plot2 

Inoltre sembra che l'intero output venga sovrascritto non appena tocco uno dei cursori e visualizza solo un grafico (quello che sto cambiando).

Come posso risolvere questo problema? (Potenzialmente posso farlo se li separo in due celle diverse, tuttavia ho intenzione di fare qualcosa di più complesso e alla fine deve essere in una cella)

+1

Ho visto che hai iniziato una taglia, quindi ho pensato che probabilmente sei ancora interessato a una risposta più dettagliata. Ho aggiunto del codice qui sotto che dovrebbe illustrare come farlo. Sono un po 'in ritardo per la taglia, ma forse puoi ancora assegnargli una certa reputazione. –

risposta

6

Notebook IPython visualizza i widget prima di qualsiasi output. Una cosa che puoi fare è posizionare i tuoi grafici all'interno di uno HTML widget. Questo può essere posizionato in qualsiasi posizione rispetto ad altri widget.

In questo caso, tuttavia, è necessario posizionare la trama all'interno del widget HTML. Questo può essere un po 'complicato, ma una soluzione rapida sarebbe quella di salvare la stringa di byte del grafico su un buffer e quindi inserire la stringa di byte in un tag immagine.

Ecco un esempio (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: i widget ipython sono stati spostati IPython.html; aggiornato il codice di conseguenza.

MODIFICA 2: utilizzo di widget.interactive come da ultimo IPython widgets documentation; aggiornando ancora una volta la posizione del widget IPython; Aggiungendo codifica ASCII

+1

I widget IPython sono stati spostati di nuovo, ma per ora è solo un avvertimento. Ancora più importante, in Python 3.x devi '.decode ('ascii')' la stringa byte restituita da 'buf.getvalue()' – gboffi

+1

Per correggere me stesso, cos'è _ascii_ è il valore restituito da 'base64.b64encode() ', quindi la modifica che propongo è' base64.b64encode (buf.getvalue()). encode ('ascii') 'che funziona pure in Python2 ed è necessario in Python3. – gboffi

+0

Grazie per il feedback, @gboffi. Ho modificato l'esempio di conseguenza e ho anche dato un'occhiata ai più recenti documenti widget IPython. Sembra come widgets.interactive() è il modo preferito per registrare l'osservatore con il widget. Non ho python3 su questa macchina, potresti forse controllare se funziona senza avvertimenti? –

Problemi correlati