Chr*_*ris 211 python real-time matplotlib while-loop
我试图使用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()
Run Code Online (Sandbox Code Playgroud)
我希望这个例子可以单独绘制1000个点.实际发生的是窗口弹出第一个点显示(确定),然后在填充图表的其余部分之前等待循环完成.
有什么想法,为什么我没有看到一次填充一个点?
Vel*_*ker 285
这是有问题的代码的工作版本(至少需要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()
Run Code Online (Sandbox Code Playgroud)
请注意一些变化:
plt.pause(0.05)两者绘制新数据并运行GUI的事件循环(允许鼠标交互).ali*_*i_m 68
如果您对实时绘图感兴趣,我建议您查看matplotlib的动画API.特别是,使用blit以避免在每个帧上重新绘制背景可以为您带来显着的速度增益(~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)
Run Code Online (Sandbox Code Playgroud)
输出:
Blit = False, average FPS: 54.37
Blit = True, average FPS: 438.27
Run Code Online (Sandbox Code Playgroud)
Bre*_*arn 33
show可能不是这个的最佳选择.我会做的是pyplot.draw()改用.您还可能希望time.sleep(0.05)在循环中包含一个小的时间延迟(例如),以便您可以看到正在发生的情节.如果我对你的例子进行了这些修改,它对我有用,我看到每个点一次出现一个.
K.M*_*ier 31
我知道我回答这个问题有点晚了.不过,我前段时间制作了一些代码来绘制实时图表,我想分享一下:
###################################################################
# #
# 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_())
''''''
Run Code Online (Sandbox Code Playgroud)
试一试吧.将此代码复制粘贴到新的python文件中,然后运行它.你应该得到一个漂亮,流畅的图表:
Ore*_*ren 30
这些方法都不适合我.但我发现这个 实时matplotlib图仍然在循环中不起作用
你只需要添加
plt.pause(0.0001)
Run Code Online (Sandbox Code Playgroud)
而且你可以看到新的情节.
所以你的代码应该是这样的,它会起作用
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
Run Code Online (Sandbox Code Playgroud)
Hai*_*ang 18
顶部(和许多其他)答案是建立在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()
Run Code Online (Sandbox Code Playgroud)
您还可以在FuncAnimation文档中探索blit更好的性能.
Sco*_*ott 13
我知道这个问题已经过时了,但是现在GitHub上有一个叫做drawow的软件包就是"python-drawnow".这提供了类似于MATLAB的绘图界面 - 您可以轻松更新图形.
您的用例的示例:
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)
Run Code Online (Sandbox Code Playgroud)
python-drawnow是一个薄的包装器,plt.draw但提供了在图形显示后确认(或调试)的能力.
另一种选择是使用bokeh。IMO,至少对于实时绘图来说,这是一个不错的选择。这是问题中代码的散景版本:
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)
Run Code Online (Sandbox Code Playgroud)
并运行它:
pip3 install bokeh
bokeh serve --show test.py
Run Code Online (Sandbox Code Playgroud)
bokeh 通过 websocket 通信在 Web 浏览器中显示结果。当数据由远程无头服务器进程生成时,它特别有用。
这是我必须在我的系统上工作的版本。
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)
Run Code Online (Sandbox Code Playgroud)
drawow(makeFig) 线可以用 makeFig() 替换;plt.draw() 序列,它仍然可以正常工作。
实时绘制 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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
437833 次 |
| 最近记录: |