Matplotlib实时子图循环耗时优化及耗时递增原因咨询
Matplotlib实时绘图性能优化与耗时递增原因解析
耗时随迭代递增的原因
- 线条对象持续累积:每次循环调用
ax.plot()都会在坐标轴上新增一条完整曲线,而非更新已有曲线。随着迭代次数增加,轴上的历史线条数量越来越多,matplotlib每次渲染时需要处理所有这些线条,计算量线性增长,导致耗时逐步上升。 - 低效的列表头部删除:使用列表
pop(0)删除头部元素是O(n)复杂度操作,每次删除都要移动列表中所有后续元素,迭代次数越多,该操作的累积耗时越明显。 - 重复的轴范围设置:每次循环都重复设置固定的y轴范围,这会触发不必要的轴布局计算,增加额外开销。
优化方案
1. 复用线条对象,避免重复创建
初始化时先绘制一次曲线,获取线条实例,后续仅更新线条的xdata和ydata,而非重新绘制整条曲线,彻底避免线条对象累积的问题。
2. 改用双端队列优化列表操作
使用collections.deque替代普通列表,其popleft()方法是O(1)复杂度,大幅提升头部元素删除的效率,且可通过maxlen自动维护数据长度,省去手动判断删除的逻辑。
3. 减少冗余的轴配置操作
固定的y轴范围仅在初始化时设置一次,无需每次循环重复调用;x轴范围按需更新即可。
4. 可选:启用高效渲染方式
使用fig.canvas.draw_idle()替代plt.draw(),该方法仅重绘需要更新的部分,比全画布重绘更高效。
优化后的完整代码
import matplotlib.pyplot as plt import random import time from collections import deque # 用deque自动维护数据长度,避免手动pop操作 x_scale = 30 x = deque(maxlen=x_scale) y1 = deque(maxlen=x_scale) y2 = deque(maxlen=x_scale) i = 0 # 初始化画布与坐标轴 fig, (ax1, ax2) = plt.subplots(2, sharex=True) fig.set_size_inches(8, 4) ax1.set_title("top chart") ax2.set_title("bottom chart") ax2.set_xlabel("TIME") ax1.set_ylabel("RND_1") ax2.set_ylabel("RND_2") # 固定y轴范围,仅初始化时设置 ax1.set_ylim(0, 150) ax2.set_ylim(0, 20) # 初始化线条对象,后续仅更新数据 line1, = ax1.plot([], [], color='b') line2, = ax2.plot([], [], color='r') while True: now = time.time() # 添加新数据,deque自动溢出旧数据 x.append(i) y1.append(round(100 * random.random())) y2.append(round(10 * random.random())) # 更新x轴范围 ax1.set_xlim(i - x_scale, i) ax2.set_xlim(i - x_scale, i) # 更新线条数据 line1.set_data(x, y1) line2.set_data(x, y2) # 仅重绘需要更新的区域 fig.canvas.draw_idle() if plt.waitforbuttonpress(0.01): break now1 = time.time() duration = round((now1 - now) * 1000) print(duration) i += 1
内容的提问来源于stack exchange,提问作者xuraax
相关产品推荐
相关产品推荐

