Fabian
Fabian

Reputation: 13

Matplotlib and Tkinter Real time Plot (AttributeError: 'NoneType' object has no attribute 'update' Exception in Tkinter callback)

I am currently trying to graph the data sent from the submit button, but after reaching 100 iterations the program gives me an error, but if I implement random numbers it works without problem, do you know why this happens ?, any suggestion that can you give me it would be very useful, thanks and regards

import tkinter as tk
import time
import collections
import matplotlib, matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
matplotlib.use('TkAgg')
import matplotlib.animation as animation
import random


class Aplicacion():
    def __init__(self, plotLength = 100):
        self.raiz = tk.Tk()
        self.raiz.configure(bg = 'beige')
        self.raiz.title('Aplicación')

        self.plotMaxLength = plotLength
        self.data = collections.deque([0] * plotLength, maxlen=plotLength)
        self.plotTimer = 0
        self.previousTimer = 0

        self.entry = tk.Entry(self.raiz)
        self.entry.insert(0, '0')
        self.entry.pack(padx=5)
        SendButton = tk.Button(self.raiz, text='Send', command=self.send)
        SendButton.pack(padx=5)
        self.send()
        self.main()

    def send(self):
        self.val = self.entry.get()
        print(self.val)

    def tag1(self, frame, lines, lineValueText, lineLabel, timeText):

        currentTimer = time.clock()
        self.plotTimer = int((currentTimer - self.previousTimer) * 1000)
        self.previousTimer = currentTimer
        timeText.set_text('Muestreo = ' + str(self.plotTimer) + 'ms')

        value, = [self.val]
        #value = random.randint(1, 10)
        self.data.append(value)
        lines.set_data(range(self.plotMaxLength), self.data)
        lineValueText.set_text('[' + lineLabel + '] = ' + str(value))


    def main(self):

        maxPlotLength = 100
        xmin = 0
        xmax = maxPlotLength
        ymin = 0
        ymax = 10

        fig = plt.figure(figsize=(12, 6), dpi=70)
        ax = fig.add_subplot(111)
        ax.set_xlim(xmin, xmax)
        ax.set_ylim(ymin, ymax)
        ax.set_title('Control de Nivel')
        ax.set_xlabel("Tiempo")
        ax.set_ylabel("Variable de Control vs Variable de Proceso")

        lineLabel = 'Set Point (Litros)'
        timeText = ax.text(0.7, 0.95, '', transform=ax.transAxes)
        lines = ax.plot([], [], linewidth=1.0, label=lineLabel)[0]
        lineValueText = ax.text(0.7, 0.90, '', transform=ax.transAxes)
        plt.legend(loc="upper left")

        plt.grid(True)

        canvas = FigureCanvasTkAgg(fig, master=self.raiz)
        canvas.get_tk_widget().pack()
        anim = animation.FuncAnimation(fig, self.tag1, fargs=(lines, lineValueText, lineLabel, timeText),
                                       interval=10, blit=False)

        self.raiz.mainloop()


if __name__ == '__main__':
    Aplicacion()

Upvotes: 0

Views: 1093

Answers (1)

Luke Woodward
Luke Woodward

Reputation: 64959

The error ultimately arises because you are appending string values into self.data and expecting Matplotlib to plot these strings, and it can't do that. (Admittedly however the error message is somewhat cryptic. I only figured it out by adding debugging lines to Matplotlib source files.)

You must ensure the values appended to self.data are numbers, so you will need to convert the string value from self.entry.get() into a number and also handle the case that the string isn't a valid number.

The simplest way to do this is in your send method. Try replacing it with the following:

    def send(self):
        try:
            self.val = float(self.entry.get())
            print(self.val)
        except ValueError:
            messagebox.showwarning("Invalid number", "You entered an invalid number.  Please try again.")

You will also need to add the line import tkinter.messagebox as messagebox. Feel free to translate the error message into another language.

Upvotes: 1

Related Questions