0

I have some Tkinter code which makes a 4tabbed gui. In the GUI tab2 has a button to plot a simplified graph, which works, but when I click the button again it reprints the canvas and figure directly below the first plot. I have looked at how to remove the plot with a Close or clear button but really need it to just plot once (even if the button is clicked again).

Code

import tkinter as tk                     
from tkinter import ttk 
import matplotlib
matplotlib.use("TkAgg")  # this is the backend of matplotlib
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import style


root = tk.Tk() 
root.title("Tab Widget")
root.geometry("1300x950") 
tabControl = ttk.Notebook(root) 
  
tab1 = ttk.Frame(tabControl) 
tab2 = ttk.Frame(tabControl)
tab3 = ttk.Frame(tabControl) 
tab4 = ttk.Frame(tabControl) 
  
tabControl.add(tab1, text ='Tab 1') 
tabControl.add(tab2, text ='Tab 2')
tabControl.add(tab3, text ='Tab 3')
tabControl.add(tab4, text ='Tab 4')


tabControl.pack(expand = 1, fill ="both") 
  
ttk.Label(tab1, text ="This is a  tab\n (1)").grid(column = 0, row = 0, padx = 30, pady = 30)   
ttk.Label(tab2, text ="This is another tab\n (2)").grid(column = 0, row = 0,  padx = 30, pady = 30) 
ttk.Label(tab3, text ="This is another tab\n (3)").grid(column = 0, row = 0,  padx = 30, pady = 30) 
ttk.Label(tab4, text ="This is another tab\n (4)").grid(column = 0, row = 0,  padx = 30, pady = 30)  


label_b1 = ttk.Label(tab1, text = "Button label 0,1").grid(column = 0, row = 1, padx = 30, pady = 30)
label_b1 = ttk.Label(tab1, text = "Button label 1,1").grid(column = 1, row = 1, padx = 30, pady = 30)
label_b1 = ttk.Label(tab1, text = "Button label 1,2").grid(column = 2, row = 1, padx = 30, pady = 30)


def plot(): 
    # the figure that will contain the plot 
    fig = Figure(figsize = (5, 5), dpi = 100) 
     
    y = [i**2 for i in range(101)] # list of squares
    
    # adding the subplot 
    plot1 = fig.add_subplot(111) 
    # plotting the graph 
    plot1.plot(y) 
    canvas = FigureCanvasTkAgg(fig, master = tab2)  # creating the Tkinter canvas containing the Matplotlib figure  
    canvas.draw() 
    canvas.get_tk_widget().grid()  # placing the canvas on the Tkinter window 


plot_button = tk.Button(master = tab2,  command = plot, height = 2,  width = 10, text = "Plot") 
plot_button.grid()   # place the button in main window 
root.mainloop() 

Desired output

Pressing the Plot button a second time would not result in the graph appearing underneath the first plot.

idea from xszym

was_plotted = False

def plot():
    global was_plotted
    if(was_plotted) == False:
            # the figure that will contain the plot 
        fig = Figure(figsize = (5, 5), dpi = 100) 
        
        y = [i**2 for i in range(101)] # list of squares
        
        # adding the subplot 
        plot1 = fig.add_subplot(111) 
        # plotting the graph 
        plot1.plot(y) 
        canvas = FigureCanvasTkAgg(fig, master = tab2)  # creating the Tkinter canvas containing the Matplotlib figure  
        canvas.draw() 
        canvas.get_tk_widget().grid()  # placing the canvas on the Tkinter window 

        
        was_plotted = True
4
  • 1
    The key is to reuse the same canvas object, but not create a new one every time you execute the plot function. Commented Sep 7, 2020 at 16:12
  • I don't know how to do that, I can see now how to do it with the flag setting that xszym mentioned. Commented Sep 7, 2020 at 16:20
  • 1
    The flag has nothing to do and does not help with reusing the same object. Simply move your canvas creation and grid method outside your function, and when you plot it, clear the canvas and draw on it. Take a look at this if you still cannot figure it out. Commented Sep 7, 2020 at 16:30
  • Hi Henry Yik, I used your idea and it worked, if you repost your comment as an answer I will gladly accept it. Commented Sep 8, 2020 at 9:09

1 Answer 1

1

You can solve it by setting a global flag was_plotted

was_plotted = False

def plot():
    global was_plotted
    if(was_plotted):
        return 
    was_plotted = True
Sign up to request clarification or add additional context in comments.

Comments

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.