使用Matplotlib绘制实时数据时遇PyEval_RestoreThread错误求助
问题
尝试用Python的Matplotlib绘制实时更新数据时出现报错,代码如下:
plt.rcParams['animation.html'] = 'jshtml' fig = plt.figure() ax = fig.add_subplot(111) fig.show() i = 0 plot_x , plot_y = [], [] while True : ###some code to get live updating x_in_data### x_in_data = np.reshape(x_in, (1)) print(x_in_data) plot_x.append(i) plot_y.append(x_in_data[0]) ax.plot(plot_x, plot_y, color='b') fig.canvas.draw() ax.set_xlim(left=max(0, i-50), right= i+50) time.sleep(0.1) i += 1
报错信息:
Fatal Python error: PyEval_RestoreThread: NULL tstate
Python runtime state: initialized
Current thread 0x00004fc4 (most recent call first):
程序弹出绘图窗口但无法正常工作,试过网上方案无效。数据是逐行更新的,格式示例:
[-18.75235738] [-19.02642986] [-18.75235738] [-19.02642986] [-18.75235738] [-19.02642986] [-18.92591474] [-18.75235738]
想知道该错误是否和数据更新方式有关,同时求高效绘制这类逐行更新数据的方法。
解决方案
错误原因
这个报错和数据更新方式无关,是因为你用while True循环加time.sleep阻塞了Matplotlib的事件循环,导致绘图线程和主线程冲突,触发了线程状态恢复的致命错误。
高效实现方法
方法1:使用FuncAnimation(推荐)
Matplotlib的FuncAnimation会自动处理事件循环,避免线程冲突,性能更优:
import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation import numpy as np # 初始化绘图 fig, ax = plt.subplots() line, = ax.plot([], [], color='b') ax.set_xlim(0, 50) ax.set_ylim(-20, -18) # 根据你的数据范围调整 plot_x, plot_y = [], [] i = 0 def update(frame): global i, plot_x, plot_y # 替换成你的实际数据获取逻辑 x_in = np.random.uniform(-19.1, -18.7) x_in_data = np.reshape(x_in, (1)) plot_x.append(i) plot_y.append(x_in_data[0]) # 只保留最近50个数据点,优化性能 if len(plot_x) > 50: plot_x = plot_x[-50:] plot_y = plot_y[-50:] line.set_data(plot_x, plot_y) ax.set_xlim(max(0, i-50), i+10) i += 1 return line, # interval是更新间隔(毫秒),blit=True提升绘图效率 ani = FuncAnimation(fig, update, interval=100, blit=True) plt.show()
方法2:修复原循环的事件处理
如果坚持用while True循环,需要在每次绘图后处理事件队列:
import matplotlib.pyplot as plt import numpy as np import time plt.rcParams['animation.html'] = 'jshtml' fig = plt.figure() ax = fig.add_subplot(111) line, = ax.plot([], [], color='b') # 只创建一条线,重复更新数据 ax.set_xlim(0, 50) ax.set_ylim(-20, -18) i = 0 plot_x , plot_y = [], [] while True : # 替换成你的实际数据获取逻辑 x_in = np.random.uniform(-19.1, -18.7) x_in_data = np.reshape(x_in, (1)) plot_x.append(i) plot_y.append(x_in_data[0]) # 限制数据点数量 if len(plot_x) > 50: plot_x = plot_x[-50:] plot_y = plot_y[-50:] line.set_data(plot_x, plot_y) ax.set_xlim(left=max(0, i-50), right= i+10) fig.canvas.draw() fig.canvas.flush_events() # 关键:处理事件队列,避免阻塞 time.sleep(0.1) i += 1
关键优化点
- 不要每次循环调用
ax.plot(),这会不断创建新线条,导致内存飙升,应该创建单条线后用set_data()更新数据。 - 限制保留的数据点数量,避免数据量过大影响性能。
- 通过
FuncAnimation或flush_events()处理Matplotlib事件循环,避免线程冲突。
内容的提问来源于stack exchange,提问作者park
相关产品推荐
相关产品推荐

