Python 如何更新 matplotlib 中的绘图?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4098131/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 14:15:18  来源:igfitidea点击:

How to update a plot in matplotlib?

pythonmatplotlibtkinter

提问by thenickname

I'm having issues with redrawing the figure here. I allow the user to specify the units in the time scale (x-axis) and then I recalculate and call this function plots(). I want the plot to simply update, not append another plot to the figure.

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

采纳答案by Joe Kington

You essentially have two options:

您基本上有两个选择:

  1. Do exactly what you're currently doing, but call graph1.clear()and graph2.clear()before replotting the data. This is the slowest, but most simplest and most robust option.

  2. Instead of replotting, you can just update the data of the plot objects. You'll need to make some changes in your code, but this should be much, much faster than replotting things every time. However, the shape of the data that you're plotting can't change, and if the range of your data is changing, you'll need to manually reset the x and y axis limits.

  1. 完全按照您目前正在做的事情做,但在重新绘制数据之前调用graph1.clear()graph2.clear()。这是最慢但最简单和最强大的选项。

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

To give an example of the second option:

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

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

回答by jkeyser

All of the above might be true, however for me "online-updating" of figures only works with some backends, specifically wx. You just might try to change to this, e.g. by starting ipython/pylab by ipython --pylab=wx! Good luck!

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

回答by CavemanPhD

In case anyone comes across this article looking for what I was looking for, I found examples at

万一有人看到这篇文章寻找我想要的东西,我在

How to visualize scalar 2D data with Matplotlib?

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

and

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

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

then modified them to use imshow with an input stack of frames, instead of generating and using contours on the fly.

然后修改它们以将 imshow 与输入的帧堆栈一起使用,而不是即时生成和使用轮廓。



Starting with a 3D array of images of shape (nBins, nBins, nBins), called frames.

从形状(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)

I also found a much simpler way to go about this whole process, albeit less robust:

我还找到了一种更简单的方法来完成整个过程,尽管不那么健壮:

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

Note that both of these only seem to work with ipython --pylab=tk, a.k.a.backend = TkAgg

请注意,这两个似乎只适用于ipython --pylab=tk,也就是backend = TkAgg

Thank you for the help with everything.

感谢您对一切的帮助。

回答by Scott

I have released a package called python-drawnowthat provides functionality to let a figure update, typically called within a for loop, similar to Matlab's drawnow.

我发布了一个名为python-drawnow的包,它提供了让图形更新的功能,通常在 for 循环中调用,类似于 Matlab 的drawnow.

An example usage:

示例用法:

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)

This package works with any matplotlib figure and provides options to wait after each figure update or drop into the debugger.

此包适用于任何 matplotlib 图,并提供在每次图更新后等待或放入调试器的选项。

回答by Vituel

This worked for me. Repeatedly calls a function updating the graph every time.

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

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" is a function that returns an integer. FuncAnimation will repeatedly call "update", it will do that "xmax" times.

“fun”是一个返回整数的函数。FuncAnimation 会反复调用“更新”,它会执行“xmax”次。

回答by Arindam

You can also do like the following: This will draw a 10x1 random matrix data on the plot for 50 cycles of the for loop.

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

回答by Julian

This worked for me:

这对我有用:

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