web-dev-qa-db-fra.com

Comment mettre à jour une parcelle dans matplotlib?

J'ai des problèmes pour redessiner le chiffre ici. J'autorise l'utilisateur à spécifier les unités dans l'échelle de temps (axe des x), puis je recalcule et appelle cette fonction plots(). Je veux simplement que l'intrigue se mette à jour et non pas en annexant une autre.

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)
125
thenickname

Vous avez essentiellement deux options:

  1. Faites exactement ce que vous êtes en train de faire, mais appelez graph1.clear() et graph2.clear() avant de replacer les données. C'est l'option la plus lente, mais la plus simple et la plus robuste.

  2. Au lieu de replacer, vous pouvez simplement mettre à jour les données des objets de tracé. Vous devrez apporter des modifications à votre code, mais cela devrait être beaucoup, beaucoup plus rapide que de replacer des choses à chaque fois. Toutefois, la forme des données que vous tracez ne peut pas changer et si la plage de vos données change, vous devrez réinitialiser manuellement les limites des axes x et y.

Pour donner un exemple de la deuxième option:

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()
142
Joe Kington

Vous pouvez également faire comme suit: Cela va dessiner une donnée de matrice aléatoire 10x1 sur le tracé pour 50 cycles de la boucle for.

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()
22
Arindam

Cela a fonctionné pour moi. Appelle à plusieurs reprises une fonction mettant à jour le graphique à chaque fois.

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" est une fonction qui renvoie un entier. FuncAnimation appellera à plusieurs reprises "update", il le fera "xmax" fois.

14
Vituel

Au cas où quelqu'un tomberait sur cet article en cherchant ce que je cherchais, j'ai trouvé des exemples à

Comment visualiser des données 2D scalaires avec Matplotlib?

et

http://mri.brechmos.org/2009/07/automatically-update-a-figure-in-a-loop (sur web.archive.org)

les a ensuite modifiés pour utiliser imshow avec une pile de trames en entrée, au lieu de générer et d’utiliser des contours à la volée.


Commençant par un tableau 3D d’images de forme (nBins, nBins, nBins), appelé 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)

J'ai également trouvé un moyen beaucoup plus simple de procéder à tout ce processus, bien que moins robuste:

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

Notez que ces deux-là ne semblent fonctionner qu'avec ipython --pylab=tk, a.k.a .backend = TkAgg

Merci pour l'aide avec tout.

8
CavemanPhD

J'ai publié un paquetage appelé python-drawnow qui fournit une fonctionnalité permettant à une figure de se mettre à jour, généralement appelée dans une boucle for, similaire à drawnow de Matlab.

Un exemple d'utilisation:

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)

Ce paquet fonctionne avec n'importe quelle figure matplotlib et fournit des options pour attendre après chaque mise à jour ou insertion dans le débogueur.

5
Scott

Tout ce qui précède est peut-être vrai. Cependant, pour moi, la mise à jour en ligne des chiffres ne fonctionne qu'avec certains moteurs, en particulier wx. Vous pouvez simplement essayer de changer ceci, par exemple en démarrant ipython/pylab par ipython --pylab=wx! Bonne chance!

3
jkeyser