【问题标题】:How to update a plot in matplotlib如何更新 matplotlib 中的绘图
【发布时间】:2011-05-05 03:07:56
【问题描述】:

我在此处重绘图形时遇到问题。我允许用户指定时间刻度(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)

【问题讨论】:

标签: python matplotlib tkinter


【解决方案1】:

你基本上有两个选择:

  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 个图,就像以前一样。
  • @thenickname - 您在代码中的哪个位置调用clear?你应该在你的for循环中调用graph1.clear(); graph2.clear(),就在你调用graph1.plot(...)graph2.plot(...)等之前......
  • for 循环会创建调用 graphx.plot(...) N 次,并且将清晰的语句放在那里只绘制最后一个。我实际上已经提取了画布代码并将其与图形代码一起放入主程序循环中,现在我的函数被一个按钮调用了。出于某种原因,如果我只是调用该函数,绘图会得到更新,但如果我按下按钮,绘图不会。这是非常有趣的行为。我认为这一定是 Tkinter 中的一个错误。
  • 现在是 2k14,我偶然发现了这样的事情......它按预期工作,但绘图窗口变成“没有响应”......有什么建议吗??
  • 在 2020 年使用 mpl 3.3.1 不幸的是,这不起作用。可以依赖后端吗?
【解决方案2】:

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

【讨论】:

  • 感谢您的留言,我从未使用过交互模式,因为它从未与我使用的默认后端一起使用。使用交互模式比每次想要查看图表时停止执行要好得多!
  • 在我的情况下,其他答案都没有帮助。我正在使用 pycharm,问题在于控制台的绘图和交互性。我需要在代码主体中添加 From pylab import * 然后 ion() 以打开交互。它现在对我来说很顺利。
【解决方案3】:

如果有人看到这篇文章来寻找我正在寻找的东西,我在

上找到了示例

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 与帧的输入堆栈一起使用,而不是动态生成和使用轮廓。


从名为frames 的形状(nBins、nBins、nBins)图像的 3D 数组开始。

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,也就是backend = TkAgg

感谢您对一切的帮助。

【讨论】:

    【解决方案4】:

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

    【讨论】:

    • 它如何同时健壮和不稳定?
    • 我的意思是“与任何 matplotlib 图形一起工作”中的健壮和“周末项目”中的不稳定。我已经更新了答案
    【解决方案5】:

    这对我有用。重复调用一个函数,每次更新图。

    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 会重复调用“update”,它会执行“xmax”次。

    【讨论】:

    • 你能举个例子说明你如何调用这个函数(尤其是你如何在函数调用中传递一个函数)以及 fun() 函数的样子吗?
    • 当然。 “fun()”是任何返回整数的函数。您可以将函数作为参数传递给另一个函数,如下所示:“plot_cont(my_function, 123)”。你让我在第 86 行调用 plot_cont:github.com/vitobasso/audio-ml/blob/…
    • 请注意,“a =”是必需的,否则 FuncAnimation 将被垃圾回收,代码将无法工作!
    【解决方案6】:

    您还可以执行以下操作: 这将在 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()
    

    【讨论】:

    • 这似乎没有输出图表。我错过了什么吗?我在 Jupyter 笔记本中也有 %matplotlib inline
    • 哈哈,当我删除 plt.clf() 时为我工作。哦matplotlib,你这个无赖:)
    • 但这不是更新一个情节!它绘制了 50 个地块!
    • 这没有回答问题,只是绘制并清除了 50 次。被警告!
    【解决方案7】:

    这对我有用:

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

    【讨论】:

    • 您的回答正是我所需要的。谢谢!
    • Jupyter notebook 的完美解决方案
    • 它只适用于 Jupyter notebook
    【解决方案8】:

    根据其他答案,我将图形的更新包装在 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)
    

    【讨论】:

      猜你喜欢
      • 2011-03-31
      • 2022-08-13
      • 1970-01-01
      • 2011-07-06
      • 2015-10-02
      • 2012-06-12
      相关资源
      最近更新 更多