如何使用Matplotlib和Tkinter实现5秒后更新完整图表?
解决定时更新Tkinter中Matplotlib图表的问题
问题回顾
- 代码预期功能:调用
get_latest_data(1)绘制初始数据,5秒后调用get_latest_data(2)重绘更新数据 - 代码现有功能:仅能完成首次图表绘制,无法触发后续更新
原代码的核心问题
- 线程调用参数不匹配:启动线程时传递了队列,但
get_latest_data需要的是dataid参数 - 缺少定时触发逻辑:没有实现5秒后调用更新函数的机制
- 变量作用域错误:
display_result和get_result无法访问UI类内部的图表对象(如a、canvas) - 重绘逻辑缺失:更新时未清除旧图表,直接绘制会导致数据叠加
修复后的完整代码
from threading import Thread from queue import Empty, Queue import time import tkinter as tk from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.figure import Figure class tkChartGUI(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) self.parent = parent self.result_queue = Queue() self.canvas = None self.ax = None self.initUI() # 5秒后触发更新数据 self.parent.after(5000, self.update_chart) def get_latest_data(self, dataid): x_array=[] y_array=[] if (dataid == 1): x_array=[1,2,3,4,5,6,7,8,9,10,11,12,13,14] y_array=[0.5,0.7,0.3,1.0,0.6,0.9,0.5,0.2,0.1,0.5,0.33,0.55,0.3,0.6] if (dataid == 2): x_array=[1,2,3,4,5,6,7,8,9,10,11,12,13,14] y_array=[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.1,1.2,1.3] return (x_array, y_array) def initUI(self): self.parent.title("Simple chart") self.parent.geometry("800x600+300+100") # 绘制初始图表 x_array, y_array = self.get_latest_data(1) f = Figure(figsize=(5, 3), dpi=150) self.ax = f.add_subplot(111) self.ax.set_xlabel("Values_X") self.ax.set_ylabel("Values_Y") self.ax.yaxis.grid(True, which='major') self.ax.xaxis.grid(True, which='major') self.ax.plot(x_array, y_array) self.canvas = FigureCanvasTkAgg(f, master=self.parent) self.canvas.draw() self.canvas.get_tk_widget().grid(row=0,column=0) def update_chart(self): # 用线程获取新数据(避免阻塞UI) Thread(target=self.get_result, args=[2], daemon=True).start() # 检查队列中的数据并更新图表 self.display_result() def get_result(self, dataid): x_array, y_array = self.get_latest_data(dataid) self.result_queue.put(x_array) self.result_queue.put(y_array) def display_result(self): x_array = [] y_array = [] try: x_array = self.result_queue.get(block=False) y_array = self.result_queue.get(block=False) except Empty: # 如果队列还没数据,100ms后再检查 self.parent.after(100, self.display_result) return # 清除旧图表,绘制新数据 self.ax.clear() self.ax.set_xlabel("Values_X") self.ax.set_ylabel("Values_Y") self.ax.yaxis.grid(True, which='major') self.ax.xaxis.grid(True, which='major') self.ax.plot(x_array, y_array) self.canvas.draw() def onExit(self): self.quit() def main(): root = tk.Tk() my_gui = tkChartGUI(root) root.mainloop() if __name__ == '__main__': main()
关键修改说明
- 将队列、画布、坐标轴对象设为类的属性,让所有方法都能访问
- 在
__init__中用after(5000, self.update_chart)实现5秒后触发更新 - 新增
update_chart方法,负责启动线程获取新数据并触发显示逻辑 display_result方法中加入队列空时的重试逻辑,确保能获取到线程返回的数据- 更新图表前先调用
self.ax.clear()清除旧内容,避免数据叠加 - 修正线程调用的参数,确保
get_result能正确传递dataid
当前代码运行效果

内容的提问来源于stack exchange,提问作者GarfieldCat
相关产品推荐
相关产品推荐

