如何在matplotlib中更新图?

时间:2010-11-04 15:15:46

标签: python matplotlib tkinter

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

8 个答案:

答案 0 :(得分:134)

你基本上有两个选择:

  1. 完全执行您当前正在执行的操作,但在重新绘制数据之前请调用graph1.clear()graph2.clear()。这是最慢,但最简单,最强大的选择。

  2. 您可以只更新绘图对象的数据,而不是重新绘制。您需要对代码进行一些更改,但这应该比每次重新绘制事物快得多。但是,您绘制的数据的形状无法更改,如果数据范围发生变化,则需要手动重置x和y轴限制。

  3. 举一个第二个选项的例子:

    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 :(得分:15)

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

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

答案 2 :(得分:13)

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

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

"乐趣"是一个返回整数的函数。 FuncAnimation会反复调用"更新"它会这样做" xmax"次。

答案 3 :(得分:8)

如果有人发现这篇文章正在寻找我想要的东西,我在

找到了例子

How to visualize scalar 2D data with Matplotlib?

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

然后修改它们以使用imshow与输入堆栈的帧,而不是动态生成和使用轮廓。


从形状(nBins,nBins,nBins)的3D图像数组开始,称为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

感谢您对所有事情的帮助。

答案 4 :(得分:5)

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

答案 5 :(得分:3)

以上所有情况都可能属实,但对我而言,“在线更新”数字仅适用于某些后端,特别是wx。您可能会尝试更改为此,例如通过ipython --pylab=wx启动ipython / pylab!祝你好运!

答案 6 :(得分:2)

根据其他答案,我将图形的更新包装在 python 装饰器中,以将绘图的更新机制与实际绘图分开。这样,更新任何情节就容易多了。

def plotlive(func):
    plt.ion()

    @functools.wraps(func)
    def new_func(*args, **kwargs):

        # Clear all axes in the current figure.
        axes = plt.gcf().get_axes()
        for axis in axes:
            axis.cla()

        # Call func to plot something
        result = func(*args, **kwargs)

        # Draw the plot
        plt.draw()
        plt.pause(0.01)

        return result

    return new_func 

使用示例

然后你就可以像其他装饰器一样使用它了。

@plotlive
def plot_something_live(ax, x, y):
    ax.plot(x, y)
    ax.set_ylim([0, 100])

唯一的限制是您必须在循环之前创建图形:

fig, ax = plt.subplots()
for i in range(100):
    x = np.arange(100)
    y = np.full([100], fill_value=i)
    plot_something_live(ax, x, y)

答案 7 :(得分:0)

这对我有用:

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