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
Windy71
  • 851
  • 1
  • 9
  • 30
  • 1
    The key is to reuse the same `canvas` object, but not create a new one every time you execute the `plot` function. – Henry Yik Sep 07 '20 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. – Windy71 Sep 07 '20 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](https://stackoverflow.com/questions/59001195/how-to-update-a-graph-created-by-matplotlib-in-tkinter/59004437#59004437) if you still cannot figure it out. – Henry Yik Sep 07 '20 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. – Windy71 Sep 08 '20 at 09:09

1 Answers1

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
xszym
  • 928
  • 1
  • 5
  • 11