Search code examples
pythonmatplotlibtkintercanvasfigure

How to make Tkinter GUI only plot Matplotlib figure once


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

Solution

  • 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