2

I'm making a simple GUI using tkinter and matplotlib. I want to plot inside a LabelFrame, but when I try to plot again using a new entries, it overlap the new graph with the old one. How can I plot just the last graph? I'm almost sure the problem it the last lines of code or the way how I declare the frame. My plan is to have a window with more a graphs, each one in their own frame.

Here's what I have tired :

from tkinter import *
import tkinter as Tk
from tkinter import ttk
from matplotlib import pyplot as plt
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

def main():

    root = Tk.Tk()
    gui = Window(root)
    gui.root.mainloop()

    return None
class Window:
    def __init__(self,root):
        self.root = root
        self.root.title("Overpressure Estimation")
        self.root.geometry('1400x500')

        parameters_frame =LabelFrame(self.root, text="Blast parameters", padx=20,pady=20)
        parameters_frame.pack(padx=1,pady=1)
        self.parameters_frame = parameters_frame

        graph_frame =LabelFrame(self.root, text="Graphs", padx=20,pady=20)
        graph_frame.pack(padx=10,pady=10)

        self.graph_frame = graph_frame

        self.charge = 100
        self.distance = 100
        self.kasite = 516
        self.asite = -1.45


        charge = Label(self.parameters_frame ,  text = "Charge Q (Kg)")
        self.charge_entry = Entry(self.parameters_frame ,  width = 15)
        self.charge_entry.grid(row=0, column=1)
        charge.grid(row=0, column=0)

        distance = Label(self.parameters_frame ,  text = "Distance (m)")
        self.distance_entry = Entry(self.parameters_frame ,  width = 15)
        self.distance_entry.grid(row=1, column=1)
        distance.grid(row=1, column=0)

        kasite = Label(self.parameters_frame ,  text = "Site constant (K)")
        self.kasite_entry = Entry(self.parameters_frame ,  width = 15)
        self.kasite_entry.grid(row=2, column=1)
        kasite.grid(row=2, column=0)

        asite = Label(parameters_frame ,  text = "Site exponent (a)")
        self.asite_entry = Entry(self.parameters_frame ,  width = 15)
        self.asite_entry.grid(row=3, column=1)
        asite.grid(row=3, column=0)



        button1 = Button(self.parameters_frame, text = "Calculate",command = self.update_values)
        parameters_frame.bind("<Return>", self.update_values)
        self.plot_values()
        button1.grid(row=5, column=1)
        pass

    def update_values(self, event=None):

        self.charge = int(self.charge_entry.get())
        self.distance = int(self.distance_entry.get())
        self.kasite = int(self.kasite_entry.get())
        self.asite = float(self.asite_entry.get())
        self.plot_values()
        return None

    pass

    def plot_values(self):

        # GRAPH
        z1 = [np.round(10 * np.log10((((((i/(self.charge**(1/3)))**self.asite) * self.kasite)/(0.00002))**2)),0) 
                       for i in np.arange(0.1,self.distance + 1) ]

        line_1 = [120 for i in range(1,self.distance + 1)]
        line_2 = [125 for i in range(1,self.distance + 1)]
        line_3 = [133 for i in range(1,self.distance + 1)]
        x1 = np.arange(1, self.distance + 1) 

        figure1 = plt.figure(figsize = (6,5), dpi = 100)
        figure1.add_subplot(111)

        plt.plot(z1,label="Decay Curve")
        plt.plot(x1, line_3,'b--',label="130 dbL: Maximum for Structural Damage Level" )
        plt.plot(x1, line_2,'r--',label="125 dbL: Maximum for Human Comfort Level" )
        plt.plot(x1, line_1,'g--',label="120 dbL: Annoying" )
        plt.legend()
        plt.xlabel('Distance (m)')
        plt.ylabel('Sound  Pressure Level(dBL)',labelpad=1)
        plt.title('SPL DECAY')
        plt.xscale('log')
        plt.grid(True, which="both", ls="-")

        chart = FigureCanvasTkAgg(figure1,self.graph_frame)
        chart.get_tk_widget().pack()
   
      
        return None
    pass
main()
imxitiz
  • 3,920
  • 3
  • 9
  • 33
  • Are you trying to, clear and make another graph when clicked in calculate? – imxitiz Jul 30 '21 at 17:28
  • What you should be doing is to re-use the same `canvas` when you plot again. Take a look at [this](https://stackoverflow.com/questions/59001195/how-to-update-a-graph-created-by-matplotlib-in-tkinter/59004437#59004437) if you need. – Henry Yik Jul 30 '21 at 17:41
  • @Xitiz yes, something like that – StonedBored Jul 30 '21 at 18:04
  • I think that link provided by OP solved almost your problem but I am confused in how to plot that data again. I will post the answer, check that, if it doesn't solved your problem then I may delete it? @StonedBored I am tkinter user I haven't used "FigureCanvasTkAgg" but now I understand basics. – imxitiz Jul 30 '21 at 18:07
  • @StonedBored check my answer, it is working as you expect, right? – imxitiz Jul 30 '21 at 18:49

1 Answers1

1

You can try this :

from tkinter import *
import tkinter as Tk
from tkinter import ttk
from matplotlib import pyplot as plt
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

def main():

    root = Tk.Tk()
    gui = Window(root)
    gui.root.mainloop()

    return None
class Window:
    def __init__(self,root):
        self.root = root
        self.root.title("Overpressure Estimation")
        self.root.geometry('1400x500')

        parameters_frame =LabelFrame(self.root, text="Blast parameters", padx=20,pady=20)
        parameters_frame.pack(padx=1,pady=1)
        self.parameters_frame = parameters_frame

        graph_frame =LabelFrame(self.root, text="Graphs", padx=20,pady=20)
        graph_frame.pack(padx=10,pady=10)

        self.graph_frame = graph_frame

        self.charge = 100
        self.distance = 100
        self.kasite = 516
        self.asite = -1.45

        charge = Label(self.parameters_frame ,  text = "Charge Q (Kg)")
        self.charge_entry = Entry(self.parameters_frame ,  width = 15)
        self.charge_entry.grid(row=0, column=1)
        self.charge_entry.insert(0,7)
        charge.grid(row=0, column=0)

        distance = Label(self.parameters_frame ,  text = "Distance (m)")
        self.distance_entry = Entry(self.parameters_frame ,  width = 15)
        self.distance_entry.grid(row=1, column=1)
        distance.grid(row=1, column=0)
        self.distance_entry.insert(0,7)
        kasite = Label(self.parameters_frame ,  text = "Site constant (K)")
        self.kasite_entry = Entry(self.parameters_frame ,  width = 15)
        self.kasite_entry.grid(row=2, column=1)
        kasite.grid(row=2, column=0)
        self.kasite_entry.insert(0,7)
        asite = Label(parameters_frame ,  text = "Site exponent (a)")
        self.asite_entry = Entry(self.parameters_frame ,  width = 15)
        self.asite_entry.grid(row=3, column=1)
        asite.grid(row=3, column=0)
        self.asite_entry.insert(0,7)

        button1 = Button(self.parameters_frame, text = "Calculate",command = self.update_values)
        parameters_frame.bind("<Return>", self.update_values)
 
        button1.grid(row=5, column=1)
        
        self.test()
        frame=Frame(self.graph_frame)
        frame.pack()
        self.frame=frame
        chart = FigureCanvasTkAgg(self.figure1,self.frame)
        chart.get_tk_widget().pack()
    
        self.chart =chart

    def update_values(self, event=None):

        self.charge = int(self.charge_entry.get())
        self.distance = int(self.distance_entry.get())
        self.kasite = int(self.kasite_entry.get())
        self.asite = float(self.asite_entry.get())
        self.plot_values()
        return None
    
    def test(self):
        z1 = [np.round(10 * np.log10((((((i/(self.charge**(1/3)))**self.asite) * self.kasite)/(0.00002))**2)),0) for i in np.arange(0.1,self.distance + 1) ]
        line_1 = [120 for i in range(1,self.distance + 1)]
        line_2 = [125 for i in range(1,self.distance + 1)]
        line_3 = [133 for i in range(1,self.distance + 1)]
        x1 = np.arange(1, self.distance + 1) 
        figure1 = plt.figure(figsize = (6,5), dpi = 100)
        figure1.add_subplot(111)
        
        self.figure1=figure1
        plt.plot(z1,label="Decay Curve")
        plt.plot(x1, line_3,'b--',label="130 dbL: Maximum for Structural Damage Level" )
        plt.plot(x1, line_2,'r--',label="125 dbL: Maximum for Human Comfort Level" )
        plt.plot(x1, line_1,'g--',label="120 dbL: Annoying" )
        plt.legend()
        plt.xlabel('Distance (m)')
        plt.ylabel('Sound  Pressure Level(dBL)',labelpad=1)
        plt.title('SPL DECAY')
        plt.xscale('log')
        plt.grid(True, which="both", ls="-")

    def plot_values(self):
        self.test()
        self.frame.destroy()
        frame=Frame(self.graph_frame)
        frame.pack()
        self.frame=frame
        chart = FigureCanvasTkAgg(self.figure1,self.frame)
        chart.get_tk_widget().pack()

        return None
    pass
main()

We have done some trick, we have made new frame as parent frame for FigureCanvasTkAgg and if we have to create new FigureCanvasTkAgg then we can destroy parent frame and make new Frame and FigureCanvasTkAgg

imxitiz
  • 3,920
  • 3
  • 9
  • 33
  • There could be unnecessary `self`. I personally don't use OOP so, you can remove those, if you found any you can inform me, I will remove that from here as well. – imxitiz Jul 30 '21 at 18:45
  • Woooow thank you! I really appreciate it, its what i was lookin for. This is my first project with tkinter and i tried with OOP, maybe you are right and is much easier without that. But thank you so much. – StonedBored Jul 30 '21 at 18:59