[Tkinter] Matplotlib clear x,y data - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: GUI (https://python-forum.io/forum-10.html) +--- Thread: [Tkinter] Matplotlib clear x,y data (/thread-29648.html) |
Matplotlib clear x,y data - LoneStar - Sep-14-2020 Hi, How do I clear a Matplotlib line chart's data? I have the following lines when a user clicks a button: def on_btn_reset(self): self.ax.clear() self.plotcanvas.draw() def on_btn_start(self): self.anim = animation.FuncAnimation(self.fig, self.animate, interval=1000) self.plotcanvas.draw()The x- and y-axes are cleared when Reset button is clicked. But when I click the Start button after clicking the Resert button, the charts draws with the previous data included and the graph is a mess. I'm including the codes here to reproduce the result. But I'm using a CO2 sensor device hooked up to my raspberry pi 4, so I don't know if this is going to help. The line chart is a real-time line chart that graphs actual CO2 data from the sensor. import serial, sys, glob, select import time import matplotlib.pyplot as plt import matplotlib.animation as animation import matplotlib.pyplot as plt import matplotlib.animation as animation import tkinter as tk import pandas as pd from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.figure import Figure from tkinter import * from tkinter import messagebox from tkinter import ttk from tkinter import font from itertools import count from pandas import DataFrame from datetime import datetime from datetime import timedelta offBulb = "/home/pi/projects/SoilCO2Logger/images/off_bulb.png" redBulb = "/home/pi/projects/SoilCO2Logger/images/red_bulb.png" greenBulb = "/home/pi/projects/SoilCO2Logger/images/green_bulb.png" yellowBulb = "/home/pi/projects/SoilCO2Logger/images/yellow_bulb.png" peakList = [] #use for Excel file co2List = [] #use for Excel file MINCO2 = 50 co2 = 0 sampleNo = 0 resp = [] pk_counter = 0 #peak_time counter bt_counter = 0 #break_time counter xs = [] ys = [] root = tk.Tk() root.wm_title("Soil CO2 Logger" ) root.geometry("800x480") def quit(*args): root.destroy() #Create a display window class Main: def __init__(self, root): self.root = root self.maxt = 30 self.xs = [0] self.ys = [0] self.dt = 1 self.after_id = None self.tt_counter = 0 #Build graph self.fig = plt.Figure(figsize=(5,3), dpi=100) self.ax = self.fig.add_subplot(111) self.ax.set_xlim(1, self.maxt) self.ax.set_title('K-30 CO2 Sensor Readings', fontweight='bold') self.ax.set_xlabel('Time in Seconds') self.ax.set_ylabel('CO2 ppm') #Create a tk.DrawingArea to overlay figure self.plotcanvas = FigureCanvasTkAgg(self.fig, root) self.plotcanvas.get_tk_widget().pack(side=LEFT, fill=Y) self.frame1 = tk.Frame(root) self.lblReadings = tk.Label(self.frame1, text="CO2 Readings") self.lblReadings.grid(row=0, column=0, sticky=W) #Add a listbox to frame1 self.lboxResult = Listbox(self.frame1, width=32, height=9) self.lboxResult.grid(row=1, column=0, sticky=W) #Add a scrollbar to listbox self.ybar = tk.Scrollbar(self.frame1, orient=VERTICAL, command=self.lboxResult.yview) self.lboxResult.config(yscrollcommand = self.ybar.set) self.ybar.grid(row=1, column=1, sticky=W) self.frame1.pack() self.frame2 = tk.Frame(root) self.spacer = tk.Label(self.frame2, text="") self.spacer.grid(row=0, sticky=W) self.lblCoffee = tk.Label(self.frame2, text="Coffee Break (secs):") self.lblCoffee.grid(row=1, sticky=W) self.valBreakTime = tk.Label(self.frame2, bg="white", width=12, borderwidth=1, relief="solid") self.valBreakTime.grid(row=1, column=1, sticky=W) #Start the testing time self.lblTestTime = tk.Label(self.frame2, text="Test Time (hh:mm:ss)") self.lblTestTime.grid(row=2, sticky=tk.W) self.valTestTime = tk.Label(self.frame2, text="", bg="white", width= 12, borderwidth=1, relief="solid") self.valTestTime.grid(row=2, column=1, sticky=tk.W) self.lblPeakTime = tk.Label(self.frame2, text="Countdown to Peak Time") self.lblPeakTime.grid(row=3, sticky=tk.W) self.valPeakTime = tk.Label(self.frame2, bg="white", width= 12, borderwidth=1, relief="solid") self.valPeakTime.grid(row=3, column=1, sticky=tk.W) self.lblCo2 = tk.Label(self.frame2, text="CO2 (ppm)") self.lblCo2.grid(row=4, sticky=tk.W) self.valCo2 = tk.Label(self.frame2, bg="white", width=12, borderwidth=1, relief="solid") self.valCo2.grid(row=4, column=1, sticky=tk.W) self.lblPeakCaptured = tk.Label(self.frame2, text="Peak Captured @ 30-second") self.lblPeakCaptured.grid(row=5, sticky=tk.W) self.valPeakCaptured = tk.Label(self.frame2, bg="white", width= 12, borderwidth=1, relief="solid") self.valPeakCaptured.grid(row=5, column=1, sticky=tk.W) self.frame2.pack() self.frame3 = tk.Frame(root) self.lblInfo = tk.Label(self.frame3, text="Sample #", foreground='blue') self.lblInfo.grid(row=0, column=0, columnspan=2, sticky=tk.W) self.img = PhotoImage(file=offBulb) self.canvas2 = tk.Canvas(self.frame3, width=50, height=70) self.canvas2.create_image(14,14, anchor=NW, image=self.img) self.canvas2.grid(row=1, column=0, sticky=W) self.btnStart = tk.Button(self.frame3, text="Start", command=self.on_btn_start) self.btnStart.grid(row=1, column=1, sticky=W) self.btnStop = tk.Button(self.frame3, text="Stop", command=self.on_btn_stop) self.btnStop.grid(row=1, column=2, sticky=W) self.btnReset = tk.Button(self.frame3, text="Reset", command=self.on_btn_reset) self.btnReset.grid(row=1, column=3, sticky=W) self.btnExit = tk.Button(self.frame3, text="Exit", command=self.on_btn_exit) self.btnExit.grid(row=1, column=4, sticky=W) self.frame3.pack(side="top") def on_btn_start(self): self.tt_counter = 0 self.pk_counter = 0 if not self.after_id: self.increase_counter() #fargs = (xs, ys), self.anim = animation.FuncAnimation(self.fig, self.animate, interval=1000) self.plotcanvas.draw() def on_btn_stop(self): if self.after_id: self.frame3.after_cancel(self.after_id) self.after_id = None self.anim.event_source.stop() #self.stop_test_timer() #Get co2List co2Df = pd.DataFrame(co2List) def on_btn_reset(self): self.on_btn_stop() self.tt_counter = 0 self.display_counter() self.lboxResult.delete(0, END) self.valPeakTime.config(text= '') self.valPeakCaptured.config(text='') self.valCo2.config(text= '') self.lblInfo.config(text = 'Sample #') self.img.config(file=offBulb) self.ax.clear() self.plotcanvas.draw() def increase_counter(self): self.tt_counter += 1 self.display_counter() self.after_id = self.frame3.after(1000, self.increase_counter) def display_counter(self): startTime = datetime.fromtimestamp(self.tt_counter) startTime = startTime.replace(hour=0) ttStr = startTime.strftime("%H:%M:%S") display = ttStr self.valTestTime.config(text=display) def on_btn_exit(self): quit() def getSampleNo(self): global sampleNo co2 = self.valCo2.cget('text') #Note: length of list is NOT zero-based if co2 > MINCO2 and bt_counter == 0 and len(peakList) == 0: sampleNo = 1 if co2 < MINCO2 and bt_counter == 0 and len(peakList) == 0: sampleNo = 1 if co2 < MINCO2 and bt_counter == 0 and len(peakList) > 0: sampleNo += 1 if co2 < MINCO2 and bt_counter > 0 and len(peakList) > 0: if bt_counter == 1: #so it won't increment at every tick sampleNo += 1 return sampleNo def start_test_time(self): def count(): #global tt_counter self.tt_counter = 0 #Manage initial delay if self.tt_counter == 0: display = "Starting " else: startTime = datetime.fromtimestamp(self.tt_counter) startTime = startTime.replace(hour=0) ttStr = startTime.strftime("%H:%M:%S") display = ttStr self.valTestTime.config(text=display) #Trigger after 1 second delay self.after_id = self.valTestTime.after(1000, count) self.tt_counter += 1 #Trigger the start of counter count() def stop_test_time(self): self.start_test_time.stop() def animate(self, i): global co2 #Initialize x,y data self.tt_counter = i #Initialize serial port ser = self.serialCo2_init() counter = 0 #Parse sensor data ser.flushInput() ser.write(b"\xFE\x44\x00\x08\x02\x9f\x25") time.sleep(.1) resp = ser.read(7) co2 = resp[4] self.valCo2.config(text=co2) #Log if CO2 > 600 self.record_co2(co2) #Add x and y to lists xs.append(self.tt_counter) ys.append(co2) #Draw x and y lists self.ax.plot(xs, ys, label='CO2 (ppm)', ms=4, marker='s', color='blue') self.update() def update(self): self.dt = 1 lastt = self.xs[-1] if lastt > self.xs[0] + self.maxt: #reset the arrays self.xs = [self.xs[-1]] self.ys = [self.ys[-1]] self.ax.set_xlim(self.xs[0], self.xs[0] + self.maxt) self.ax.figure.canvas.draw() t = self.xs[-1] + self.dt self.xs.append(t) self.ys.append(ys) def record_co2(self, co2): global bt_counter bt_counter = 0 peak = self.valPeakCaptured.cget('text') self.valCo2.config(text=co2) self.countdown_peaktime() def countdown_peaktime(self): def count(): global pk_counter peak = self.valPeakCaptured.cget('text') info = self.lblInfo.cget('text') sampleNo = self.getSampleNo() co2 = self.valCo2.cget('text') self.valCo2.config(text=co2) #Manage initial delay if pk_counter == 0: pkDisplay = "Countdown..." else: if co2 > MINCO2: startTime = datetime.fromtimestamp(pk_counter) startTime = startTime.replace(hour=0) #Get min:sec part of counter pkMins = startTime.strftime("%M:%S") self.valPeakTime.config(text = pkMins) self.valBreakTime.config(text = '') sampleNo = self.getSampleNo() self.lblInfo.config(text = 'Testing Sample #' + str(sampleNo)) self.img.config(file=redBulb) #Add item to Listbox now = datetime.now() d1 = now.strftime("%d-%m-%y %H:%M:%S") lboxStr = d1 + ' S#' + str(sampleNo) + ' ' + str(co2) self.lboxResult.insert('end', lboxStr) #Add item to peakList carbon = round((co2 / 40) * 0.273, 1) pklistStr = d1 + ' S#' + str(sampleNo) + ' ' + str(co2) + ' ' + str(carbon) co2List.append(lboxStr) peakList.append(pklistStr) #Record peaks captured if pk_counter == 30: lboxStr = d1 + ' S#' + str(sampleNo) + ' ' + str(co2) self.lboxResult.insert('end', lboxStr + ' **PEAK**') self.valPeakCaptured.config(text=co2) self.lblInfo.config(text = 'Sample Captured') self.img.config(file=yellowBulb) #Record subsequent peaks if pk_counter >= 30 and peak != '': #Should stay on yellow until co2 drops below MINCO2 self.lblInfo.config(text = 'Sample Captured') self.img.config(file=yellowBulb) else: self.coffee_break() pk_counter += 1 #Trigger the start of counter count() def coffee_break(self): def bt_count(): global bt_counter peak = self.valPeakCaptured.cget('text') co2 = self.valCo2.cget('text') #Manage initial delay if bt_counter == 0: pkDisplay = "Break..." else: if co2 < MINCO2 and peak > 0: ''' - Replace sample and start coffee break. - Stays green once co2 drops below MINCO2. - Note: change sample at this point but wait until co2 drops below MINCO2 and bulbs turn green before replacing sample ''' bt_counter = 0 if str(peak) != '' or str(peak) == '': self.lblInfo.config(text = 'Ready for Sample') self.img.config(file=greenBulb) #Start coffee break counter self.valBreakTime.config(text = str(bt_counter)) #Hide peak time counter self.valPeakTime.config(text = '') bt_counter += 1 #Trigger the start of counter bt_count() def serialCo2_init(self): #Initialize serial port dev = "/dev/ttyUSB0" scan = glob.glob(dev) rate = "9600" if(len(scan) == 0): dev = '/dev/ttyUSB*' scan = glob.glob(dev) if(len(scan) == 0): messagebox.showerror("Error","Unable to find any ports for /dev/[ttyACM*|ttyUSB*]") + dev sys.exit() serport = scan[0] if(len(sys.argv) > 1): l = len(sys.argv) - 1 while( l > 0): if(sys.argv[l][0] == '/'): serport = sys.argv[l] else: l = l - 1 ser = serial.Serial( port = serport, # or '/dev/ttyUSB0' baudrate = rate, parity = serial.PARITY_NONE, stopbits = serial.STOPBITS_ONE, bytesize = serial.EIGHTBITS, timeout = 1) return ser main = Main(root) root.mainloop()Appreciate any help. |