Was ist derzeit die richtige Methode, um Diagramme in Jupyter / iPython dynamisch zu aktualisieren?

89

In den Antworten zum dynamischen Aktualisieren eines Plots in einer Schleife in einem Ipython-Notizbuch (innerhalb einer Zelle) wird ein Beispiel für das dynamische Aktualisieren eines Plots in einem Jupyter-Notizbuch in einer Python-Schleife gegeben. Dies funktioniert jedoch, indem der Plot bei jeder Iteration zerstört und neu erstellt wird. Ein Kommentar in einem der Threads weist darauf hin, dass diese Situation durch die Verwendung der neuen %matplotlib nbaggMagie verbessert werden kann , die eine interaktive Figur bietet, die eher in das Notizbuch eingebettet ist als ein statisches Bild.

Dies ist jedoch wunderbar neu nbaggSoweit ich das beurteilen kann, scheint Funktion jedoch völlig undokumentiert zu sein, und ich kann kein Beispiel dafür finden, wie sie zum dynamischen Aktualisieren eines Plots verwendet werden kann. Meine Frage ist also, wie man ein vorhandenes Diagramm in einem Jupyter / Python-Notizbuch mithilfe des nbagg-Backends effizient aktualisiert. Da das dynamische Aktualisieren von Plots in matplotlib im Allgemeinen ein heikles Thema ist, wäre ein einfaches Arbeitsbeispiel eine enorme Hilfe. Ein Verweis auf eine Dokumentation zu diesem Thema wäre ebenfalls äußerst hilfreich.

Um klar zu sein, wonach ich frage: Ich möchte einen Simulationscode für einige Iterationen ausführen, dann ein Diagramm des aktuellen Status zeichnen, es dann für einige weitere Iterationen ausführen und dann das Diagramm entsprechend aktualisieren der aktuelle Zustand und so weiter. Die Idee ist also, ein Diagramm zu zeichnen und dann ohne Interaktion des Benutzers die Daten im Diagramm zu aktualisieren, ohne das Ganze zu zerstören und neu zu erstellen.

Hier ist ein leicht modifizierter Code aus der Antwort auf die oben verknüpfte Frage, der dies erreicht, indem die gesamte Figur jedes Mal neu gezeichnet wird. Ich möchte das gleiche Ergebnis erzielen, aber effizienter nutzen nbagg.

%matplotlib inline
import time
import pylab as pl
from IPython import display
for i in range(10):
    pl.clf()
    pl.plot(pl.randn(100))
    display.display(pl.gcf())
    display.clear_output(wait=True)
    time.sleep(1.0)
Nathaniel
quelle

Antworten:

62

Hier ist ein Beispiel, das einen Plot in einer Schleife aktualisiert. Es aktualisiert die Daten in der Abbildung und zeichnet nicht jedes Mal die gesamte Abbildung neu. Es blockiert die Ausführung. Wenn Sie jedoch daran interessiert sind, eine begrenzte Anzahl von Simulationen auszuführen und die Ergebnisse irgendwo zu speichern, ist dies möglicherweise kein Problem für Sie.

%matplotlib notebook

import numpy as np
import matplotlib.pyplot as plt
import time

def pltsin(ax, colors=['b']):
    x = np.linspace(0,1,100)
    if ax.lines:
        for line in ax.lines:
            line.set_xdata(x)
            y = np.random.random(size=(100,1))
            line.set_ydata(y)
    else:
        for color in colors:
            y = np.random.random(size=(100,1))
            ax.plot(x, y, color)
    fig.canvas.draw()

fig,ax = plt.subplots(1,1)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_xlim(0,1)
ax.set_ylim(0,1)
for f in range(5):
    pltsin(ax, ['b', 'r'])
    time.sleep(1)

Ich habe das hier auf nbviewer eingestellt.

Es gibt eine IPython-Widget-Version nbagg, die derzeit im Matplotlib-Repository in Arbeit ist . Wenn dies verfügbar ist, ist dies wahrscheinlich die beste Verwendung nbagg.

BEARBEITEN: aktualisiert, um mehrere Diagramme anzuzeigen

Pneumatik
quelle
1
Großartig, das scheint gut zu funktionieren. Der Mangel an Interaktivität während des Betriebs ist für mich kein großes Problem. Eine etwas seltsame Sache: Wenn ich die while True:Schleife in eine for-Schleife ändere , erhalte ich am Ende der Schleife zwei statische Bilder des letzten Plots anstelle eines interaktiven nbagg-Bildes. Irgendeine Idee warum das so ist?
Nathaniel
Ich habe die Weile in eine for-Schleife geändert und es auf tmpnb.org versucht, aber ich sehe kein zweites Bild oder keinen Verlust an Interaktivität. Im Dunkeln aufgenommen, aber Sie könnten versuchen, die Schleife um den Aufruf der Funktion zu verschieben, anstatt die Schleife in der Funktion zu haben. für f im Bereich (10): pltsin (ax) time.sleep (1)
Pneumatik
3
@pneumatics Leider gibt es einige Probleme mit Matplotlib 2.0 auf dem Retina-Display: In der Schleife sind die Diagramme doppelt so klein wie normalerweise.
Alexander Rodin
1
Es scheint, dass der Figur nicht die Zeit gegeben wird, ihre Größe korrekt zu ändern. Ich hatte also eine viel bessere Erfahrung, als ich eine plt.show()for-Schleife platzierte und in die nächste Zelle verschob.
ImportanceOfBeingErnest
2
Stellen Sie sicher, dass Sie das% matplotlib-Notizbuch in derselben Jupyter-Notizbuchzelle wie Ihr Plot haben. Ich habe heute über 2 Stunden damit verbracht, dieses Problem zu beheben, da ich% matplotlib-Notizbuch in der ersten Zelle mit den Importanweisungen hatte
aguazul
9

Ich benutze jupyter-lab und das funktioniert bei mir (passe es an deinen Fall an):

from IPython.display import clear_output
from matplotlib import pyplot as plt
import collections
%matplotlib inline

def live_plot(data_dict, figsize=(7,5), title=''):
    clear_output(wait=True)
    plt.figure(figsize=figsize)
    for label,data in data_dict.items():
        plt.plot(data, label=label)
    plt.title(title)
    plt.grid(True)
    plt.xlabel('epoch')
    plt.legend(loc='center left') # the plot evolves to the right
    plt.show();

Dann füllen Sie in einer Schleife ein Wörterbuch und übergeben es an live_plot():

data = collections.defaultdict(list)
for i in range(100):
    data['foo'].append(np.random.random())
    data['bar'].append(np.random.random())
    data['baz'].append(np.random.random())
    live_plot(data)

Stellen Sie sicher, dass sich einige Zellen unterhalb des Diagramms befinden. Andernfalls rastet die Ansicht jedes Mal ein, wenn das Diagramm neu gezeichnet wird.

Ziofil
quelle
1
Pneumatik
2
Richtig. Ich habe keinen besseren Weg gefunden, um im Jupyter-Labor eine dynamische Handlung zu haben.
Ziofil
1
Gibt es eine Möglichkeit festzulegen, wie lange zwischen den Iterationen gewartet wird? anstatt nur zu warten = wahr
Ahmad Moussa
1
Jedes Mal, wenn der Plot neu gezeichnet wird, flackert die Grafik. Gibt es eine Möglichkeit, dieses Problem zu beheben? Ich habe ein paar leere Zellen unter der Handlung, aber das scheint nicht zu helfen.
MasayoMusic
@ MasayoMusic siehe "Flackern und Springen Ausgabe" in buildmedia.readthedocs.org/media/pdf/ipywidgets/latest/…
Leo
0

Ich habe die Antwort von @Ziofil angepasst und geändert, um x, y als Liste zu akzeptieren und ein Streudiagramm sowie einen linearen Trend auf demselben Diagramm auszugeben.

from IPython.display import clear_output
from matplotlib import pyplot as plt
%matplotlib inline
    
def live_plot(x, y, figsize=(7,5), title=''):
    clear_output(wait=True)
    plt.figure(figsize=figsize)
    plt.xlim(0, training_steps)
    plt.ylim(0, 100)
    x= [float(i) for i in x]
    y= [float(i) for i in y]
    
    if len(x) > 1:
        plt.scatter(x,y, label='axis y', color='k') 
        m, b = np.polyfit(x, y, 1)
        plt.plot(x, [x * m for x in x] + b)

    plt.title(title)
    plt.grid(True)
    plt.xlabel('axis x')
    plt.ylabel('axis y')
    plt.show();

Sie müssen nur live_plot(x, y)innerhalb einer Schleife aufrufen . So sieht es aus: Geben Sie hier die Bildbeschreibung ein

Miguel Silva
quelle