Как обновить сюжет в matplotlib? - PullRequest
119 голосов
/ 04 ноября 2010

У меня проблемы с перерисовкой рисунка здесь. Я позволяю пользователю указать единицы измерения во временной шкале (ось X), а затем я пересчитываю и вызываю эту функцию plots(). Я хочу, чтобы сюжет просто обновлялся, а не добавлялся к рисунку.

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)

Ответы [ 6 ]

140 голосов
/ 04 ноября 2010

У вас есть два варианта:

  1. Делайте в точности то, что вы делаете в настоящее время, но позвоните graph1.clear() и graph2.clear() перед повторным размещением данных. Это самый медленный, но самый простой и надежный вариант.

  2. Вместо повторной печати вы можете просто обновить данные объектов графика. Вам нужно будет внести некоторые изменения в ваш код, но это должно быть намного, намного быстрее, чем каждый раз повторять реплоты. Однако форма данных, которые вы выводите, не может измениться, и если диапазон ваших данных меняется, вам нужно вручную сбросить пределы по осям x и y.

Чтобы привести пример второго варианта:

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()
19 голосов
/ 21 марта 2018

Вы также можете сделать следующее: Это нарисует случайные матричные данные 10x1 на графике для 50 циклов цикла 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()
14 голосов
/ 24 января 2015

Это сработало для меня. Неоднократно вызывает функцию, обновляющую график каждый раз.

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» - это функция, которая возвращает целое число. FuncAnimation будет неоднократно вызывать «обновление», он будет делать это «xmax» раз.

8 голосов
/ 21 апреля 2012

В случае, если кто-нибудь сталкивается с этой статьей в поисках того, что я искал, я нашел примеры на

Как визуализировать скалярные 2D-данные с помощью Matplotlib?

и

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

затем изменил их, чтобы использовать imshow со входным стеком кадров вместо генерации и использования контуров на лету.


Начиная с трехмерного массива изображений формы (nBins, nBins, nBins), называемого 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)

Я также нашел гораздо более простой способ выполнить весь этот процесс, хотя и менее надежный:

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

Обратите внимание, что оба они работают только с ipython --pylab=tk, a.k.a. backend = TkAgg

Спасибо за помощь во всем.

5 голосов
/ 08 сентября 2014

Я выпустил пакет под названием python-drawnow , который обеспечивает функциональность, позволяющую обновлять фигуру, обычно вызываемую в цикле for, аналогично drawnow.

в Matlab. Пример использования:

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)

Этот пакет работает с любой фигурой matplotlib и предоставляет опции для ожидания после каждого обновления фигуры или перехода в отладчик.

3 голосов
/ 17 апреля 2012

Все вышеперечисленное может быть правдой, однако для меня «онлайн-обновление» фигур работает только с некоторыми бэкэндами, в частности wx.Вы можете попытаться изменить это, например, запустив ipython / pylab с помощью ipython --pylab=wx!Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...