问题
Running the python python script below does not show the embedded matplotlib plot. However it also throws no error message. Upon running the script, it is supposed to display a GUI displaying 4 buttons on the left hand side and a realtime graph on the right hand side. The graph receives its input from a text file 'sample_graph_data.txt'
, which is in the same directory as the script. What's wrong in the script and how do I make it work?
#Script begins here
from tkinter import *
from tkinter import messagebox
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib import animation
from matplotlib import style
from matplotlib.figure import Figure
PROGRAM_NAME = 'Smart Farm Controller'
style.use('ggplot')
fig = Figure(figsize=(5, 30), dpi=100)
a = fig.add_subplot(111)
class Controller:
def __init__(self, root):
self.root = root
self.root.title(PROGRAM_NAME)
self.root.protocol('WM_DELETE_WINDOW', self.exit_app)
self.init_gui()
def create_right_graphs(self):
right_frame = Frame(self.root)
right_frame.grid(row=2, column=6, sticky=N+E+W+S,
padx=2, pady=2)
anim = animation.FuncAnimation(fig, self.animate_graph(right_frame),
interval=1000)
def create_left_switches(self):
left_frame = Frame(self.root)
left_frame.grid(row=2, column=1, columnspan=6, sticky=N+E+W+S,
padx=2, pady=2)
led_button = Button(left_frame, text='LED') #command=self.on_led_button_clicked)
led_button.config(height=2, width=30)
led_button.grid(row=2, column=0, padx=4, pady=8)
apump_button = Button(left_frame, text='Air Pump') #command=self.on_apump_button_clicked)
apump_button.config(height=2, width=30)
apump_button.grid(row=3, column=0, padx=4, pady=8)
wpump_res_button = Button(left_frame, text='Reservoir Water Pump')
#command=self.on_wpump_res_button_clicked)
wpump_res_button.config(height=2, width=30)
wpump_res_button.grid(row=4, column=0, padx=4, pady=8)
wpump_grow_button = Button(left_frame, text='Grow Bucket Water Pump')
#command=self.on_wpump_grow_button_clicked)
wpump_grow_button.config(height=2, width=30)
wpump_grow_button.grid(row=5, column=0, padx=4, pady=8)
def animate_graph(self, right_frame):
pullData = open("sample_graph_data.txt","r").read()
dataList = pullData.split('\n')
xList = []
yList = []
for eachLine in dataList:
if len(eachLine)>1:
x, y = eachLine.split(',')
xList.append(int(x))
yList.append(int(x))
a.clear()
a.plot(xList, yList)
canvas = FigureCanvasTkAgg(fig, right_frame)
canvas.show()
canvas.get_tk_widget().pack(side=RIGHT, fill=BOTH, expand=True)
def init_gui(self):
self.create_right_graphs()
self.create_left_switches()
def exit_app(self):
if messagebox.askokcancel("Quit", "Really quit?"):
self.root.destroy()
if __name__ == '__main__':
root = Tk()
Controller(root)
root.mainloop()
回答1:
There are indeed no errors triggered in the code from the question when being run, but it's also not running as expected. Some errors simply don't get triggered, because the respective part of the code is never called.
There are several issues:
- You need to actually add the
FigureCanvas
to theFrame
outside the animation. - Always keep a reference to the objects you want to work on. Especially the animation must stay alive. This is best be done by making it a class attribute using
self
. - You need to actually place the frames to the root window. This can be done using
pack
. - Inside the FuncAnimation you must not call the function to animate but simply provide it as argument. Also, you need to provide some number of frames to animate for the animation to start.
FuncAnimation(fig, self.animate_graph, frames=12)
instead ofFuncAnimation(fig, self.animate_graph(someargument))
- The animating function needs an argument which is the framenumber (or the list entry from a list that is given by the
frames
argument). You may provide further arguments if needed (in that case refer to the documentation).
I'm sure I forgot to mention some other things as well. But here is a running code.
from tkinter import *
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib import animation
from matplotlib import style
from matplotlib.figure import Figure
style.use('ggplot')
fig = Figure(figsize=(5, 4), dpi=100)
a = fig.add_subplot(111)
class Controller:
def __init__(self, root):
self.root = root
self.create_left_switches()
self.create_right_graphs()
def create_right_graphs(self):
right_frame = Frame(self.root)
right_frame.grid(row=2, column=6, sticky=N+E+W+S,
padx=2, pady=2)
right_frame.pack(fill=X, padx=5, pady=5)
self.canvas = FigureCanvasTkAgg(fig,right_frame )
self.canvas.get_tk_widget().pack(side=RIGHT, fill=BOTH, expand=True)
self.anim = animation.FuncAnimation(fig, self.animate_graph, frames=12,
interval=500, repeat=True)
self.canvas.show()
def create_left_switches(self):
left_frame = Frame(self.root)
left_frame.grid(row=2, column=1, columnspan=6, sticky=N+E+W+S,
padx=2, pady=2)
left_frame.pack(fill=X, padx=5, pady=5)
led_button = Button(left_frame, text='LED') #command=self.on_led_button_clicked)
led_button.config(height=2, width=30)
led_button.grid(row=2, column=0, padx=4, pady=8)
def animate_graph(self, i):
pullData = open("sample_graph_data.txt","r").read()
dataList = pullData.split('\n')
xList = []
yList = []
for eachLine in dataList:
if len(eachLine)>1:
x, y = eachLine.split(',')
xList.append(int(x))
yList.append(int(y)**(1+i/12.))
a.clear()
a.plot(xList, yList)
if __name__ == '__main__':
root = Tk()
Controller(root)
root.mainloop()
来源:https://stackoverflow.com/questions/42599836/embedding-matplotlib-canvas-into-tkinter-gui-plot-is-not-showing-up-but-no-er