Reputation: 13
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()
Upvotes: 1
Views: 3779
Reputation: 10592
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.
Upvotes: 1