Hoe een plot bijwerken in matplotlib?

Ik heb problemen met het opnieuw tekenen van de afbeelding hier. Ik sta de gebruiker toe om de eenheden in de tijdschaal (x-as) te specificeren en dan herbereken ik en noem ik deze functie plots(). Ik wil dat de plot gewoon wordt bijgewerkt, niet dat er nog een plot aan de figuur wordt toegevoegd.

def plots():
    global vlgaBuffSorted
    cntr()
    result = collections.defaultdict(list)
    for d in vlgaBuffSorted:
        result[d['event']].append(d)
    result_list = result.values()
    f = Figure()
    graph1 = f.add_subplot(211)
    graph2 = f.add_subplot(212,sharex=graph1)
    for item in result_list:
        tL = []
        vgsL = []
        vdsL = []
        isubL = []
        for dict in item:
            tL.append(dict['time'])
            vgsL.append(dict['vgs'])
            vdsL.append(dict['vds'])
            isubL.append(dict['isub'])
        graph1.plot(tL,vdsL,'bo',label='a')
        graph1.plot(tL,vgsL,'rp',label='b')
        graph2.plot(tL,isubL,'b-',label='c')
    plotCanvas = FigureCanvasTkAgg(f, pltFrame)
    toolbar = NavigationToolbar2TkAgg(plotCanvas, pltFrame)
    toolbar.pack(side=BOTTOM)
    plotCanvas.get_tk_widget().pack(side=TOP)

Antwoord 1, autoriteit 100%

Je hebt in wezen twee opties:

  1. Doe precies wat u momenteel doet, maar bel graph1.clear()en graph2.clear()voordat u de gegevens opnieuw plot. Dit is de langzaamste, maar meest eenvoudige en meest robuuste optie.

  2. In plaats van opnieuw te repletten, kunt u gewoon de gegevens van de plotobjecten bijwerken. U moet enkele wijzigingen in uw code aanbrengen, maar dit zou veel moeten zijn, veel sneller dan elke keer opnieuw te replatteren. De vorm van de gegevens die u plotte, kan echter niet veranderen, en als het bereik van uw gegevens verandert, moet u de X- en Y-aslimieten handmatig resetten.

Om een ​​voorbeeld van de tweede optie te geven:

import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 6*np.pi, 100)
y = np.sin(x)
# You probably won't need this if you're embedding things in a tkinter plot...
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
line1, = ax.plot(x, y, 'r-') # Returns a tuple of line objects, thus the comma
for phase in np.linspace(0, 10*np.pi, 500):
    line1.set_ydata(np.sin(x + phase))
    fig.canvas.draw()
    fig.canvas.flush_events()

Antwoord 2, Autoriteit 24%

U kunt ook het volgende doen:
Dit trekt een 10×1 willekeurige matrixgegevens op het perceel voor 50 cycli van de voor lus.

import matplotlib.pyplot as plt
import numpy as np
plt.ion()
for i in range(50):
    y = np.random.random([10,1])
    plt.plot(y)
    plt.draw()
    plt.pause(0.0001)
    plt.clf()

Antwoord 3, Autoriteit 9%

Dit werkte voor mij. Roept herhaaldelijk een functie op de grafiek bij het bijwerken van de grafiek.

import matplotlib.pyplot as plt
import matplotlib.animation as anim
def plot_cont(fun, xmax):
    y = []
    fig = plt.figure()
    ax = fig.add_subplot(1,1,1)
    def update(i):
        yi = fun()
        y.append(yi)
        x = range(len(y))
        ax.clear()
        ax.plot(x, y)
        print i, ': ', yi
    a = anim.FuncAnimation(fig, update, frames=xmax, repeat=False)
    plt.show()

“fun” is een functie die een geheel getal retourneert.
FuncAnimation zal herhaaldelijk “update” aanroepen, het zal dat “xmax” keer doen.


Antwoord 4, autoriteit 4%

Voor het geval iemand dit artikel tegenkomt op zoek naar wat ik zocht, ik vond voorbeelden op

Hoe kan ik scalaire 2D-gegevens visualiseren met Matplotlib?

en

http://mri.brechmos.org/2009/ 07/automatisch-update-een-cijfer-in-een-loop
(op web.archive.org)

vervolgens aangepast om imshow te gebruiken met een invoerstapel van frames, in plaats van on-the-fly contouren te genereren en te gebruiken.


Begin met een 3D-array van vormafbeeldingen (nBins, nBins, nBins), genaamd frames.

def animate_frames(frames):
    nBins   = frames.shape[0]
    frame   = frames[0]
    tempCS1 = plt.imshow(frame, cmap=plt.cm.gray)
    for k in range(nBins):
        frame   = frames[k]
        tempCS1 = plt.imshow(frame, cmap=plt.cm.gray)
        del tempCS1
        fig.canvas.draw()
        #time.sleep(1e-2) #unnecessary, but useful
        fig.clf()
fig = plt.figure()
ax  = fig.add_subplot(111)
win = fig.canvas.manager.window
fig.canvas.manager.window.after(100, animate_frames, frames)

Ik heb ook een veel eenvoudigere manier gevonden om dit hele proces aan te pakken, zij het minder robuust:

fig = plt.figure()
for k in range(nBins):
    plt.clf()
    plt.imshow(frames[k],cmap=plt.cm.gray)
    fig.canvas.draw()
    time.sleep(1e-6) #unnecessary, but useful

Merk op dat allebei alleen lijken te werken met ipython --pylab=tk, A.K.A. backend = TkAgg

Bedankt voor de hulp bij alles.


Antwoord 5, Autoriteit 4%

Ik heb een pakket vrijgegeven genaamd python-curatow die functionaliteit biedt om een ​​figuur-update te laten updaten, Typisch gebeld in een voor lus, vergelijkbaar met Matlab’s drawnow.

Een voorbeeldgebruik:

from pylab import figure, plot, ion, linspace, arange, sin, pi
def draw_fig():
    # can be arbitrarily complex; just to draw a figure
    #figure() # don't call!
    plot(t, x)
    #show() # don't call!
N = 1e3
figure() # call here instead!
ion()    # enable interactivity
t = linspace(0, 2*pi, num=N)
for i in arange(100):
    x = sin(2 * pi * i**2 * t / 100.0)
    drawnow(draw_fig)

Dit pakket werkt met een matplotlib-figuur en biedt opties om te wachten na elke figuur-update of dalen in de debugger.


Antwoord 6, Autoriteit 2%

Dit werkte voor mij:

from matplotlib import pyplot as plt
from IPython.display import clear_output
import numpy as np
for i in range(50):
    clear_output(wait=True)
    y = np.random.random([10,1])
    plt.plot(y)
    plt.show()

Antwoord 7, Autoriteit 2%

Al het bovenstaande kan waar zijn, maar voor mij werkt “online-updaten” van cijfers alleen met sommige backends, met name wx. Je zou kunnen proberen om hierin te veranderen, b.v. door ipython/pylab te starten door ipython --pylab=wx! Veel succes!


Antwoord 8

Op basis van de andere antwoorden heb ik de update van de figuur in een python-decorateur gewikkeld om het updatemechanisme van de plot te scheiden van de eigenlijke plot. Op deze manier is het veel gemakkelijker om een plot bij te werken.

def plotlive(func):
    plt.ion()
    @functools.wraps(func)
    def new_func(*args, **kwargs):
        # Clear all axes in the current figure.
        axes = plt.gcf().get_axes()
        for axis in axes:
            axis.cla()
        # Call func to plot something
        result = func(*args, **kwargs)
        # Draw the plot
        plt.draw()
        plt.pause(0.01)
        return result
    return new_func 

Gebruiksvoorbeeld

En dan kun je het gebruiken zoals elke andere decorateur.

@plotlive
def plot_something_live(ax, x, y):
    ax.plot(x, y)
    ax.set_ylim([0, 100])

De enige beperking is dat je de figuur vóór de lus moet maken:

fig, ax = plt.subplots()
for i in range(100):
    x = np.arange(100)
    y = np.full([100], fill_value=i)
    plot_something_live(ax, x, y)

Other episodes