My aim to is to plot real time data coming from Arduino to a GUI in python. I have developed everything required for it. I want to see some of the values, so defined labels accordingly to display varying input data beside the plotting. I did around 3, but the aim is to do 9 values. But when I try to include the 4th one, am getting an Attribute error.
import copy
from threading import Thread
from tkinter import Frame
import tkinter as Tk
import tkinter.font
import serial
import time
import collections
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import struct
from PIL import ImageTk
from PIL import Image
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from tkinter import Text
import math
import pandas as pd
A=0
B=0
C=0
D=0
Sum = 0
Az = 0
El = 0
angle = 0
ang = 0
Ang = 0
Ta = 0
Tb = 0
Va = 0
Vb = 0
cond = False
class serialPlot:
def __init__(self, serialPort='com7', serialBaud=38400, plotLength=100, dataNumBytes=4, numPlots=9):
self.port = serialPort
self.baud = serialBaud
self.plotMaxLength = plotLength
self.dataNumBytes = dataNumBytes
self.numPlots = numPlots
self.rawData = bytearray(numPlots * dataNumBytes)
self.dataType = None
if dataNumBytes == 2:
self.dataType = 'h' # 2 byte integer
elif dataNumBytes == 4:
self.dataType = 'f' # 4 byte float
self.data = []
self.privateData = None # for storing a copy of the data so all plots are synchronized
for i in range(numPlots): # give an array for each type of data and store them in a list
self.data.append(collections.deque([0] * plotLength, maxlen=plotLength))
self.isRun = True
self.isReceiving = False
self.thread = None
self.plotTimer = 0
self.previousTimer = 0
self.started = False
self.csvData = []
print('Trying to connect to: ' + str(serialPort) + ' at ' + str(serialBaud) + ' BAUD.')
try:
self.serialConnection = serial.Serial(serialPort, serialBaud, timeout=4)
print('Connected to ' + str(serialPort) + ' at ' + str(serialBaud) + ' BAUD.')
except:
print("Failed to connect with " + str(serialPort) + ' at ' + str(serialBaud) + ' BAUD.')
def readSerialStart(self):
if self.thread == None:
self.thread = Thread(target=self.backgroundThread)
self.thread.start()
# Block till we start receiving values
while self.isReceiving != True:
time.sleep(0.1)
def getSerialData(self, frame, lines, lineValueText, lineLabel, timeText, pltNumber):
global cond
if cond == True:
# if pltNumber == 0: # in order to make all the clocks show the same reading
if not self.started:
currentTimer = time.perf_counter()
self.plotTimer = int((currentTimer - self.previousTimer) * 1000) # the first reading will be erroneous
self.previousTimer = currentTimer
self.started = True
self.privateData = copy.deepcopy(
self.rawData) # so that the 4 values in our plots will be synchronized to the same sample time
timeText.set_text('Plot Interval = ' + str(self.plotTimer) + 'ms')
data = self.privateData[(pltNumber * self.dataNumBytes):(self.dataNumBytes + pltNumber * self.dataNumBytes)]
value, = (struct.unpack(self.dataType, (data)))
self.data[pltNumber].append(value) # we get the latest data point and append it to our array
lines.set_data(range(self.plotMaxLength), self.data[pltNumber])
lineValueText.set_text('[' + lineLabel + '] = ' + str(value))
# self.csvData.append([self.data[0][-1], self.data[1][-1], self.data[2][-1]])
if lineLabel == 'Detector A':
global A
A = float(value)
if lineLabel == 'Detector B':
global B
B = float(value)
if lineLabel == 'Detector C':
global C
C = float(value)
if lineLabel == 'Detector D':
global D
D = float(value)
if lineLabel == 'Temp Detector':
global Ta
Ta = float(value)
if lineLabel == 'Temp Servo':
global Tb
Tb = float(value)
if lineLabel == 'Voltage Servo':
global Va
Va = float(value)
if lineLabel == 'Voltage Detector':
global Vb
Vb = float(value)
if lineLabel == 'Angle':
global Ang
Ang = float(value)
Sum = (A + B + C + D)
Az = (A + D - C - B)
El = (A + B - C - D)
def backgroundThread(self): # retrieve data
time.sleep(0.8) # give some buffer time for retrieving data
self.serialConnection.reset_input_buffer()
while (self.isRun):
self.serialConnection.readinto(self.rawData)
self.isReceiving = True
def Sum(self):
global A, B, C, D
return '%.6f' % (A + B + C + D)
def Az(self):
global A, B, C, D
return '%.6f' % (A - B - C + D)
def El(self):
global A, B, C, D
return '%.6f' % (A + B - C - D)
def A(self):
global A
return '%.6f' % (A)
def B(self):
global B
return '%.6f' % (B)
def C(self):
global C
return '%.6f' % (C)
def D(self):
global D
return '%.6f' % (D)
def Ang(self):
global Ang
return '%.6f' % (Ang)
def TA(self):
global Ta
return '%.6f' % (Ta)
def TB(self):
global Tb
return '%.6f' % (Tb)
def VA(self):
global Va
return '%.6f' % (Va)
def VB(self):
global Vb
return '%.6f' % (Vb)
''''
def m1(self):
x = A - B - C + D
y = A + B - C - D
if x > 0 and y > 0:
angle = math.degrees(math.atan(y / x))
elif (x < 0 and y > 0) or (x < 0 and y < 0):
angle = math.degrees(math.atan(y / x)) + 180
elif x > 0 and y < 0:
angle = math.degrees(math.atan(y / x)) + 360
elif x == 0:
angle = 0
return int(angle)
def m1(self):
angle=0
global A,B,C,D
x = A-B-C+D
y = A+B-C-D
if x > 0 and y > 0:
angle = math.degrees(math.atan(y / x))
elif (x < 0 and y > 0) or (x < 0 and y < 0):
angle = math.degrees(math.atan(y / x)) + 180
elif x > 0 and y < 0:
angle = math.degrees(math.atan(y / x)) + 360
elif x==0:
angle=0
return angle
def m2(self):
angle1=0
global A,B,C,D
x1 = math.log10((A + D) / (B + C))
y1 = math.log10((A + B) / (D + C))
if x1==0 or (B+C)==0 or (D+C)==0:
angle1=0
elif x1 > 0 and y1 > 0:
angle1 = math.degrees(math.atan(y1 / x1))
elif (x1 < 0 and y1 > 0) or (x1 < 0 and y1 < 0):
angle1 = math.degrees(math.atan(y1 / x1)) + 180
elif x1 > 0 and y1 < 0:
angle1 = math.degrees(math.atan(y1 / x1)) + 360
return angle1
'''''
def close(self):
self.isRun = False
self.thread.join()
self.serialConnection.close()
print('Disconnected...')
# df = pd.DataFrame(self.csvData)
# df.to_csv('/home/Abhinav Kumar/Desktop/data.csv')
def plot_start():
global cond
cond = True
def plot_stop():
global cond
cond = False
def makeFigure(xLimit, yLimit, title):
xmin, xmax = xLimit
ymin, ymax = yLimit
fig = plt.figure(dpi=100)
fig.set_figheight = 1
fig.set_figwidth = 3
ax = plt.axes(xlim=(xmin, xmax), ylim=(int(ymin - (ymax - ymin) / 10), int(ymax + (ymax - ymin) / 10)))
ax.set_title(title)
ax.set_xlabel("Time")
ax.set_ylabel("Detector Output")
ax.grid(True)
return fig, ax
class Window(Frame):
def __init__(self, flist, master, SerialReference):
Frame.__init__(self, master)
self.entry = None
self.setPoint = None
self.master = master # a reference to the master window
self.serialReference = SerialReference # keep a reference to our serial connection so that we can use it for bi-directional communicate from this class
self.initWindow(flist) # initialize the window with our settings
def initWindow(self, flist):
self.master.title("Detector Data")
p = {1: [50, 120], 2: [480, 120], 3: [900, 120], 4: [50, 430], 5: [480, 430], 6: [900, 430], 7: [50, 750],
8: [480, 750], 9: [900, 750]}
x = 1
for item in flist:
canvas = FigureCanvasTkAgg(item, master=self.master)
# toolbar = NavigationToolbar2TkAgg(canvas, self.master)
canvas.get_tk_widget().place(x=p[x][0], y=p[x][1], width=400, height=300)
canvas.draw()
x += 1
def main():
portName = 'COM7'
# portName = '/dev/ttyUSB0'
baudRate = 38400
maxPlotLength = 100 # number of points in x-axis of real time plot
dataNumBytes = 4 # number of bytes of 1 data point
numPlots = 9 # number of plots in 1 graph
s = serialPlot(portName, baudRate, maxPlotLength, dataNumBytes, numPlots) # initializes all required variables
s.readSerialStart() # starts background thread
# plotting starts below
pltInterval = 1 # Period at which the plot animation updates [ms]
lineLabelText = ['Detector A', 'Detector B', 'Detector C', 'Detector D', 'Temp Detector', 'Temp Servo',
'Voltage Servo', 'Volatge detector', 'Angle']
title = ['Detector A', 'Detector B', 'Detector C', 'Detector D', 'Temp Detector', 'Temp Servo', 'Voltage Servo',
'Volatge detector', 'Angle']
xLimit = [(0, maxPlotLength), (0, maxPlotLength), (0, maxPlotLength), (0, maxPlotLength), (0, maxPlotLength),
(0, maxPlotLength), (0, maxPlotLength), (0, maxPlotLength), (0, maxPlotLength)]
yLimit = [(0, 3), (0, 3), (0, 3), (0, 3), (0, 60), (0, 60), (0, 8), (0, 8), (-120, 120)]
style = ['r-', 'g-', 'b-', 'y-', 'r-', 'g-', 'b-', 'y-', 'r-'] # linestyles for the different plots
# anim = []
root = Tk.Tk()
image = Image.open("kalyani(3).gif")
test = ImageTk.PhotoImage(image)
label = Tk.Label(image=test)
label.image = test
label.place(x=25, y=25)
image = Image.open("a.gif")
test = ImageTk.PhotoImage(image)
label = Tk.Label(image=test)
label.image = test
label.place(x=1350, y=40)
image = Image.open("b.gif")
test = ImageTk.PhotoImage(image)
label = Tk.Label(image=test)
label.image = test
label.place(x=1650, y=40)
image = Image.open("c.gif")
test = ImageTk.PhotoImage(image)
label = Tk.Label(image=test)
label.image = test
label.place(x=1400, y=170)
root.configure(background='light blue')
# root.geometry('1920x1080')
w = Tk.Label(root, text="LASER SEEKER GUI", fg='black', bg='light blue')
desired_font = tkinter.font.Font(family="Arial Bold", size=40, weight='bold')
w.configure(font=desired_font)
w.pack(pady=15)
labelf = Tk.Label(root, text='A:', fg='black', bg='light blue')
desired_font = tkinter.font.Font(family="calibri", size=25, weight='bold')
labelf.configure(font=desired_font)
labelf.place(x=1350, y=450)
label4 = Tk.Label(root, text='ELE', fg='black', bg='light blue')
desired_font = tkinter.font.Font(family="calibri", size=25, weight='bold')
label4.configure(font=desired_font)
label4.place(x=1500, y=450)
def a():
label4.config(text=s.A())
root.after(1, a)
a()
labels = Tk.Label(root, text='SUM:', fg='black', bg='light blue')
desired_font = tkinter.font.Font(family="calibri", size=25, weight='bold')
labels.configure(font=desired_font)
labels.place(x=1350, y=300)
label1 = Tk.Label(root, text='SUM', fg='black', bg='light blue')
desired_font = tkinter.font.Font(family="calibri", size=25, weight='bold')
label1.configure(font=desired_font)
label1.place(x=1500, y=300)
def sum():
label1.config(text=s.Sum())
root.after(1, sum)
sum()
labela = Tk.Label(root, text='AZ:', fg='black', bg='light blue')
desired_font = tkinter.font.Font(family="calibri", size=25, weight='bold')
labela.configure(font=desired_font)
labela.place(x=1350, y=350)
label2 = Tk.Label(root, text='AZ', fg='black', bg='light blue')
desired_font = tkinter.font.Font(family="calibri", size=25, weight='bold')
label2.configure(font=desired_font)
label2.place(x=1500, y=350)
def az():
label2.config(text=s.Az())
root.after(1, az)
az()
labele = Tk.Label(root, text='ELE:', fg='black', bg='light blue')
desired_font = tkinter.font.Font(family="calibri", size=25, weight='bold')
labele.configure(font=desired_font)
labele.place(x=1350, y=400)
label3 = Tk.Label(root, text='ELE', fg='black', bg='light blue')
desired_font = tkinter.font.Font(family="calibri", size=25, weight='bold')
label3.configure(font=desired_font)
label3.place(x=1500, y=400)
def el():
label3.config(text=s.El())
root.after(1, el)
el()
start = Tk.Button(root, width=10, height=3, activebackground='green', fg='black', text="START",
font=('calibri', 12), command=lambda: plot_start())
start.place(x=1800, y=600)
# root.update();
stop = Tk.Button(root, width=10, height=3, activebackground='red', text="STOP", fg='black', font=('calibri', 12),
command=lambda: plot_stop())
stop.place(x=1800, y=700)
# root.update()
exit = Tk.Button(root, width=10, height=3, activebackground='yellow', fg='black', text="EXIT", font=('calibri', 12),
command=root.destroy)
exit.place(x=1800, y=900)
flist = []
axlist = []
a = []
b = []
c = []
anim = []
for i in range(9):
fig, ax = makeFigure(xLimit[i], yLimit[i], title[i])
lines = ax.plot([], [], style[i], label=lineLabelText[i])[0]
timeText = ax.text(0.40, 0.95, '', transform=ax.transAxes)
lineValueText = ax.text(0.40, 0.90, '', transform=ax.transAxes)
flist.append(fig)
axlist.append(axlist)
a.append(lines)
b.append(timeText)
c.append(lineValueText)
app = Window(flist, root, s)
for i in range(9):
anim.append(animation.FuncAnimation(flist[i], s.getSerialData, frames=200,
fargs=(a[i], c[i], lineLabelText[i], b[i], i),
interval=pltInterval)) # fargs has to be a tuple
# plt.legend(loc="upper left")
# plt.show()
root.mainloop()
s.close()
if __name__ == '__main__':
main()
Am getting error for the A label. How do I solve this? Thanks in advance.
The error is happening for this part of code:
labelf = Tk.Label(root, text='A:', fg='black', bg='light blue')
desired_font = tkinter.font.Font(family="calibri", size=25, weight='bold')
labelf.configure(font=desired_font)
labelf.place(x=1350, y=450)
label4 = Tk.Label(root, text='ELE', fg='black', bg='light blue')
desired_font = tkinter.font.Font(family="calibri", size=25, weight='bold')
label4.configure(font=desired_font)
label4.place(x=1500, y=450)
def a():
label4.config(text=s.A())
root.after(1, a)
a()
And the traceback is this:
Traceback (most recent call last):
File "C:\Program Files\Python39\lib\tkinter\__init__.py", line 1892, in __call__
return self.func(*args)
File "C:\Program Files\Python39\lib\tkinter\__init__.py", line 814, in callit
func(*args)
File "C:\Users\Abhinav Kumar\PycharmProjects\realtimemultiple\Nag2.py", line 351, in a
root.after(1, a)
File "C:\Program Files\Python39\lib\tkinter\__init__.py", line 820, in after
callit.__name__ = func.__name__
AttributeError: 'list' object has no attribute '__name__'
Traceback (most recent call last)to the last line before you are back in the Terminal or Command Prompt.