2010-11-04 17 views
80

Sto riscontrando problemi nel ridisegnare la figura qui. Autorizzo l'utente a specificare le unità nella scala temporale (asse x), quindi ricalcolo e richiamo questa funzione plots(). Voglio che la trama si aggiorni semplicemente, non aggiungere un'altra trama alla figura.Come aggiornare un grafico in matplotlib?

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) 
+0

Possibile duplicato del [tempo reale tramando in ciclo while con matplotlib] (http://stackoverflow.com/questions/11874767/real-time-plotting-in-while-loop-with-matplotlib) –

risposta

97

Hai essenzialmente due opzioni:

  1. fare esattamente quello che stai facendo attualmente, ma chiamano graph1.clear() e graph2.clear() prima di tracciare nuovamente i dati. Questa è l'opzione più lenta, ma la più semplice e più robusta.

  2. Invece di eseguire la sostituzione, è possibile aggiornare semplicemente i dati degli oggetti di stampa. Dovrai apportare alcune modifiche al tuo codice, ma questo dovrebbe essere molto, molto più veloce di ogni volta che si sostituiscono le cose. Tuttavia, la forma dei dati che stai stampando non può cambiare, e se l'intervallo dei tuoi dati sta cambiando, dovrai reimpostare manualmente i limiti dell'asse x e y.

Per dare un esempio della seconda opzione:

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() 
+0

Ho provato a testare "1." e il risultato è stato, dopo che ho sostituito i dati, un altro set di grafici sono stati disegnati nella GUI, quindi ora ho avuto 4 grafici dopo il ricalcolo, proprio come prima. – thenickname

+0

@thenickname - Dove esattamente nel tuo codice stai chiamando 'clear'? Dovresti chiamare 'graph1.clear(); graph2.clear() 'all'interno del ciclo' for', appena prima di chiamare 'graph1.plot (...)', 'graph2.plot (...)' etc ... –

+0

Questo per ciclo crea call graphx. trama (...) N volte e mettendo le dichiarazioni chiare lì solo trame l'ultimo. In realtà ho tirato fuori il codice canvas e l'ho inserito nel loop del programma principale insieme al codice della figura e ora ho chiamato la mia funzione da un pulsante. Per qualche ragione, se chiamo semplicemente la funzione, i grafici vengono aggiornati, ma se premo il pulsante i grafici non lo fanno. È un comportamento piuttosto interessante. Penso che dev'essere un bug in Tkinter. – thenickname

3

Tutto quanto sopra potrebbe essere vero, ma per me "linea-aggiornamento" di figure funziona solo con alcuni backend, in particolare wx. Potresti semplicemente provare a passare a questo, ad es. avviando ipython/pylab per ipython --pylab=wx! In bocca al lupo!

+1

Grazie per il tuo messaggio, non ho mai usato la modalità interattiva perché non ha mai funzionato con il backend predefinito che ho usato. È molto più bello usare la modalità interattiva che fermare l'esecuzione ogni volta che vuoi vedere un grafico! – PierreE

+0

Nessuna delle altre risposte ha aiutato nel mio caso. Sto usando pycharm e il problema era con il tracciamento e l'interattività della console. Ho dovuto aggiungere Da pylab import * e poi ion() nel corpo del codice per attivare l'interattivo. Adesso funziona senza problemi per me. – shev72

8

Nel caso qualcuno si imbatte in questo articolo alla ricerca di ciò che stavo cercando, ho trovato esempi a

How to visualize scalar 2D data with Matplotlib?

e

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

poi modificati per utilizzare imshow con una input stack di frame, invece di generare e utilizzare i contorni al volo.


Partendo da una serie di immagini in 3D di forma (nBins, nBins, nBins), chiamato 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) 

Ho anche trovato un modo molto più semplice per andare su tutto questo processo, anche se meno robusto:

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 

Nota che entrambi questi sembrano funzionare solo con ipython --pylab=tk, alias backend = TkAgg

Grazie per l'aiuto con tutto.

5

Ho rilasciato un pacchetto chiamato python-drawnow che fornisce funzionalità per consentire l'aggiornamento di una figura, in genere denominata all'interno di un ciclo for, simile a drawnow di Matlab.

Un esempio d'uso:

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) 

Questo pacchetto funziona con qualsiasi figura matplotlib e fornisce opzioni di attesa dopo ogni aggiornamento figura o cadere nel debugger.

+1

Com'è robusto e instabile allo stesso tempo? – BlueMoon93

+1

Intendevo robusto come in "funziona con qualsiasi figura di matplotlib" e instabile come nel "progetto del fine settimana". Ho aggiornato la mia risposta – Scott

12

Questo ha funzionato per me. Richiama ripetutamente una funzione aggiornando il grafico ogni volta.

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" è una funzione che restituisce un numero intero. FuncAnimation chiamerà ripetutamente "update", eseguirà "xmax" volte.

+0

Puoi dare un esempio su come si chiama questa funzione (specialmente come si passa una funzione in una chiamata di funzione) e come appare la funzione fun()? – bjornasm

+1

Sicuro. "fun()" è una funzione che restituisce un intero. È possibile passare la funzione come argomento ad un'altra come questa: "plot_cont (my_function, 123)". Ci avete chiamarmi plot_cont alla linea 86: https://github.com/vitobasso/audio-ml/blob/bbb3f633ef3638406912d6f75a8c6a7311aea3fc/src/train_spec.py – Vituel

-1
import csv 
import sys 
import getopt 
import socket 
import time 
import numpy as np 
import matplotlib 
from scipy.misc import imread 
from matplotlib import pyplot as plt 
import warnings 
fig, ax = plt.subplots() 
ax.set_xlim(-158, 553) 
ax.set_ylim(-290, 733) 
im = plt.imread("") 
plt.imshow(img, zorder=0, extent=[0.5, 8.0, 1.0, 7.0]) 

fig.show() 
l_global=[] 
points=[] 
master_tag_csvlink='c:/logfolde.log.csv' 
csvfile=open(master_tag_csvlink, 'r') 
for ainfo in csvfile: 
     line= ainfo 
     l_list= list(line.split('_')) 
     l_local=[] 
     for i in range(int(l_list[0])): 
      l_local.append(list(l_list[i+1].split(','))) 
     function1= lambda x,i: x[i] # return list[n,X] of elements at x 
     c= lambda x,l: [x for i in range(l) if True] 
     for i in range(len(l_local)): 
      l_local[i][1],l_local[i][2]=int(l_local[i][1]),int(l_local[i][2]) 

     if l_global: #In begining l_glocal is empty, so just copy the data in to l_global 
      l_global=l_local[:] 
      for i in range(len(l_global)): 
       points.append(plt.plot(function1(l_global[i],1),function1(l_global[i],2),'g',label="Tag:%s, X:%f, y: %f"%(function1(l_global[i],0),function1(l_global[i],1),function1(l_global[i],2)))) 



     else: # compare the l_local & l_global for any updates 
      tag_Id=map(function1,l_local,c(0,len(l_local))) #list of list of tagId,x,y TagId is filtered - local 
      mTag_Id=map(fuction1,l_global,c(0,len(l_global))) #list of list of tagId,x,y TagId is filtered - master 

      for i in mTag_Id: 
       if i not in tag_Id: #comparing master tags and tag_Id's 
        index=mTag_Id.index(i) ############### Tags in master list but not in Tag_id 
        copy_point=l_global[index] 
        [removing_point]=points[index]######## means tag is in-active ,turn tag color into red 
        removing_point.remove() 
        del points[index] 

        points.insert(index,plt.plot(function1(l_global[index],1),function1(l_global[index],2),'r',label="Tag:%s, X:%f, y: %f"%(function1(l_global[i],0),function1(l_global[i],1),function1(l_global[i],2)))) 

       elif i in tag_Id: # append the tag into l_global 
        index=mTag_Id.index(i) ############### Tags in master list but not in Tag_id 
        l_global[index]=l_local[index][:] 
        [removing_point]=points[index]######## means tag is active update coordinates 
        removing_point.remove() 
        del points[index] 
        points.insert(index,plt.plot(function1(l_global[index],1),function1(l_global[index],2),'g',label="Tag:%s, X:%f, y: %f"%(function1(l_global[i],0),function1(l_global[i],1),function1(l_global[i],2)))) 
      for i in Tag_Id: 
       if i not in mTag_Id: 
        index=Tag_Id(i) 
        l_global.append(l_local[index]] 
        points.append(plt.plot(function1(l_global[-1],1),function1(l_global[-1],2),'g',label="Tag:%s, X:%f, y: %f"%(function1(l_global[i],0),function1(l_global[i],1),function1(l_global[i],2)))) 

# 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(11)1 
# 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() 
+0

Questo aggiunge nulla ai cinque risposte che sono stati pubblicati già ? In tal caso, suggerirei di modificarlo per ridurre il codice al minimo necessario per dimostrarlo. Benvenuto nel sito, a proposito. – user2699

Problemi correlati