如何提高循环重绘绘图的性能?
How to improve performance of plot redraw in a loop?
我正在从串行端口读取加速度计传感器数据,并尝试使用 matplot 库实时绘制它。我写了下面的代码来做我想做的,但速度很慢。此代码需要 5-6 秒来绘制 100 个样本,但我需要在不到 1 秒的时间内完成它。
import matplotlib.pyplot as plt
import numpy as np
x = np.zeros((1000,))
data = np.zeros((1000,))
plt.ion()
fig, ax = plt.subplots()
ax.set_ylim(-2, 2)
ax.set_xlim(0, 1000)
l, = ax.plot(data)
import serial
ser = serial.Serial('COM3',9600)
index = 0
while True:
b = ser.readline().decode("utf-8") # reading samples
temp = b[:-1].split()
print(temp[0], temp[1])
x[index] = index
data[index] = temp[0]
print(index, temp[0])
l.set_xdata(x[0:index])
l.set_ydata(data[0:index])
index += 1
fig.canvas.draw()
fig.canvas.flush_events()
如何提高这段代码的性能?
我需要它足够快,这样我就可以在来自多个传感器的原始数据之上实时看到经过过滤(平滑)的数据版本。
这是程序提前终止时分析器的屏幕截图。
这似乎是对 Matplotlib 性能的限制。它不是为实时高速绘图而制作的。你应该看看 pyqtgraph。
有examples条可以修改。
它使用 OpenGL 进行绘图,对于简单的线图,每秒可以达到几百个点。
我仍然认为您可能不需要单独绘制每个数据点,但即使只是调整我在评论中链接的 blitting 示例,我也得到 155 fps。
import time
import matplotlib.pyplot as plt
import numpy as np
x = np.zeros((1000,))
data = np.zeros((1000,))
fig, ax = plt.subplots()
ax.set_ylim(-2, 2)
ax.set_xlim(0, 1000)
# animated=True tells matplotlib to only draw the artist when we
# explicitly request it
l, = ax.plot(data, animated=True)
# make sure the window is raised, but the script keeps going
plt.show(block=False)
# stop to admire our empty window axes and ensure it is rendered at
# least once.
#
# We need to fully draw the figure at its final size on the screen
# before we continue on so that :
# a) we have the correctly sized and drawn background to grab
# b) we have a cached renderer so that ``ax.draw_artist`` works
# so we spin the event loop to let the backend process any pending operations
plt.pause(0.1)
# get copy of entire figure (everything inside fig.bbox) sans animated artist
bg = fig.canvas.copy_from_bbox(fig.bbox)
# draw the animated artist, this uses a cached renderer
ax.draw_artist(l)
# show the result to the screen, this pushes the updated RGBA buffer from the
# renderer to the GUI framework so you can see it
fig.canvas.blit(fig.bbox)
N = 1000
tic = time.time()
index = 0
for ii in range(N):
# reset the background back in the canvas state, screen unchanged
fig.canvas.restore_region(bg)
# update the artist, neither the canvas state nor the screen have changed
# b = ser.readline().decode("utf-8") # reading samples
b = f'{2 * np.random.rand()} abcd'
temp = b[:-1].split()
x[index] = index
data[index] = temp[0]
l.set_xdata(x[0:index])
l.set_ydata(data[0:index])
index += 1
# re-render the artist, updating the canvas state, but not the screen
ax.draw_artist(l)
# copy the image to the GUI state, but screen might not be changed yet
fig.canvas.blit(fig.bbox)
# flush any pending GUI events, re-painting the screen if needed
fig.canvas.flush_events()
# you can put a pause in if you want to slow things down
# plt.pause(.1)
toc = time.time()
fps = N / (toc - tic)
print(f'fps = {fps}')
我正在从串行端口读取加速度计传感器数据,并尝试使用 matplot 库实时绘制它。我写了下面的代码来做我想做的,但速度很慢。此代码需要 5-6 秒来绘制 100 个样本,但我需要在不到 1 秒的时间内完成它。
import matplotlib.pyplot as plt
import numpy as np
x = np.zeros((1000,))
data = np.zeros((1000,))
plt.ion()
fig, ax = plt.subplots()
ax.set_ylim(-2, 2)
ax.set_xlim(0, 1000)
l, = ax.plot(data)
import serial
ser = serial.Serial('COM3',9600)
index = 0
while True:
b = ser.readline().decode("utf-8") # reading samples
temp = b[:-1].split()
print(temp[0], temp[1])
x[index] = index
data[index] = temp[0]
print(index, temp[0])
l.set_xdata(x[0:index])
l.set_ydata(data[0:index])
index += 1
fig.canvas.draw()
fig.canvas.flush_events()
如何提高这段代码的性能?
我需要它足够快,这样我就可以在来自多个传感器的原始数据之上实时看到经过过滤(平滑)的数据版本。
这是程序提前终止时分析器的屏幕截图。
这似乎是对 Matplotlib 性能的限制。它不是为实时高速绘图而制作的。你应该看看 pyqtgraph。 有examples条可以修改。
它使用 OpenGL 进行绘图,对于简单的线图,每秒可以达到几百个点。
我仍然认为您可能不需要单独绘制每个数据点,但即使只是调整我在评论中链接的 blitting 示例,我也得到 155 fps。
import time
import matplotlib.pyplot as plt
import numpy as np
x = np.zeros((1000,))
data = np.zeros((1000,))
fig, ax = plt.subplots()
ax.set_ylim(-2, 2)
ax.set_xlim(0, 1000)
# animated=True tells matplotlib to only draw the artist when we
# explicitly request it
l, = ax.plot(data, animated=True)
# make sure the window is raised, but the script keeps going
plt.show(block=False)
# stop to admire our empty window axes and ensure it is rendered at
# least once.
#
# We need to fully draw the figure at its final size on the screen
# before we continue on so that :
# a) we have the correctly sized and drawn background to grab
# b) we have a cached renderer so that ``ax.draw_artist`` works
# so we spin the event loop to let the backend process any pending operations
plt.pause(0.1)
# get copy of entire figure (everything inside fig.bbox) sans animated artist
bg = fig.canvas.copy_from_bbox(fig.bbox)
# draw the animated artist, this uses a cached renderer
ax.draw_artist(l)
# show the result to the screen, this pushes the updated RGBA buffer from the
# renderer to the GUI framework so you can see it
fig.canvas.blit(fig.bbox)
N = 1000
tic = time.time()
index = 0
for ii in range(N):
# reset the background back in the canvas state, screen unchanged
fig.canvas.restore_region(bg)
# update the artist, neither the canvas state nor the screen have changed
# b = ser.readline().decode("utf-8") # reading samples
b = f'{2 * np.random.rand()} abcd'
temp = b[:-1].split()
x[index] = index
data[index] = temp[0]
l.set_xdata(x[0:index])
l.set_ydata(data[0:index])
index += 1
# re-render the artist, updating the canvas state, but not the screen
ax.draw_artist(l)
# copy the image to the GUI state, but screen might not be changed yet
fig.canvas.blit(fig.bbox)
# flush any pending GUI events, re-painting the screen if needed
fig.canvas.flush_events()
# you can put a pause in if you want to slow things down
# plt.pause(.1)
toc = time.time()
fps = N / (toc - tic)
print(f'fps = {fps}')