0

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__'
10
  • Please give us a minimum reproducible example... Commented Aug 14, 2021 at 5:53
  • ...and the full error traceback. Commented Aug 14, 2021 at 6:00
  • @DaniyalWarraich I didn't get what you said Commented Aug 14, 2021 at 6:04
  • @KlausD. What do you mean by full error traceback Commented Aug 14, 2021 at 6:05
  • A minimum reproducible example is code that represents the problem, but is small, short, and understandable. The full error traceback is the error, and the full traceback starts as Traceback (most recent call last) to the last line before you are back in the Terminal or Command Prompt. Commented Aug 14, 2021 at 6:33

1 Answer 1

1

When you do this:

def a(): 
    label4.config(text=s.A()) 
    root.after(1, a) a()

You defined a as an function that is callable to your interpreter. But later in your code you define a as a list that isn't callable. a = []

So you basically have overwritten your variable and you try to access the older content of that variable which isn't possible. So when you do this:

a = 1
a = 2

then a will become 2 and 1 is gone except you would resign it to 1.

Got it?

Sign up to request clarification or add additional context in comments.

1 Comment

Upvoted for reading all the way to through the code and highlighting the error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.