How do I plot in real-time in a while loop using m

2018-12-31 05:42发布

I am trying to plot some data from a camera in real time using OpenCV. However, the real-time plotting (using matplotlib) doesn't seem to be working.

I've isolated the problem into this simple example:

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

I would expect this example to plot 1000 points individually. What actually happens is that the window pops up with the first point showing (ok with that), then waits for the loop to finish before it populates the rest of the graph.

Any thoughts why I am not seeing points populated one at a time?

10条回答
刘海飞了
2楼-- · 2018-12-31 06:29

The problem seems to be that you expect plt.show() to show the window and then to return. It does not do that. The program will stop at that point and only resume once you close the window. You should be able to test that: If you close the window and then another window should pop up.

To resolve that problem just call plt.show() once after your loop. Then you get the complete plot. (But not a 'real-time plotting')

You can try setting the keyword-argument block like this: plt.show(block=False) once at the beginning and then use .draw() to update.

查看更多
一个人的天荒地老
3楼-- · 2018-12-31 06:31

None of the methods worked for me. But I have found this Real time matplotlib plot is not working while still in a loop

All you need is to add

plt.pause(0.0001)

and than you could see the new plot.

So your code should look like this, and it will work

import matplotlib.pyplot as plt
import numpy as np
plt.ion() ## Note this correction
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()
    plt.pause(0.0001) #Note this correction
查看更多
萌妹纸的霸气范
4楼-- · 2018-12-31 06:33

I know this question is old, but there's now a package available called drawnow on GitHub as "python-drawnow". This provides an interface similar to MATLAB's drawnow -- you can easily update a figure.

An example for your use case:

import matplotlib.pyplot as plt
from drawnow import drawnow

def make_fig():
    plt.scatter(x, y)  # I think you meant this

plt.ion()  # enable interactivity
fig = plt.figure()  # make a figure

x = list()
y = list()

for i in range(1000):
    temp_y = np.random.random()
    x.append(i)
    y.append(temp_y)  # or any arbitrary update to your figure's data
    i += 1
    drawnow(make_fig)

python-drawnow is a thin wrapper around plt.draw but provides the ability to confirm (or debug) after figure display.

查看更多
骚的不知所云
5楼-- · 2018-12-31 06:36

If you're interested in realtime plotting, I'd recommend looking into matplotlib's animation API. In particular, using blit to avoid redrawing the background on every frame can give you substantial speed gains (~10x):

#!/usr/bin/env python

import numpy as np
import time
import matplotlib
matplotlib.use('GTKAgg')
from matplotlib import pyplot as plt


def randomwalk(dims=(256, 256), n=20, sigma=5, alpha=0.95, seed=1):
    """ A simple random walk with memory """

    r, c = dims
    gen = np.random.RandomState(seed)
    pos = gen.rand(2, n) * ((r,), (c,))
    old_delta = gen.randn(2, n) * sigma

    while True:
        delta = (1. - alpha) * gen.randn(2, n) * sigma + alpha * old_delta
        pos += delta
        for ii in xrange(n):
            if not (0. <= pos[0, ii] < r):
                pos[0, ii] = abs(pos[0, ii] % r)
            if not (0. <= pos[1, ii] < c):
                pos[1, ii] = abs(pos[1, ii] % c)
        old_delta = delta
        yield pos


def run(niter=1000, doblit=True):
    """
    Display the simulation using matplotlib, optionally using blit for speed
    """

    fig, ax = plt.subplots(1, 1)
    ax.set_aspect('equal')
    ax.set_xlim(0, 255)
    ax.set_ylim(0, 255)
    ax.hold(True)
    rw = randomwalk()
    x, y = rw.next()

    plt.show(False)
    plt.draw()

    if doblit:
        # cache the background
        background = fig.canvas.copy_from_bbox(ax.bbox)

    points = ax.plot(x, y, 'o')[0]
    tic = time.time()

    for ii in xrange(niter):

        # update the xy data
        x, y = rw.next()
        points.set_data(x, y)

        if doblit:
            # restore background
            fig.canvas.restore_region(background)

            # redraw just the points
            ax.draw_artist(points)

            # fill in the axes rectangle
            fig.canvas.blit(ax.bbox)

        else:
            # redraw everything
            fig.canvas.draw()

    plt.close(fig)
    print "Blit = %s, average FPS: %.2f" % (
        str(doblit), niter / (time.time() - tic))

if __name__ == '__main__':
    run(doblit=False)
    run(doblit=True)

Output:

Blit = False, average FPS: 54.37
Blit = True, average FPS: 438.27
查看更多
萌妹纸的霸气范
6楼-- · 2018-12-31 06:37

Here's the working version of the code in question (requires at least version Matplotlib 1.1.0 from 2011-11-14):

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

Note some of the changes:

  1. Call plt.pause(0.05) to both draw the new data and it runs the GUI's event loop (allowing for mouse interaction).
查看更多
零度萤火
7楼-- · 2018-12-31 06:42

If you want draw and not freeze your thread as more point are drawn you should use plt.pause() not time.sleep()

im using the following code to plot a series of xy coordinates.

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)
查看更多
登录 后发表回答