简体   繁体   English

将matplotlib画布嵌入到tkinter GUI中-图未显示,但未引发任何错误

[英]Embedding matplotlib canvas into tkinter GUI - plot is not showing up, but no error is thrown

Running the python python script below does not show the embedded matplotlib plot. 运行以下python python脚本不会显示嵌入式matplotlib图。 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. 运行脚本后,应该显示一个GUI,该GUI在左侧显示4个按钮,在右侧显示一个实时图形。 The graph receives its input from a text file 'sample_graph_data.txt' , which is in the same directory as the script. 该图从文本文件'sample_graph_data.txt'接收其输入,该文件与脚本位于同一目录中。 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()

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 the Frame outside the animation. 您实际上需要将FigureCanvas添加到动画外部的Frame
  • 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 . 最好通过使用self将其设为类属性来完成此操作。
  • You need to actually place the frames to the root window. 您实际上需要将框架放置在根窗口中。 This can be done using pack . 这可以使用pack完成。
  • Inside the FuncAnimation you must not call the function to animate but simply provide it as argument. 在FuncAnimation内部,您不能调用该函数进行动画处理,而只能将其作为参数提供。 Also, you need to provide some number of frames to animate for the animation to start. 另外,您需要提供一些帧来制作动画,以使动画开始。 FuncAnimation(fig, self.animate_graph, frames=12) instead of FuncAnimation(fig, self.animate_graph(someargument)) FuncAnimation(fig, self.animate_graph, frames=12)代替 FuncAnimation(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). 动画功能需要一个参数,该参数是帧编号(或frames参数给定的列表中的列表条目)。 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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM