Matplotlib'de bir arsa nasıl güncellenir?


156

Buradaki rakamı yeniden çizmeyle ilgili sorunlar yaşıyorum. Kullanıcının zaman ölçeğinde (x ekseni) birimleri belirtmesine izin veriyorum ve sonra yeniden hesaplayıp bu işlevi çağırıyorum plots(). Grafiğin basitçe güncellenmesini istiyorum, şekle başka bir grafik eklemem.

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)

Yanıtlar:


178

Temel olarak iki seçeneğiniz vardır:

  1. Şu anda tam olarak ne yaptığınızı yapın, ancak verileri yeniden kaydetmeden önce graph1.clear()ve arayın graph2.clear(). Bu en yavaş, ancak en basit ve en sağlam seçenektir.

  2. Yeniden çizmek yerine, çizim nesnelerinin verilerini güncelleyebilirsiniz. Kodunuzda bazı değişiklikler yapmanız gerekecek, ancak bu her seferinde bir şeyleri yeniden yazmaktan çok, çok daha hızlı olmalıdır. Ancak, çizdiğiniz verilerin şekli değişemez ve verilerinizin aralığı değişiyorsa, x ve y ekseni sınırlarını manuel olarak sıfırlamanız gerekir.

İkinci seçeneğe bir örnek vermek için:

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

"1" i test etmeyi denedim. ve sonuç, verileri yeniden kaydettikten sonra GUI'mde başka bir dizi grafik çizildi, bu yüzden şimdi, daha önce olduğu gibi, yeniden hesaplamadan sonra 4 çizimim vardı.
sonra

@thenickname - Kodunuzun tam olarak neresini cleararıyorsunuz? Dönmeden önce, döngünüzün graph1.clear(); graph2.clear()içinde arama yapmalısınız , vb ...forgraph1.plot(...)graph2.plot(...)
Joe Kington

Bu döngü için N kere callx graphlot.plot (...) oluşturur ve açık ifadeleri oraya koymak sonuncuyu çizer. Aslında tuval kodunu çıkardım ve şekil kodu ile birlikte ana program döngüsüne koydum ve şimdi bir düğme tarafından çağrıldığım işlevim var. Herhangi bir nedenle sadece fonksiyonu çağırırsam araziler güncellenir, ancak düğmeye basarsam grafikler çizilmez. Oldukça ilginç bir davranış. Bunun Tkinter'de bir hata olması gerektiğini düşünüyorum.
sonra

Sadece bir önsezi ... Bir aramayı kaçırıyor musunuz fig.canvas.draw()veya plt.draw()her kareyi çizdikten sonra mı? (Yani sen bir dizi olmalı clear, plot, drawher seferinde bir kare göstermek istiyorum) ben tahmin ediyorum, ama bu tam olarak davranışı Tarif ettiğiniz ... İyi şanslar, herhangi bir oranda neden olur düşünün!
Joe Kington

3
2k14 ve böyle bir şey elde etmek için tökezledi ... beklendiği gibi çalışıyor ama çizim penceresi "yanıt değil" dönüyor .. herhangi bir öneri ??
DevC

39

Ayrıca aşağıdakileri de yapabilirsiniz: Bu, for döngüsünün 50 döngüsü için arsa üzerine 10x1 rasgele matris verisi çizer.

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

Bu bir grafik çıktı gibi görünmüyor. Bir şey mi kaçırıyorum? Ben %matplotlib inlinede Jupyter defterindeki.
MasayoMusic

haha, kaldırdığımda benim için çalıştı plt.clf(). Ah matplotlib, sen rezil :)
AndyP

15

Bu benim için çalıştı. Grafiği her seferinde güncelleyen bir işlevi tekrar tekrar çağırır.

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" bir tamsayı döndüren bir fonksiyondur. FuncAnimation tekrar tekrar "update" olarak adlandırır, "xmax" kez yapar.


Bu işlevi nasıl çağırdığınıza (özellikle bir işlev çağrısında bir işlevi nasıl geçirdiğinize) ve fun () işlevinin nasıl göründüğüne bir örnek verebilir misiniz?
Ocak 15

1
Elbette. "fun ()" bir tamsayı döndüren herhangi bir işlevdir. İşlevi böyle bir başkasına argüman olarak iletebilirsiniz: "plot_cont (my_function, 123)". Orada beni 86 numaralı hattan plot_cont çağırıyorsunuz: github.com/vitobasso/audio-ml/blob/…
Vituel

1
"A =" işaretinin gerekli olduğunu veya FuncAnimation öğesinin çöp toplanacağını ve kodun çalışmayacağını unutmayın!
Kiuhnm

8

Aradığım şeyi arayan birinin bu makaleyle karşılaşması durumunda,

Matplotlib ile skaler 2D verileri nasıl görselleştirebilirim?

ve

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

daha sonra bunları, konturları anında oluşturmak ve kullanmak yerine imshow'u bir çerçeve giriş yığını ile kullanmak üzere değiştirdi.


3D görüntü dizisi ile başlayarak (nBins, nBins, nBins) denir 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)

Ayrıca, daha az sağlam da olsa, tüm bu süreç hakkında daha basit bir yol buldum:

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

Bunların her ikisi de sadece çalışmak gibi görünüyor Not ipython --pylab=tkakabackend = TkAgg

Her şeyle ilgili yardım için teşekkürler.


6

Matlab'ınkine benzer şekilde genellikle for döngüsü içinde çağrılan bir şekil güncellemesine izin veren işlevsellik sağlayan python-drawnow adlı bir paket yayınladım drawnow.

Örnek bir kullanım:

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)

Bu paket, herhangi bir matplotlib figürüyle çalışır ve her şekil güncellemesinden veya hata ayıklayıcıya bırakıldıktan sonra beklemek için seçenekler sunar.


2
Aynı zamanda nasıl sağlam ve kararsız?
BlueMoon93

2
"Herhangi bir matplotlib figürüyle çalışıyor" gibi sağlam ve "hafta sonu projesi" nde olduğu gibi istikrarsız demek istedim. Cevabımı güncelledim
Scott

3

Yukarıdakilerin hepsi doğru olabilir, ancak benim için rakamların "çevrimiçi güncellenmesi" sadece bazı arka uçlarla, özellikle çalışır wx. Bunu değiştirmeye çalışabilirsiniz, örneğin ipython / pylab by ipython --pylab=wx! İyi şanslar!


1
Mesajınız için teşekkür ederim, etkileşimli modu hiç kullanmadım çünkü kullandığım varsayılan arka uçla hiç çalışmadı. Etkileşimli modu kullanmak, her grafik görmek istediğinizde yürütmeyi durdurmaktan çok daha iyidir!
PierreE

1
Diğer cevapların hiçbiri benim durumumda yardımcı olmadı. Pycharm kullanıyorum ve sorun konsolun çizimi ve etkileşimi ile ilgiliydi. Ben interaktif açmak için kod gövdesinde pylab ithalat * ve sonra iyon () eklemek gerekiyordu. Şimdi benim için sorunsuz çalışıyor.
shelbypereira

2

Bu benim için çalıştı:

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()
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.