我正在尝试使用OpenCV实时绘制来自摄像机的一些数据。但是,实时绘图(使用matplotlib)似乎不能正常工作。

我把这个问题隔离在这个简单的例子中:

fig = plt.figure()
plt.axis([0, 1000, 0, 1])

i = 0
x = list()
y = list()

while i < 1000:
    temp_y = np.random.random()
    x.append(i)
    y.append(temp_y)
    plt.scatter(i, temp_y)
    i += 1
    plt.show()

我希望这个例子能分别画出1000个点。实际发生的情况是,窗口弹出,显示第一个点(好吧),然后等待循环结束,然后填充图的其余部分。

有什么想法,为什么我没有看到点填充一个时间?


当前回答

如果你想要绘制而不是在绘制更多点时冻结线程,你应该使用plt.pause()而不是time.sleep()

我使用下面的代码来绘制一系列的xy坐标。

import matplotlib.pyplot as plt 
import math


pi = 3.14159

fig, ax = plt.subplots()

x = []
y = []

def PointsInCircum(r,n=20):
    circle = [(math.cos(2*pi/n*x)*r,math.sin(2*pi/n*x)*r) for x in xrange(0,n+1)]
    return circle

circle_list = PointsInCircum(3, 50)

for t in range(len(circle_list)):
    if t == 0:
        points, = ax.plot(x, y, marker='o', linestyle='--')
        ax.set_xlim(-4, 4) 
        ax.set_ylim(-4, 4) 
    else:
        x_coord, y_coord = circle_list.pop()
        x.append(x_coord)
        y.append(y_coord)
        points.set_data(x, y)
    plt.pause(0.01)

其他回答

如果你想要绘制而不是在绘制更多点时冻结线程,你应该使用plt.pause()而不是time.sleep()

我使用下面的代码来绘制一系列的xy坐标。

import matplotlib.pyplot as plt 
import math


pi = 3.14159

fig, ax = plt.subplots()

x = []
y = []

def PointsInCircum(r,n=20):
    circle = [(math.cos(2*pi/n*x)*r,math.sin(2*pi/n*x)*r) for x in xrange(0,n+1)]
    return circle

circle_list = PointsInCircum(3, 50)

for t in range(len(circle_list)):
    if t == 0:
        points, = ax.plot(x, y, marker='o', linestyle='--')
        ax.set_xlim(-4, 4) 
        ax.set_ylim(-4, 4) 
    else:
        x_coord, y_coord = circle_list.pop()
        x.append(x_coord)
        y.append(y_coord)
        points.set_data(x, y)
    plt.pause(0.01)

下面是问题代码的工作版本(至少需要2011年11月14日的Matplotlib 1.1.0版本):

import numpy as np
import matplotlib.pyplot as plt

plt.axis([0, 10, 0, 1])

for i in range(10):
    y = np.random.random()
    plt.scatter(i, y)
    plt.pause(0.05)

plt.show()

请注意对plt.pause(0.05)的调用,它既绘制新数据,又运行GUI的事件循环(允许鼠标交互)。

表演可能不是最好的选择。我要做的是使用pyplot.draw()代替。您还可能希望在循环中包含一个小的时间延迟(例如,time.sleep(0.05)),以便您可以看到情节的发生。如果我对你的例子做这些改变,它对我有用,我看到每个点一次出现一个。

带有保留线条风格的圆形缓冲区的活动情节:

import os
import time
import psutil
import collections

import matplotlib.pyplot as plt

pts_n = 100
x = collections.deque(maxlen=pts_n)
y = collections.deque(maxlen=pts_n)
(line, ) = plt.plot(x, y, linestyle="--")

my_process = psutil.Process(os.getpid())
t_start = time.time()
while True:
    x.append(time.time() - t_start)
    y.append(my_process.cpu_percent())

    line.set_xdata(x)
    line.set_ydata(y)
    plt.gca().relim()
    plt.gca().autoscale_view()
    plt.pause(0.1)

问题似乎是您希望plot .show()显示窗口,然后返回。它不会那样做。程序将在此时停止,只有在您关闭该窗口后才恢复。您应该能够测试这一点:如果您关闭窗口,然后另一个窗口将弹出。

要解决这个问题,只需在循环之后调用一次plt.show()。然后你就得到了完整的情节。(但不是“实时绘图”)

你可以尝试像这样设置关键字参数块:plt.show(block=False)在开始时,然后使用.draw()来更新。