如何使用matplotlib在while循环中实时绘制?


233

我正在尝试使用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点。实际发生的是,窗口弹出并显示第一个点(表示正确),然后等待循环结束,然后再填充图的其余部分。

有什么想法为什么我一次看不到点呢?

Answers:


312

这是有问题的代码的工作版本(至少需要从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()

注意一些更改:

  1. 调用plt.pause(0.05)均绘制新数据,并运行GUI的事件循环(允许鼠标交互)。

3
这在Python2中对我有用。在Python3中没有。渲染绘图窗口后,它将暂停循环。但是在将plt.show()方法移动到循环之后之后……对我来说,它已为Python3解决了。
Continuousqa

1
很奇怪,在Python 3(版本3.4.0),Matplotlib(版本1.3.1),Numpy(版本1.8.1),Ubuntu Linux 3.13.0(64位)中为我工作得很好
2014年

37
而不是plt.show()和plt.draw()只是将plt.draw()替换为plt.pause(0.1)
denfromufa 2014年

4
在Win64 / Anaconda matplotlib .__ version__ 1.5.0上不起作用。初始图形窗口已打开,但未显示任何内容,直到我关闭它之前,它一直处于阻塞状态
isti_spl 2016年

5
这个答案需要先验知识x / y数据...这不是必需的:我更喜欢1.不要调用plt.axis(),而是创建两个列表x和y并调用plt.plot(x,y)2.在循环中,将新数据值附加到这两个列表3.致电plt.gca().lines[0].set_xdata(x); plt.gca().lines[0].set_ydata(y); plt.gca().relim(); plt.gca().autoscale_view(); plt.pause(0.05);
Trevor Boyd Smith

76

如果您对实时绘图感兴趣,建议您使用matplotlib的animation API。特别是,blit避免在每帧上绘制背景都会使您获得可观的速度提升(〜10倍):

#!/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)

输出:

Blit = False, average FPS: 54.37
Blit = True, average FPS: 438.27

1
@bejota原始版本旨在在交互式matplotlib会话中工作。为了使其能够作为独立脚本工作,必须1)为matplotlib显式选择一个后端,以及2)在使用plt.show()和进入动画循环之前强制显示和绘制图形plt.draw()。我已将这些更改添加到上面的代码中。
ali_m 2015年

2
blit()看起来的意图/动机是否很可能是“改善实时绘图”?如果您有matplotlib开发人员/博客来讨论为什么/目的/意图/动机会很棒。(似乎这种新的blit操作会将Matplotlib从仅用于脱机或变化非常缓慢的数据转换为现在,您可以将Matplotlib与更新速度非常快的数据一起使用...几乎就像示波器一样)。
Trevor Boyd Smith

1
我发现这种方法使绘图窗口无响应:我无法与之交互,否则可能会使其崩溃。
Ninjakannon '16

1
对于那些遇到“未找到gtk”的问题,它可以在其他后端正常工作(我使用了“ TKAgg”)。为了找到一个支持的支持我用这个解决方案:stackoverflow.com/questions/3285193/...
詹姆斯尼尔森

1
该答案中的链接似乎不再起作用。这可能是最新链接:scipy-cookbook.readthedocs.io/items/…–
awelkie

35

我知道我回答这个问题有点晚了。不过,我前段时间已经编写了一些代码来绘制实时图形,我想分享一下:

PyQt4的代码:

###################################################################
#                                                                 #
#                    PLOT A LIVE GRAPH (PyQt4)                    #
#                  -----------------------------                  #
#            EMBED A MATPLOTLIB ANIMATION INSIDE YOUR             #
#            OWN GUI!                                             #
#                                                                 #
###################################################################


import sys
import os
from PyQt4 import QtGui
from PyQt4 import QtCore
import functools
import numpy as np
import random as rd
import matplotlib
matplotlib.use("Qt4Agg")
from matplotlib.figure import Figure
from matplotlib.animation import TimedAnimation
from matplotlib.lines import Line2D
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
import time
import threading


def setCustomSize(x, width, height):
    sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
    sizePolicy.setHorizontalStretch(0)
    sizePolicy.setVerticalStretch(0)
    sizePolicy.setHeightForWidth(x.sizePolicy().hasHeightForWidth())
    x.setSizePolicy(sizePolicy)
    x.setMinimumSize(QtCore.QSize(width, height))
    x.setMaximumSize(QtCore.QSize(width, height))

''''''

class CustomMainWindow(QtGui.QMainWindow):

    def __init__(self):

        super(CustomMainWindow, self).__init__()

        # Define the geometry of the main window
        self.setGeometry(300, 300, 800, 400)
        self.setWindowTitle("my first window")

        # Create FRAME_A
        self.FRAME_A = QtGui.QFrame(self)
        self.FRAME_A.setStyleSheet("QWidget { background-color: %s }" % QtGui.QColor(210,210,235,255).name())
        self.LAYOUT_A = QtGui.QGridLayout()
        self.FRAME_A.setLayout(self.LAYOUT_A)
        self.setCentralWidget(self.FRAME_A)

        # Place the zoom button
        self.zoomBtn = QtGui.QPushButton(text = 'zoom')
        setCustomSize(self.zoomBtn, 100, 50)
        self.zoomBtn.clicked.connect(self.zoomBtnAction)
        self.LAYOUT_A.addWidget(self.zoomBtn, *(0,0))

        # Place the matplotlib figure
        self.myFig = CustomFigCanvas()
        self.LAYOUT_A.addWidget(self.myFig, *(0,1))

        # Add the callbackfunc to ..
        myDataLoop = threading.Thread(name = 'myDataLoop', target = dataSendLoop, daemon = True, args = (self.addData_callbackFunc,))
        myDataLoop.start()

        self.show()

    ''''''


    def zoomBtnAction(self):
        print("zoom in")
        self.myFig.zoomIn(5)

    ''''''

    def addData_callbackFunc(self, value):
        # print("Add data: " + str(value))
        self.myFig.addData(value)



''' End Class '''


class CustomFigCanvas(FigureCanvas, TimedAnimation):

    def __init__(self):

        self.addedData = []
        print(matplotlib.__version__)

        # The data
        self.xlim = 200
        self.n = np.linspace(0, self.xlim - 1, self.xlim)
        a = []
        b = []
        a.append(2.0)
        a.append(4.0)
        a.append(2.0)
        b.append(4.0)
        b.append(3.0)
        b.append(4.0)
        self.y = (self.n * 0.0) + 50

        # The window
        self.fig = Figure(figsize=(5,5), dpi=100)
        self.ax1 = self.fig.add_subplot(111)


        # self.ax1 settings
        self.ax1.set_xlabel('time')
        self.ax1.set_ylabel('raw data')
        self.line1 = Line2D([], [], color='blue')
        self.line1_tail = Line2D([], [], color='red', linewidth=2)
        self.line1_head = Line2D([], [], color='red', marker='o', markeredgecolor='r')
        self.ax1.add_line(self.line1)
        self.ax1.add_line(self.line1_tail)
        self.ax1.add_line(self.line1_head)
        self.ax1.set_xlim(0, self.xlim - 1)
        self.ax1.set_ylim(0, 100)


        FigureCanvas.__init__(self, self.fig)
        TimedAnimation.__init__(self, self.fig, interval = 50, blit = True)

    def new_frame_seq(self):
        return iter(range(self.n.size))

    def _init_draw(self):
        lines = [self.line1, self.line1_tail, self.line1_head]
        for l in lines:
            l.set_data([], [])

    def addData(self, value):
        self.addedData.append(value)

    def zoomIn(self, value):
        bottom = self.ax1.get_ylim()[0]
        top = self.ax1.get_ylim()[1]
        bottom += value
        top -= value
        self.ax1.set_ylim(bottom,top)
        self.draw()


    def _step(self, *args):
        # Extends the _step() method for the TimedAnimation class.
        try:
            TimedAnimation._step(self, *args)
        except Exception as e:
            self.abc += 1
            print(str(self.abc))
            TimedAnimation._stop(self)
            pass

    def _draw_frame(self, framedata):
        margin = 2
        while(len(self.addedData) > 0):
            self.y = np.roll(self.y, -1)
            self.y[-1] = self.addedData[0]
            del(self.addedData[0])


        self.line1.set_data(self.n[ 0 : self.n.size - margin ], self.y[ 0 : self.n.size - margin ])
        self.line1_tail.set_data(np.append(self.n[-10:-1 - margin], self.n[-1 - margin]), np.append(self.y[-10:-1 - margin], self.y[-1 - margin]))
        self.line1_head.set_data(self.n[-1 - margin], self.y[-1 - margin])
        self._drawn_artists = [self.line1, self.line1_tail, self.line1_head]

''' End Class '''

# You need to setup a signal slot mechanism, to 
# send data to your GUI in a thread-safe way.
# Believe me, if you don't do this right, things
# go very very wrong..
class Communicate(QtCore.QObject):
    data_signal = QtCore.pyqtSignal(float)

''' End Class '''


def dataSendLoop(addData_callbackFunc):
    # Setup the signal-slot mechanism.
    mySrc = Communicate()
    mySrc.data_signal.connect(addData_callbackFunc)

    # Simulate some data
    n = np.linspace(0, 499, 500)
    y = 50 + 25*(np.sin(n / 8.3)) + 10*(np.sin(n / 7.5)) - 5*(np.sin(n / 1.5))
    i = 0

    while(True):
        if(i > 499):
            i = 0
        time.sleep(0.1)
        mySrc.data_signal.emit(y[i]) # <- Here you emit a signal!
        i += 1
    ###
###


if __name__== '__main__':
    app = QtGui.QApplication(sys.argv)
    QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('Plastique'))
    myGUI = CustomMainWindow()
    sys.exit(app.exec_())

''''''

 
我最近重写了PyQt5的代码。
PyQt5的代码:

###################################################################
#                                                                 #
#                    PLOT A LIVE GRAPH (PyQt5)                    #
#                  -----------------------------                  #
#            EMBED A MATPLOTLIB ANIMATION INSIDE YOUR             #
#            OWN GUI!                                             #
#                                                                 #
###################################################################

import sys
import os
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import functools
import numpy as np
import random as rd
import matplotlib
matplotlib.use("Qt5Agg")
from matplotlib.figure import Figure
from matplotlib.animation import TimedAnimation
from matplotlib.lines import Line2D
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import time
import threading

class CustomMainWindow(QMainWindow):
    def __init__(self):
        super(CustomMainWindow, self).__init__()
        # Define the geometry of the main window
        self.setGeometry(300, 300, 800, 400)
        self.setWindowTitle("my first window")
        # Create FRAME_A
        self.FRAME_A = QFrame(self)
        self.FRAME_A.setStyleSheet("QWidget { background-color: %s }" % QColor(210,210,235,255).name())
        self.LAYOUT_A = QGridLayout()
        self.FRAME_A.setLayout(self.LAYOUT_A)
        self.setCentralWidget(self.FRAME_A)
        # Place the zoom button
        self.zoomBtn = QPushButton(text = 'zoom')
        self.zoomBtn.setFixedSize(100, 50)
        self.zoomBtn.clicked.connect(self.zoomBtnAction)
        self.LAYOUT_A.addWidget(self.zoomBtn, *(0,0))
        # Place the matplotlib figure
        self.myFig = CustomFigCanvas()
        self.LAYOUT_A.addWidget(self.myFig, *(0,1))
        # Add the callbackfunc to ..
        myDataLoop = threading.Thread(name = 'myDataLoop', target = dataSendLoop, daemon = True, args = (self.addData_callbackFunc,))
        myDataLoop.start()
        self.show()
        return

    def zoomBtnAction(self):
        print("zoom in")
        self.myFig.zoomIn(5)
        return

    def addData_callbackFunc(self, value):
        # print("Add data: " + str(value))
        self.myFig.addData(value)
        return

''' End Class '''


class CustomFigCanvas(FigureCanvas, TimedAnimation):
    def __init__(self):
        self.addedData = []
        print(matplotlib.__version__)
        # The data
        self.xlim = 200
        self.n = np.linspace(0, self.xlim - 1, self.xlim)
        a = []
        b = []
        a.append(2.0)
        a.append(4.0)
        a.append(2.0)
        b.append(4.0)
        b.append(3.0)
        b.append(4.0)
        self.y = (self.n * 0.0) + 50
        # The window
        self.fig = Figure(figsize=(5,5), dpi=100)
        self.ax1 = self.fig.add_subplot(111)
        # self.ax1 settings
        self.ax1.set_xlabel('time')
        self.ax1.set_ylabel('raw data')
        self.line1 = Line2D([], [], color='blue')
        self.line1_tail = Line2D([], [], color='red', linewidth=2)
        self.line1_head = Line2D([], [], color='red', marker='o', markeredgecolor='r')
        self.ax1.add_line(self.line1)
        self.ax1.add_line(self.line1_tail)
        self.ax1.add_line(self.line1_head)
        self.ax1.set_xlim(0, self.xlim - 1)
        self.ax1.set_ylim(0, 100)
        FigureCanvas.__init__(self, self.fig)
        TimedAnimation.__init__(self, self.fig, interval = 50, blit = True)
        return

    def new_frame_seq(self):
        return iter(range(self.n.size))

    def _init_draw(self):
        lines = [self.line1, self.line1_tail, self.line1_head]
        for l in lines:
            l.set_data([], [])
        return

    def addData(self, value):
        self.addedData.append(value)
        return

    def zoomIn(self, value):
        bottom = self.ax1.get_ylim()[0]
        top = self.ax1.get_ylim()[1]
        bottom += value
        top -= value
        self.ax1.set_ylim(bottom,top)
        self.draw()
        return

    def _step(self, *args):
        # Extends the _step() method for the TimedAnimation class.
        try:
            TimedAnimation._step(self, *args)
        except Exception as e:
            self.abc += 1
            print(str(self.abc))
            TimedAnimation._stop(self)
            pass
        return

    def _draw_frame(self, framedata):
        margin = 2
        while(len(self.addedData) > 0):
            self.y = np.roll(self.y, -1)
            self.y[-1] = self.addedData[0]
            del(self.addedData[0])

        self.line1.set_data(self.n[ 0 : self.n.size - margin ], self.y[ 0 : self.n.size - margin ])
        self.line1_tail.set_data(np.append(self.n[-10:-1 - margin], self.n[-1 - margin]), np.append(self.y[-10:-1 - margin], self.y[-1 - margin]))
        self.line1_head.set_data(self.n[-1 - margin], self.y[-1 - margin])
        self._drawn_artists = [self.line1, self.line1_tail, self.line1_head]
        return

''' End Class '''


# You need to setup a signal slot mechanism, to
# send data to your GUI in a thread-safe way.
# Believe me, if you don't do this right, things
# go very very wrong..
class Communicate(QObject):
    data_signal = pyqtSignal(float)

''' End Class '''



def dataSendLoop(addData_callbackFunc):
    # Setup the signal-slot mechanism.
    mySrc = Communicate()
    mySrc.data_signal.connect(addData_callbackFunc)

    # Simulate some data
    n = np.linspace(0, 499, 500)
    y = 50 + 25*(np.sin(n / 8.3)) + 10*(np.sin(n / 7.5)) - 5*(np.sin(n / 1.5))
    i = 0

    while(True):
        if(i > 499):
            i = 0
        time.sleep(0.1)
        mySrc.data_signal.emit(y[i]) # <- Here you emit a signal!
        i += 1
    ###
###

if __name__== '__main__':
    app = QApplication(sys.argv)
    QApplication.setStyle(QStyleFactory.create('Plastique'))
    myGUI = CustomMainWindow()
    sys.exit(app.exec_())

尝试一下。将此代码复制粘贴到新的python文件中,然后运行它。您应该得到一个漂亮的,平滑移动的图形:

在此处输入图片说明


我注意到,dataSendLoop当您关闭窗口时,线程一直在后台运行。因此,我添加了daemon = True关键字来解决该问题。
K.Mulier

1
为此,虚拟环境需要一些工作。最后,conda install pyqt=4成功了。
Reb.Cabin

1
非常感谢您的基本代码。它通过根据您的代码修改和添加功能来帮助我构建一些简单的UI。它节省了我的时间=]
艾萨克·辛

@IsaacSim,您好,非常感谢您的来信。我很高兴这段代码对您有所帮助:-)
K.Mulier

因此,我采用了此脚本,并通过修改信号时隙机制以使用np.ndarry类型并发出相对时间戳和信号的np.array来将时间戳添加到x轴。我正在更新每个帧绘制上的xlim(),这对于使用新轴显示信号非常有用,但是x-labels / ticks只能在更改窗口大小时短暂更新。@ K.Mulier我基本上是想像数据一样滑动xtick轴,想知道您是否在类似的事情上取得了成功?
nimig18

33

show可能不是最佳选择。我要做的是pyplot.draw()代替使用。您可能还希望time.sleep(0.05)在循环中包含一个小的时间延迟(例如),以便可以看到绘图的发生。如果我对您的示例进行了这些更改,它将对我有用,并且我看到每个点一次出现。


10
我有非常相似的代码部分,当我尝试您的解决方案时(绘制而不是显示和延时),python根本不会打开图形窗口,只是贯穿循环……
George Aprilis

31

这些方法都不适合我。但是我发现这个 实时matplotlib图在仍然处于循环中时无法正常工作

您只需要添加

plt.pause(0.0001)

然后您可以看到新的地块。

因此您的代码应如下所示,并且可以正常工作

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

6
每次为我打开一个新的图形/绘图窗口时,是否有办法更新现有图形?也许是因为我正在使用imshow吗?
弗朗西斯科·瓦尔加斯

@FranciscoVargas,如果您使用的是imshow,则需要使用set_data,请看此处:stackoverflow.com/questions/17835302/…–
Oren

22

上面的(以及许多其他)答案都建立在上plt.pause(),但这是在matplotlib中对情节进行动画处理的一种旧方法。它不仅很慢,而且还会导致每次更新都引起关注(我很难停止绘制python进程)。

TL; DR:您可能想使用matplotlib.animation如文档中所述)。

在研究了各种答案和代码段之后,事实证明,这对我来说是一种无限绘制传入数据的平滑方法。

这是我的快速入门代码。它每200ms无限地绘制一次[0,100)中的随机数的当前时间,同时还处理视图的自动缩放:

from datetime import datetime
from matplotlib import pyplot
from matplotlib.animation import FuncAnimation
from random import randrange

x_data, y_data = [], []

figure = pyplot.figure()
line, = pyplot.plot_date(x_data, y_data, '-')

def update(frame):
    x_data.append(datetime.now())
    y_data.append(randrange(0, 100))
    line.set_data(x_data, y_data)
    figure.gca().relim()
    figure.gca().autoscale_view()
    return line,

animation = FuncAnimation(figure, update, interval=200)

pyplot.show()

您还可以像FuncAnimation文档中一样探索blit更好的性能。

blit文档中的示例:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], 'ro')

def init():
    ax.set_xlim(0, 2*np.pi)
    ax.set_ylim(-1, 1)
    return ln,

def update(frame):
    xdata.append(frame)
    ydata.append(np.sin(frame))
    ln.set_data(xdata, ydata)
    return ln,

ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
                    init_func=init, blit=True)
plt.show()

嗨,如果这一切都是循环的,将会发生什么。说for i in range(1000): x,y = some func_func()。这里some_func()生成在线x,y数据对,一旦有可用数据,我将对其进行绘制。是否可以使用FuncAnimation。我的目标是在每次迭代中逐步构建数据定义的曲线。
亚历山大·卡斯卡

@Alexander Cska pyploy.show()应该阻止。如果要附加数据,请检索它们并在update函数中进行更新。
张海

我担心我不太理解您的答复。请您扩大您的建议。
亚历山大·卡斯卡

我的意思是,如果您pyplot.show在循环中调用,则该调用将阻止该循环,并且该循环将不会继续。如果要逐步将数据添加到曲线,请将逻辑放在中update,该逻辑将被每次调用,interval因此它也是逐步的。
张海

Zhang的代码可从控制台运行,但不能在jupyter中运行。我只是在那儿得到一片空白。实际上,当我在顺序循环中以jupyter填充数组并使用pet.plot语句随着数组的增长打印该数组时,我可以从数组中单独打印,但只能打印一个图。看到以下代码:gist.github.com/bwanaaa/12252cf36b35fced0eb3c2f64a76cb8a
aquagremlin

15

我知道这个问题很旧,但是现在在GitHub上有一个名为drawow的软件包,名为“ python-drawnow”。这提供了类似于MATLAB的drawow的界面-您可以轻松地更新图形。

您的用例示例:

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是一个薄包装,plt.draw但是提供了在图形显示后进行确认(或调试)的功能。


这使tk挂在某处
chwi

如果是这样,请提交具有更多上下文的问题github.com/scottsievert/python-drawnow/issues
Scott

+1这对我很有效,因为当matplotlib冻结时,它会从opencv捕获每帧视频的实时数据。
jj080808

我试过了,它似乎比其他方法慢。
戴夫C

不要使用,我的服务器重新启动,matplotlib冻结了
big-vl

6

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

要解决该问题,只需plt.show()在循环后调用一次即可。然后,您可以获得完整的图。(但不是“实时绘图”)

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


1
实时绘图确实是我想要的。我将对某项内容进行5小时的测试,并希望了解其进展情况。
克里斯(Chris)

@Chris您能够进行5小时的测试吗?我也在寻找类似的东西。我正在使用plyplot.pause(time_duration)更新绘图。还有其他方法吗?
Prakhar Mohan Srivastava 2014年

4

这是我必须在系统上使用的版本。

import matplotlib.pyplot as plt
from drawnow import drawnow
import numpy as np

def makeFig():
    plt.scatter(xList,yList) # I think you meant this

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

xList=list()
yList=list()

for i in np.arange(50):
    y=np.random.random()
    xList.append(i)
    yList.append(y)
    drawnow(makeFig)
    #makeFig()      The drawnow(makeFig) command can be replaced
    #plt.draw()     with makeFig(); plt.draw()
    plt.pause(0.001)

drawow(makeFig)行可以用makeFig()代替;plt.draw()序列,它仍然可以正常工作。


1
您怎么知道要暂停多长时间?它似乎取决于情节本身。
CMCDragonkai '18年

1

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

im使用以下代码绘制一系列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)

1

另一个选择是使用bokeh。海事组织,至少对于实时绘图而言,它是一个很好的选择。这是问题代码的bokeh版本:

from bokeh.plotting import curdoc, figure
import random
import time

def update():
    global i
    temp_y = random.random()
    r.data_source.stream({'x': [i], 'y': [temp_y]})
    i += 1

i = 0
p = figure()
r = p.circle([], [])
curdoc().add_root(p)
curdoc().add_periodic_callback(update, 100)

并运行它:

pip3 install bokeh
bokeh serve --show test.py

bokeh通过websocket通信在Web浏览器中显示结果。当数据由远程无头服务器进程生成时,它特别有用。

散景样地


0

一个实时绘制CPU使用情况的示例用例。

import time
import psutil
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)

i = 0
x, y = [], []

while True:
    x.append(i)
    y.append(psutil.cpu_percent())

    ax.plot(x, y, color='b')

    fig.canvas.draw()

    ax.set_xlim(left=max(0, i - 50), right=i + 50)
    fig.show()
    plt.pause(0.05)
    i += 1

大约2分钟后,它开始真正开始变慢。原因可能是什么?也许应该放弃当前观点之外的先前观点。
pfabri

这看起来确实不错,但是有一些问题:1.无法退出2.几分钟后,程序消耗了将近100 Mb的RAM,并开始显着降低速度。
pfabri
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.