在 Tkinter 中使用 Arduino 数据动态更新标签和实时图形 [英] Updating Label and Live Graph dynamically using Arduino Data in Tkinter

查看:26
本文介绍了在 Tkinter 中使用 Arduino 数据动态更新标签和实时图形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在从事一个项目,该项目更新标签并将其绘制在来自 Arduino 的实时图表中.它输出温度和湿度.我的 arduino 串行输出如下所示:

29,50,44

我用这行代码在python中分离串口数据:

ser = serial.Serial('COM3',9600)pullData = ser.readline().decode('utf-8')get_data = pullData.split(',')

我可以分离这些值并在它们各自的标签中更新它们.但是当我使用这些相同的序列值动态更新图形时,我没有让它工作.我想同时更新它们.我收到类似

的错误<前> 28,90,43线程 Thread-3 中的异常:回溯(最近一次调用最后一次):文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\threading.py",第 916 行,在 _bootstrap_innerself.run()文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\threading.py",第 864 行,运行中self._target(*self._args, **self._kwargs)文件c:\Users\Deanne\OneDrive\Documents\Example#1\example#7.py",第 68 行,动画潮湿 = int(data_1[0])ValueError: 基数为 10 的 int() 的文字无效:'\x005\n'线程 Thread-1 中的异常:回溯(最近一次调用最后一次):文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\threading.py",第 916 行,在 _bootstrap_innerself.run()文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\threading.py",第 864 行,运行中self._target(*self._args, **self._kwargs)文件c:\Users\Deanne\OneDrive\Documents\Example#1\example#7.py",第 69 行,动画temp = int(data_1[1])ValueError: 基数为 10 的 int() 的文字无效:'\x00\x00\n'Tkinter 回调中的异常回溯(最近一次调用最后一次):文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py",第 1699 行,在 __call__ 中返回 self.func(*args)文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py",第 745 行,在 callit 中功能(*参数)GetSerialData 中的文件c:\Users\Deanne\OneDrive\Documents\Example#1\example#7.py",第 86 行data_array2 = int(get_data[2])索引错误:列表索引超出范围

这个错误一直在发生,我知道也许我的代码不是解决这个问题或实现我想要的最合适的方式,但这是我从研究中得出的结论.我尝试了这种方法 试图在 Python 中绘制来自 Arduino 的实时串行端口数据,但无济于事,因为根本没有回答问题.我也阅读了许多相关的问题,但仍然没有运气.我不知道如何把握队列和线程的话题.我希望有人能指出我做错了什么.任何帮助将不胜感激.

这是我的完整代码:

from tkinter import *导入序列导入 matplotlibmatplotlib.use("TkAgg")从 matplotlib.backends.backend_tkagg 导入 FigureCanvasTkAggfrom matplotlib.figure 导入图导入 matplotlib.animation 作为动画从 matplotlib 导入样式进口螺纹my_window = Tk()my_window.title("图形用户界面演示#1")my_window.geometry("720x720")#用于提升框架def raise_frame(frame):frame.tkraise()F1 = Frame(my_window,浮雕 = RAISED)F2 = Frame(my_window,浮雕 = RAISED)F3 = Frame(my_window,浮雕 = RAISED)F4 = Frame(my_window,浮雕 = RAISED)对于帧输入(F1、F2、F3、F4):frame.grid(row = 0, column = 0,sticky = "NSEW")raise_frame(F1)列表_1 = []列表_2 = []列表_3 = []#串口通讯初始化ser = serial.Serial('COM3', 9600)style.use("ggplot")a = 图(figsize = (7,6))plot_a = a.add_subplot(111)plot_a.set_title('温度图')plot_a.set_ylabel('温度')plot_a.set_xlabel('时间')plot_a.plot(List_1, 'c', 标记 = 'o',label = 'Degrees C')plot_a.legend(loc='左上')b = 图(图大小 = (7,6))plot_b = b.add_subplot(111)plot_b.set_title('湿度图')plot_b.set_ylabel('湿度')plot_b.plot(List_2,'g', 标记 = 'o', 标签 = '百分比 %')plot_c.legend(loc = '右上角')c = 图(figsize = (7,6))plot_c = c.add_subplot(111)plot_c.set_title('求解水图')plot_c.set_ylabel('水量')plot_c.plot(List_3,'b', 标记 = 'o', 标签 = 'mL')plot_c.legend(loc = '右上角')def animate_thread(i):threading.Thread(target=animate, args=(i,)).start()定义动画(i):pulldata = ser.readline().decode('ascii')data_1 = pulldata.split(',')潮湿 = int(data_1[0])temp = int(data_1[1])已解决_水 = int(data_1[2])List_1.append(潮湿)List_2.append(temp)List_3.append(solved_water)plot_a.set_ylim(0,40)plot_a.plot(List_1, 'c', 标记 = 'o',label = 'Degrees C')plot_b.set_ylim(0,100)plot_b.plot(List_2, 'g', 标记 = 'o',label = '百分比 %')plot_c.set_ylim(0,55)plot_c.plot(List_3, 'b', 标记 = 'o',label = 'mL')def GetSerialData():pulldata = ser.readline().decode('ascii')get_data = pulldata.split(',')data_array = int(get_data[0])data_array1 = int(get_data[1])data_array2 = int(get_data[2])label_2data.config(text = str(data_array))label_3data.config(text = str(data_array1))label_4data.config(text = str(data_array2))打印(拉数据)my_window.after(10000, GetSerialData)#对于第一帧label_1 = Label(F1, text = "GUI 主页", 浮雕 = "solid", font = "Times 22 bold")label_1.grid(row = 0, column = 3)button_1 = Button(F1, text = "Page of Humidity", Relief = GROOVE, bd = 8, command = lambda:raise_frame(F2))button_1.grid(行 = 1,列 = 2)button_2 = Button(F1, text = "Page of Temperature", 浮雕 = GROOVE, bd = 8, command = lambda:raise_frame(F3))button_2.grid(row = 1, column = 3)button_3 = Button(F1, text = "Page of Water", 浮雕 = GROOVE, bd = 8, command = lambda:raise_frame(F4))button_3.grid(row = 1, column = 4)#对于第二帧label_2 = Label(F2, text = "温度", 浮雕 = "solid", font = "Times 22 bold")label_2.grid(row = 0, column = 3)button_1 = Button(F2, text = "Back To Homepage", command = lambda:raise_frame(F1))button_1.grid(行 = 1,列 = 2)label_2_1 = Label(F2, text = "当前值:", 浮雕 = "solid", font = "Verdana 10 bold")label_2_1.grid(row = 2, column = 2)label_2data = Label(F2, font = "Verdana 10")label_2data.grid(row = 2, column = 3)canvas1 = FigureCanvasTkAgg(a, F2)canvas1.get_tk_widget().grid(row = 3, column = 3)F2.canvas = canvas1#对于第三帧label_3 = Label(F3, text = "Humidity", 浮雕 = "solid", font = "Times 22 bold")label_3.grid(row = 0, column = 3)button_1 = Button(F3, text = "Back To Homepage", command = lambda:raise_frame(F1))button_1.grid(行 = 1,列 = 2)label_3_1 = Label(F3, text = "当前值:", 浮雕 = "solid", font = "Verdana 10 bold")label_3_1.grid(row = 2, column = 2)label_3data = Label(F3, font = "Verdana 10")label_3data.grid(row = 2, column = 3)canvas2 = FigureCanvasTkAgg(b, F3)canvas2.get_tk_widget().grid(row = 3, column = 3)F3.canvas = canvas2#对于第四帧label_4 = Label(F4, text = "Solution Water Value", 浮雕 = "solid", font = "Times 22 bold")label_4.grid(row = 0, column = 3)button_1 = Button(F4, text = "Back To Homepage", command = lambda:raise_frame(F1))button_1.grid(行 = 1,列 = 2)label_4_1 = Label(F4, text = "当前值:", 浮雕 = "solid", font = "Verdana 10 bold")label_4_1.grid(row = 2, column = 2)label_4data = Label(F4,font = "Verdana 10")label_4data.grid(row = 2, column = 3)canvas3 = FigureCanvasTkAgg(b, F4)canvas3.get_tk_widget().grid(row = 3, column = 3)F4.canvas = canvas3aniA = animation.FuncAnimation(a, animate_thread, interval = 20000, blit = False)aniB = animation.FuncAnimation(b, animate_thread, interval = 20000, blit = False)aniC = animation.FuncAnimation(c, animate_thread, interval = 20000, blit = False)获取串行数据()my_window.mainloop()

更新:我试过使用@Novel 更简洁的代码.代码如下:

#from tkinter 导入 *import tkinter as tk # 正确导入 tkinter 的方法导入序列导入 matplotlibmatplotlib.use("TkAgg")从 matplotlib.backends.backend_tkagg 导入 FigureCanvasTkAggfrom matplotlib.figure 导入图导入 matplotlib.animation 作为动画从 matplotlib 导入样式style.use("ggplot")进口螺纹类迪(tk.Frame):def __init__(self, master=None, title='', ylabel='', label='', color='c', ylim=1, **kwargs):tk.Frame.__init__(self, master, **kwargs)self.data = []fig = 图(figsize = (7,6))self.plot = fig.add_subplot(111)self.plot.set_title(title)self.plot.set_ylabel(ylabel)self.plot.set_ylim(0, ylim)self.line, = self.plot.plot([], [], color, marker = 'o',label = label)self.plot.legend(loc='左上')label = tk.Label(self, text = ylabel, font = "Times 22 bold")label.grid(行 = 0,列 = 3)button_1 = tk.Button(self, text = "Back To Homepage", command = F1.tkraise)button_1.grid(行 = 1,列 = 2)label_1 = tk.Label(self, text = "Current Value: ", font = "Verdana 10 bold")label_1.grid(row = 2, column = 2)self.label_data = tk.Label(self, font = "Verdana 10")self.label_data.grid(row = 2, column = 3)canvas = FigureCanvasTkAgg(fig, master=self)canvas.get_tk_widget().grid(row = 3, column = 3)ani = animation.FuncAnimation(fig, self.update_graph, interval = 1000, blit = False)画布.draw()def update_graph(self, i):如果 self.data:self.line.set_data(range(len(self.data)), self.data)self.plot.set_xlim(0, len(self.data))定义集(自我,价值):self.data.append(value)self.label_data.config(文本=值)my_window = tk.Tk()my_window.title("图形用户界面演示#1")my_window.geometry("720x720")F1 = tk.Frame(my_window)F2 = Dee(my_window, title='温度图', ylabel='温度', color='c', label='Degrees C', ylim=40)F3 = Dee(my_window, title='湿度图', ylabel='湿度', color='g', label='百分比%', ylim=100)F4 = Dee(my_window, title='Solved Water Graph', ylabel='Water Volume', color='b', label='mL', ylim=55)#对于第一帧label_1 = tk.Label(F1, text = "GUI 主页", font = "Times 22 bold")label_1.grid(row = 0, column = 3)button_1 = tk.Button(F1, text = "Page of Humidity", bd = 8, command = F2.tkraise)button_1.grid(行 = 1,列 = 2)button_2 = tk.Button(F1, text = "Page of Temperature", bd = 8, command = F3.tkraise)button_2.grid(row = 1, column = 3)button_3 = tk.Button(F1, text = "Page of Water", bd = 8, command = F4.tkraise)button_3.grid(row = 1, column = 4)对于帧输入(F1、F2、F3、F4):frame.grid(row = 0, column = 0,sticky = "NSEW")F1.tkraise()def get_data():#串口通讯初始化ser = serial.Serial('COM3', 9600)而真:pulldata = ser.readline().decode('ascii')get_data = pulldata.split(',')F2.set(int(get_data[0]))F3.set(int(get_data[1]))F4.set(int(get_data[2]))打印(拉数据)# 启动将轮询arduino的线程t = threading.Thread(target=get_data)t.daemon = 真t.start()my_window.mainloop()

图表和标签正在更新,但现在出现的问题是它正在冻结.这也给了我这个错误:

Tkinter 回调中的异常回溯(最近一次调用最后一次):文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py",第 1699 行,在 __call__ 中返回 self.func(*args)文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py",第 745 行,在 callit 中功能(*参数)文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\backends\_backend_tk.py",第 310 行,在 idle_drawself.draw()文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\backends\backend_tkagg.py",第 12 行,绘制super(FigureCanvasTkAgg, self).draw()文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\backends\backend_agg.py",第 433 行,绘制self.figure.draw(self.renderer)文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\artist.py",第 55 行,在 draw_wrapper 中返回绘制(艺术家,渲染器,*args,**kwargs)文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\figure.py",第 1475 行,绘制渲染器,自我,艺术家,self.suppressComposite)文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\image.py",第 141 行,在 _draw_list_compositing_imagesa.draw(渲染器)文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\artist.py",第 55 行,在 draw_wrapper 中返回绘制(艺术家,渲染器,*args,**kwargs)文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\axes\_base.py",第 2607 行,绘制mimage._draw_list_compositing_images(渲染器,自我,艺术家)文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\image.py",第 141 行,在 _draw_list_compositing_imagesa.draw(渲染器)文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\artist.py",第 55 行,在 draw_wrapper 中返回绘制(艺术家,渲染器,*args,**kwargs)文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\lines.py",第 738 行,绘制self.recache()文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\lines.py",第 661 行,在 recache 中self._xy = np.column_stack(np.broadcast_arrays(x, y)).astype(float)文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\numpy\lib\stride_tricks.py",第 249 行,在 broadcast_arrays形状 = _broadcast_shape(*args)文件C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\numpy\lib\stride_tricks.py",第 184 行,在 _broadcast_shapeb = np.broadcast(*args[:32])ValueError:形状不匹配:对象不能广播到单个形状

我可以看出它仍在工作,因为它仍在输出数据.任何帮助将不胜感激.谢谢.

解决方案

这是一个疯狂的猜测,展示了如何创建一个用于轮询 arduino 的线程,以及如何通过使用类而不是复制/粘贴来使代码更整洁:

from tkinter import *import tkinter as tk # 正确导入 tkinter 的方法导入序列导入 matplotlibmatplotlib.use("TkAgg")从 matplotlib.backends.backend_tkagg 导入 FigureCanvasTkAggfrom matplotlib.figure 导入图导入 matplotlib.animation 作为动画从 matplotlib 导入样式style.use("ggplot")进口螺纹类迪(tk.Frame):def __init__(self, master=None, title='', ylabel='', label='', color='c', ylim=1, **kwargs):tk.Frame.__init__(self, master, **kwargs)self.data = []fig = 图(figsize = (7,6))self.plot = fig.add_subplot(111)self.plot.set_title(title)self.plot.set_ylabel(ylabel)self.plot.set_ylim(0, ylim)self.line, = self.plot.plot([], [], color, marker = 'o',label = label)self.plot.legend(loc='左上')标签 = 标签(自我,文本 = ylabel,浮雕 =实心",字体 =22 倍粗体")label.grid(行 = 0,列 = 3)button_1 = Button(self, text = "Back To Homepage", command = F1.tkraise)button_1.grid(行 = 1,列 = 2)label_1 = Label(self, text = "Current Value:", Relief = "solid", font = "Verdana 10 bold")label_1.grid(row = 2, column = 2)self.label_data = Label(self, font = "Verdana 10")self.label_data.grid(row = 2, column = 3)canvas = FigureCanvasTkAgg(fig, master=self)canvas.get_tk_widget().grid(row = 3, column = 3)ani = animation.FuncAnimation(fig, self.update_graph, interval = 1000, blit = False)画布.draw()def update_graph(self, i):如果 self.data:self.line.set_data(range(len(self.data)), self.data)self.plot.set_xlim(0, len(self.data))定义集(自我,价值):self.data.append(value)self.label_data.config(文本=值)my_window = Tk()my_window.title("图形用户界面演示#1")my_window.geometry("720x720")F1 = Frame(my_window,浮雕 = RAISED)F2 = Dee(my_window, title='温度图', ylabel='温度', color='c', label='Degrees C', ylim=40, 浮雕= RAISED)F3 = Dee(my_window, title='Humidity Graph', ylabel='Humidity', color='g', label='Percentage %', ylim=100, 救济= RAISED)F4 = Dee(my_window, title='Solved Water Graph', ylabel='Water Volume', color='b', label='mL', ylim=55, 浮雕= RAISED)#对于第一帧label_1 = Label(F1, text = "GUI 主页", 浮雕 = "solid", font = "Times 22 bold")label_1.grid(row = 0, column = 3)button_1 = Button(F1, text = "Page of Humidity", relief = GROOVE, bd = 8, command = F2.tkraise)button_1.grid(行 = 1,列 = 2)button_2 = Button(F1, text = "Page of Temperature", 浮雕 = GROOVE, bd = 8, command = F3.tkraise)button_2.grid(row = 1, column = 3)button_3 = Button(F1, text = "Page of Water", 浮雕 = GROOVE, bd = 8, command = F4.tkraise)button_3.grid(row = 1, column = 4)对于帧输入(F1、F2、F3、F4):frame.grid(row = 0, column = 0,sticky = "NSEW")F1.tkraise()def get_data():#串口通讯初始化ser = serial.Serial('COM3', 9600)而真:pulldata = ser.readline().decode('ascii')get_data = pulldata.split(',')F2.set(int(get_data[0]))F3.set(int(get_data[1]))F4.set(int(get_data[3]))# 启动将轮询arduino的线程t = threading.Thread(target=get_data)t.daemon = 真t.start()my_window.mainloop()

I've been working on a project that updates the label and plots it in a live graph that's coming from the Arduino. It outputs temperature and humidity. My arduino serial outputs looks like this:

29,50,44

I use this line of codes in separating the serial data in python:

ser = serial.Serial('COM3',9600)
pullData = ser.readline().decode('utf-8')
get_data = pullData.split(',')

I get to separate the values and update them in their respective labels. But what I don't get it to work is when I dynamically update the graph using those same serial values. I want to update them both at the same time. I get errors like

 28,90,43
Exception in thread Thread-3:
Traceback (most recent call last):
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\threading.py", line 916, in _bootstrap_inner
    self.run()
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\threading.py", line 864, in run
    self._target(*self._args, **self._kwargs)
  File "c:\Users\Deanne\OneDrive\Documents\Example#1\example#7.py", line 68, in animate
    humid = int(data_1[0])
ValueError: invalid literal for int() with base 10: '\x005\n'
Exception in thread Thread-1:
Traceback (most recent call last):
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\threading.py", line 916, in _bootstrap_inner
    self.run()
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\threading.py", line 864, in run
    self._target(*self._args, **self._kwargs)
  File "c:\Users\Deanne\OneDrive\Documents\Example#1\example#7.py", line 69, in animate
    temp = int(data_1[1])
ValueError: invalid literal for int() with base 10: '\x00\x00\n'
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py", line 1699, in __call__
    return self.func(*args)
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py", line 745, in callit
    func(*args)
  File "c:\Users\Deanne\OneDrive\Documents\Example#1\example#7.py", line 86, in GetSerialData
    data_array2 = int(get_data[2])
IndexError: list index out of range

This error just keeps on going, I know that maybe my code is not the most suitable way to approach this or to achieve what I want but this is what I've come up from doing researches. I tried this way of approach Trying to plot real time serial port data from Arduino in Python but to no avail since the question was not answered at all. I've also read many somewhat related problem but still no luck. I don't know how to grasp the topic of queue and threads. I wish someone could point out what I'm doing wrong. Any help will be appreciated.

Here's my full code:

from tkinter import *
import serial
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import style
import threading

my_window = Tk()
my_window.title("Graphical User Interface Demo#1")
my_window.geometry("720x720")

#For raising frames
def raise_frame(frame):
    frame.tkraise()

F1 = Frame(my_window, relief = RAISED)
F2 = Frame(my_window, relief = RAISED)
F3 = Frame(my_window, relief = RAISED)
F4 = Frame(my_window, relief = RAISED)

for frame in(F1, F2, F3, F4):
    frame.grid(row = 0, column = 0, sticky = "NSEW")

raise_frame(F1)


List_1 = []
List_2 = []
List_3 = []

#Initialization of Serial Comm
ser = serial.Serial('COM3', 9600)


style.use("ggplot")
a = Figure(figsize = (7,6))
plot_a = a.add_subplot(111)
plot_a.set_title('Temperature Graph')
plot_a.set_ylabel('Temperature')
plot_a.set_xlabel('Time')
plot_a.plot(List_1, 'c', marker = 'o',label = 'Degrees C')
plot_a.legend(loc= 'upper left')

b = Figure(figsize = (7,6))
plot_b = b.add_subplot(111)
plot_b.set_title('Humidity Graph')
plot_b.set_ylabel('Humidity')
plot_b.plot(List_2,'g', marker = 'o', label = 'Percentage %')
plot_c.legend(loc = 'upper right')

c = Figure(figsize = (7,6))
plot_c = c.add_subplot(111)
plot_c.set_title('Solved Water Graph')
plot_c.set_ylabel('Water Volume')
plot_c.plot(List_3,'b', marker = 'o', label = 'mL')
plot_c.legend(loc = 'upper right')


def animate_thread(i):
    threading.Thread(target=animate, args=(i,)).start()

def animate(i):
    pulldata = ser.readline().decode('ascii')
    data_1 = pulldata.split(',')
    humid = int(data_1[0])
    temp = int(data_1[1])
    solved_water = int(data_1[2])
    List_1.append(humid)
    List_2.append(temp)
    List_3.append(solved_water)
    plot_a.set_ylim(0,40)
    plot_a.plot(List_1, 'c', marker = 'o',label = 'Degrees C')
    plot_b.set_ylim(0,100)
    plot_b.plot(List_2, 'g', marker = 'o',label = 'Percentage %')
    plot_c.set_ylim(0,55)
    plot_c.plot(List_3, 'b', marker = 'o',label = 'mL')

def GetSerialData():
    pulldata = ser.readline().decode('ascii')
    get_data = pulldata.split(',')
    data_array = int(get_data[0])
    data_array1 = int(get_data[1])
    data_array2 = int(get_data[2])
    label_2data.config(text = str(data_array))
    label_3data.config(text = str(data_array1))
    label_4data.config(text = str(data_array2))
    print(pulldata)
    my_window.after(10000, GetSerialData)


#For Frame One
label_1 = Label(F1, text = "Homepage of GUI", relief = "solid", font = "Times 22 bold")
label_1.grid(row = 0, column = 3)
button_1 = Button(F1, text = "Page of Humidity", relief = GROOVE, bd = 8, command = lambda:raise_frame(F2))
button_1.grid(row = 1, column = 2)
button_2 = Button(F1, text = "Page of Temperature", relief = GROOVE, bd = 8, command = lambda:raise_frame(F3))
button_2.grid(row = 1, column = 3)
button_3 = Button(F1, text = "Page of Water", relief = GROOVE, bd = 8, command = lambda:raise_frame(F4))
button_3.grid(row = 1, column = 4)


#For Frame Two
label_2 = Label(F2, text = "Temperature", relief = "solid", font = "Times 22 bold")
label_2.grid(row = 0, column = 3)
button_1 = Button(F2, text = "Back To Homepage", command = lambda:raise_frame(F1))
button_1.grid(row = 1, column = 2)
label_2_1 = Label(F2, text = "Current Value: ", relief = "solid", font = "Verdana 10 bold")
label_2_1.grid(row = 2, column = 2)
label_2data = Label(F2, font = "Verdana 10")
label_2data.grid(row = 2, column = 3)
canvas1 = FigureCanvasTkAgg(a, F2)
canvas1.get_tk_widget().grid(row = 3, column = 3)
F2.canvas = canvas1


#For Frame Three
label_3 = Label(F3, text = "Humidity", relief = "solid", font = "Times 22 bold")
label_3.grid(row = 0, column = 3)
button_1 = Button(F3, text = "Back To Homepage", command = lambda:raise_frame(F1))
button_1.grid(row = 1, column = 2)
label_3_1 = Label(F3, text = "Current Value: ", relief = "solid", font = "Verdana 10 bold")
label_3_1.grid(row = 2, column = 2)
label_3data = Label(F3, font = "Verdana 10")
label_3data.grid(row = 2, column = 3)
canvas2 = FigureCanvasTkAgg(b, F3)
canvas2.get_tk_widget().grid(row = 3, column = 3)
F3.canvas = canvas2


#For Frame Four
label_4 = Label(F4, text = "Solved Water Value", relief = "solid", font = "Times 22 bold")
label_4.grid(row = 0, column = 3)
button_1 = Button(F4, text = "Back To Homepage", command = lambda:raise_frame(F1))
button_1.grid(row = 1, column = 2)
label_4_1 = Label(F4, text = "Current Value: ", relief = "solid", font = "Verdana 10 bold")
label_4_1.grid(row = 2, column = 2)
label_4data = Label(F4,font = "Verdana 10")
label_4data.grid(row = 2, column = 3)
canvas3 = FigureCanvasTkAgg(b, F4)
canvas3.get_tk_widget().grid(row = 3, column = 3)
F4.canvas = canvas3


aniA = animation.FuncAnimation(a, animate_thread, interval = 20000, blit = False)
aniB = animation.FuncAnimation(b, animate_thread, interval = 20000, blit = False)
aniC = animation.FuncAnimation(c, animate_thread, interval = 20000, blit = False)
GetSerialData()
my_window.mainloop()

Update: I've tried using @Novel's neater code. Here's the code:

#from tkinter import *
import tkinter as tk # proper way to import tkinter
import serial
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import style
style.use("ggplot")
import threading

class Dee(tk.Frame):
    def __init__(self, master=None, title='', ylabel='', label='', color='c', ylim=1, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)
        self.data = []
        fig = Figure(figsize = (7,6))
        self.plot = fig.add_subplot(111)
        self.plot.set_title(title)
        self.plot.set_ylabel(ylabel)
        self.plot.set_ylim(0, ylim)
        self.line, = self.plot.plot([], [], color, marker = 'o',label = label)
        self.plot.legend(loc='upper left')

        label = tk.Label(self, text = ylabel, font = "Times 22 bold")
        label.grid(row = 0, column = 3)
        button_1 = tk.Button(self, text = "Back To Homepage", command = F1.tkraise)
        button_1.grid(row = 1, column = 2)
        label_1 = tk.Label(self, text = "Current Value: ", font = "Verdana 10 bold")
        label_1.grid(row = 2, column = 2)
        self.label_data = tk.Label(self, font = "Verdana 10")
        self.label_data.grid(row = 2, column = 3)
        canvas = FigureCanvasTkAgg(fig, master=self)
        canvas.get_tk_widget().grid(row = 3, column = 3)

        ani = animation.FuncAnimation(fig, self.update_graph, interval = 1000, blit = False)
        canvas.draw()

    def update_graph(self, i):
        if self.data:
        self.line.set_data(range(len(self.data)), self.data)
        self.plot.set_xlim(0, len(self.data))

    def set(self, value):
        self.data.append(value)
        self.label_data.config(text=value)

my_window = tk.Tk()
my_window.title("Graphical User Interface Demo#1")
my_window.geometry("720x720")

F1 = tk.Frame(my_window)
F2 = Dee(my_window, title='Temperature Graph', ylabel='Temperature', color='c', label='Degrees C', ylim=40)
F3 = Dee(my_window, title='Humidity Graph', ylabel='Humidity', color='g', label='Percentage %', ylim=100)
F4 = Dee(my_window, title='Solved Water Graph', ylabel='Water Volume', color='b', label='mL', ylim=55)

#For Frame One
label_1 = tk.Label(F1, text = "Homepage of GUI", font = "Times 22 bold")
label_1.grid(row = 0, column = 3)
button_1 = tk.Button(F1, text = "Page of Humidity", bd = 8, command = F2.tkraise)
button_1.grid(row = 1, column = 2)
button_2 = tk.Button(F1, text = "Page of Temperature", bd = 8, command = F3.tkraise)
button_2.grid(row = 1, column = 3)
button_3 = tk.Button(F1, text = "Page of Water",  bd = 8, command = F4.tkraise)
button_3.grid(row = 1, column = 4)

for frame in(F1, F2, F3, F4):
    frame.grid(row = 0, column = 0, sticky = "NSEW")

F1.tkraise()

def get_data():
    #Initialization of Serial Comm
    ser = serial.Serial('COM3', 9600)
    while True:
        pulldata = ser.readline().decode('ascii')
        get_data = pulldata.split(',')
        F2.set(int(get_data[0]))
        F3.set(int(get_data[1]))
        F4.set(int(get_data[2]))
        print(pulldata)

# start the thread that will poll the arduino
t = threading.Thread(target=get_data)
t.daemon = True
t.start()

my_window.mainloop()

The graphs and labels are updating but the problem that now arises is that it's freezing. Also this gives me this error:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py", line 1699, in __call__
    return self.func(*args)
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py", line 745, in callit
    func(*args)
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\backends\_backend_tk.py", line 310, in idle_draw
    self.draw()
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\backends\backend_tkagg.py", line 12, in draw
    super(FigureCanvasTkAgg, self).draw()
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\backends\backend_agg.py", line 433, in draw
    self.figure.draw(self.renderer)
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\artist.py", line 55, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\figure.py", line 1475, in draw
    renderer, self, artists, self.suppressComposite)
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\image.py", line 141, in _draw_list_compositing_images
    a.draw(renderer)
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\artist.py", line 55, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\axes\_base.py", line 2607, in draw
    mimage._draw_list_compositing_images(renderer, self, artists)
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\image.py", line 141, in _draw_list_compositing_images
    a.draw(renderer)
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\artist.py", line 55, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\lines.py", line 738, in draw
    self.recache()
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\matplotlib\lines.py", line 661, in recache
    self._xy = np.column_stack(np.broadcast_arrays(x, y)).astype(float)
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\numpy\lib\stride_tricks.py", line 249, in broadcast_arrays
    shape = _broadcast_shape(*args)
  File "C:\Users\Deanne\AppData\Local\Programs\Python\Python36\lib\site-packages\numpy\lib\stride_tricks.py", line 184, in _broadcast_shape
    b = np.broadcast(*args[:32])
ValueError: shape mismatch: objects cannot be broadcast to a single shape

I can tell that it's still working because it still outputs data. Any help again would be appreciated. Thank you.

解决方案

Here's a wild guess that shows how to make a single thread for polling the arduino and also how to make your code neater by using a class instead of copy / paste:

from tkinter import *
import tkinter as tk # proper way to import tkinter
import serial
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import style
style.use("ggplot")
import threading

class Dee(tk.Frame):
    def __init__(self, master=None, title='', ylabel='', label='', color='c', ylim=1, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)
        self.data = []
        fig = Figure(figsize = (7,6))
        self.plot = fig.add_subplot(111)
        self.plot.set_title(title)
        self.plot.set_ylabel(ylabel)
        self.plot.set_ylim(0, ylim)
        self.line, = self.plot.plot([], [], color, marker = 'o',label = label)
        self.plot.legend(loc='upper left')

        label = Label(self, text = ylabel, relief = "solid", font = "Times 22 bold")
        label.grid(row = 0, column = 3)
        button_1 = Button(self, text = "Back To Homepage", command = F1.tkraise)
        button_1.grid(row = 1, column = 2)
        label_1 = Label(self, text = "Current Value: ", relief = "solid", font = "Verdana 10 bold")
        label_1.grid(row = 2, column = 2)
        self.label_data = Label(self, font = "Verdana 10")
        self.label_data.grid(row = 2, column = 3)
        canvas = FigureCanvasTkAgg(fig, master=self)
        canvas.get_tk_widget().grid(row = 3, column = 3)

        ani = animation.FuncAnimation(fig, self.update_graph, interval = 1000, blit = False)
        canvas.draw()

    def update_graph(self, i):
        if self.data:
            self.line.set_data(range(len(self.data)), self.data)
            self.plot.set_xlim(0, len(self.data))

    def set(self, value):
        self.data.append(value)
        self.label_data.config(text=value)

my_window = Tk()
my_window.title("Graphical User Interface Demo#1")
my_window.geometry("720x720")

F1 = Frame(my_window, relief = RAISED)
F2 = Dee(my_window, title='Temperature Graph', ylabel='Temperature', color='c', label='Degrees C', ylim=40, relief = RAISED)
F3 = Dee(my_window, title='Humidity Graph', ylabel='Humidity', color='g', label='Percentage %', ylim=100, relief = RAISED)
F4 = Dee(my_window, title='Solved Water Graph', ylabel='Water Volume', color='b', label='mL', ylim=55, relief = RAISED)

#For Frame One
label_1 = Label(F1, text = "Homepage of GUI", relief = "solid", font = "Times 22 bold")
label_1.grid(row = 0, column = 3)
button_1 = Button(F1, text = "Page of Humidity", relief = GROOVE, bd = 8, command = F2.tkraise)
button_1.grid(row = 1, column = 2)
button_2 = Button(F1, text = "Page of Temperature", relief = GROOVE, bd = 8, command = F3.tkraise)
button_2.grid(row = 1, column = 3)
button_3 = Button(F1, text = "Page of Water", relief = GROOVE, bd = 8, command = F4.tkraise)
button_3.grid(row = 1, column = 4)

for frame in(F1, F2, F3, F4):
    frame.grid(row = 0, column = 0, sticky = "NSEW")

F1.tkraise()

def get_data():
    #Initialization of Serial Comm
    ser = serial.Serial('COM3', 9600)
    while True:
        pulldata = ser.readline().decode('ascii')
        get_data = pulldata.split(',')
        F2.set(int(get_data[0]))
        F3.set(int(get_data[1]))
        F4.set(int(get_data[3]))

# start the thread that will poll the arduino
t = threading.Thread(target=get_data)
t.daemon = True
t.start()

my_window.mainloop()

这篇关于在 Tkinter 中使用 Arduino 数据动态更新标签和实时图形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆