如何在matplotlib中更新图?


156

我在这里重新绘制图形时遇到问题。我允许用户在时间刻度(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)

Answers:


178

您基本上有两个选择:

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

我尝试测试“ 1”。结果是,在我重新绘制数据之后,在我的GUI中绘制了另一组图,所以现在像以前一样,在重新计算后我有了4个图。
昵称,2010年

@thenickname-您在代码中的确切位置clear?您应该graph1.clear(); graph2.clear()for循环内调用,就在调用之前graph1.plot(...)graph2.plot(...)等等...
Joe Kington

该for循环会创建N次调用graphx.plot(...)的调用,并在其中放置clear语句只会绘制最后一个。实际上,我已经拉出了画布代码,并将其与图形代码一起放入了主程序循环中,现在我的功能由一个按钮调用。由于某种原因,如果我仅调用该函数,则绘图会更新,但是如果按按钮,则绘图不会更新。这是非常有趣的行为。我认为这一定是Tkinter中的错误。
昵称,2010年

只是预感...您是错过电话fig.canvas.draw()还是plt.draw()在绘制每个帧之后?(即,每次要显示框架时clear,您都应该有一个,序列),但是我认为这将完全导致您所描述的行为……祝您好运,无论如何!plotdraw
乔·

3
现在是2k14,我偶然发现要达到这样的效果……它按预期工作,但绘图窗口正在“无响应” ..有任何建议吗?
DevC

39

您还可以执行以下操作:这将在for循环的50个循环的绘图上绘制10x1随机矩阵数据。

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

这似乎没有输出图形。我想念什么吗?我也有%matplotlib inlineJupyter笔记本。
MasayoMusic,

哈哈,当我卸下时为我工作plt.clf()。哦matplotlib,你这很无赖:)
AndyP '19

15

这对我有用。每次重复调用更新图形的函数。

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”次。


您能否举一个例子,说明如何调用此函数(特别是如何在函数调用中传递函数)以及fun()函数的外观?
bjornasm

1
当然。“ fun()”是任何返回整数的函数。您可以像下面这样将函数作为参数传递给另一个:“ plot_cont(my_function,123)”。有你有我在行86调用plot_cont:github.com/vitobasso/audio-ml/blob/...
Vituel

1
请注意,“ a =”是必需的,否则FuncAnimation将被垃圾回收,并且代码将无法工作!
Kiuhnm

8

如果有人碰到本文来寻找我想要的东西,我在

如何使用Matplotlib可视化标量2D数据?

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

然后对其进行修改,以将imshow与输入的帧堆栈一起使用,而不是动态生成和使用轮廓。


从3D形状的图像阵列(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=tkbackend = TkAgg

感谢您提供的所有帮助。


6

我发布了一个名为python-drawnow的软件包,该软件包提供了使图形更新的功能(通常在for循环内调用),类似于Matlab的drawnow

用法示例:

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图形,并提供了在每个图形更新或放入调试器后等待的选项。


2
它如何同时健壮和不稳定?
BlueMoon93

2
我的意思是像在“使用任何matplotlib图形工作”中一样健壮,而像“周末项目”中那样不稳定。我更新了答案
斯科特(Scott)

3

以上所有内容可能都是正确的,但是对我来说,“在线更新”数字仅适用于某些后端wx。您可能只是想尝试更改为该值,例如通过启动ipython / pylab ipython --pylab=wx!祝好运!


1
感谢您的留言,我从未使用过交互模式,因为它从未与我使用的默认后端一起使用。使用交互模式比每次想要查看图形都停止执行要好得多!
PierreE

1
在我的情况下,其他答案均无济于事。我正在使用pycharm,问题出在控制台的绘图和交互性上。我需要在代码主体中添加From pylab import *,然后添加ion()来启用交互。现在,它对我来说很顺利。
shelbypereira

2

这对我有用:

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()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.