1

I use tkinter to build a simple GUI window with 3 buttons, and use matplotlib to show a simple figure. The process is: Push the 1st button to enable the 2nd button. Push the 2nd button to show a figure, and then enable the 3rd button. Push the 3rd button to show a figure and save the figure. However, the 3rd button can't be enabled after pushing the 2nd button. If I close the program, the errors occur. Another problem: why the saved picture is empty? Thanks.

import matplotlib.pyplot as plt
from tkinter import *
import numpy as np

class MyGUI:
    def __init__(self):
        Win=Tk()
        Win.geometry('750x640')
        Win.resizable(False,False)
        Win.update()
        w=Win.winfo_width()
        h=Win.winfo_height()

        Btn1=Button(Win,text='enable button 2',command=self.Btn1Listener)
        Btn1.place(x=20,y=20)
        Btn1.update()

        self.Btn2=Button(Win,text='Plot 1',command=self.Btn2Listener)
        self.Btn2.place(x=Btn1.winfo_x()+Btn1.winfo_width()+10,y=20,width=150)
        self.Btn2.configure(state='disabled')
        self.Btn2.update()

        self.Btn3=Button(Win,text='plot 2',command=self.Btn3Listener)
        self.Btn3.place(x=self.Btn2.winfo_x()+self.Btn2.winfo_width()+10,y=20,width=150)
        self.Btn3.configure(state='disabled')
        self.Btn3.update()        

        mainloop()

    #------------------------------------------------------- 
    def Btn1Listener(self):
        self.Btn2.configure(state='normal')

    def Btn2Listener(self):
        global v,s
        v,s=self.B1()
        self.Btn3.configure(state='normal')

    def Btn3Listener(self):
        self.B2(s,v)

    #-------------------------------------------------------------
    def B1(self):                  
        x=np.arange(0,5,0.1)
        y1=np.sin(x)
        plt.plot(x,y1)
        plt.show()

        return 0,5 

    def B2(self, s,v):
        x=np.arange(s,v,0.1)
        y1=np.sin(x)
        plt.plot(x,y1)
        plt.show()   
        plt.savefig('aaa.png')


#------------------------------------------------------------------        
if __name__ =='__main__':   
    MyApp=MyGUI()

1 Answer 1

1

From the docs of plt.show() you can see that what this function does is:

display all figures and block

Because Tkinter relies on the mainloop to run, this doesn't work well with blocking functions such as plt.show().

Again from the docs:

A single experimental keyword argument, block, may be set to True or False to override the blocking behavior described above.

Which means you can call plt.show(block=False) to make it not block the Tkinter mainloop.

However, there is a way neater option to integrate matplotlib in Tkinter, an example can be found here. In the most simple implementation, this would translate to your code something like this:

from tkinter import *
import numpy as np

from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2TkAgg)

class MyGUI:
    def __init__(self):
        win = Tk()
        win.geometry('750x640')
        win.resizable(False,False)
        win.update()
        w = win.winfo_width()
        h = win.winfo_height()

        btn1 = Button(win,text='Enable button 2',command=self.btn1Listener)
        btn1.place(x=20, y=20)
        btn1.update()

        self.btn2 = Button(win,text='Plot 1',command=self.btn2Listener)
        self.btn2.place(x=btn1.winfo_x()+btn1.winfo_width()+10, y=20, width=150)
        self.btn2.configure(state='disabled')
        self.btn2.update()

        self.btn3 = Button(win,text='Plot 2',command=self.btn3Listener)
        self.btn3.place(x=self.btn2.winfo_x()+self.btn2.winfo_width()+10, y=20, width=150)
        self.btn3.configure(state='disabled')
        self.btn3.update()


        self.fig = Figure(figsize=(5, 4), dpi=100)
        self.ax = self.fig.add_subplot(111)

        self.canvas = FigureCanvasTkAgg(self.fig, master=win)  # A tk.DrawingArea.
        self.canvas.draw()
        self.canvas.get_tk_widget().place(x=20, y=80)

        win.mainloop()

    #------------------------------------------------------- 
    def btn1Listener(self):
        self.btn2.configure(state='normal')

    def btn2Listener(self):
        self.s, self.v = self.B1()
        self.btn3.configure(state='normal')

    def btn3Listener(self):
        self.B2(self.s, self.v)

    #-------------------------------------------------------------
    def B1(self):                  
        x=np.arange(0, 5, 0.1)
        y1=np.sin(x)
        self.ax.plot(x, y1)
        self.canvas.draw()
        return 0,5 

    def B2(self, s, v):
        x=np.arange(s, v, 0.1)
        y1=np.cos(x)
        # Use this if you want to remove the first plot
        # self.ax.clear()
        self.ax.plot(x, y1)
        self.canvas.draw()
        self.fig.savefig('aaa.png')


#------------------------------------------------------------------        
if __name__ =='__main__':   
    MyApp=MyGUI()

P.S. I wouldn't recommend using place because it gets very difficult to manage in the long run and doesn't like resizing windows. Try setting up your GUI using grid and/or pack instead.

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.