将matplotlib画布嵌入到tkinter GUI中-图未显示,但未引发任何错误 [英] Embedding matplotlib canvas into tkinter GUI - plot is not showing up, but no error is thrown

查看:55
本文介绍了将matplotlib画布嵌入到tkinter GUI中-图未显示,但未引发任何错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

运行下面的 python python 脚本不会显示嵌入的 matplotlib 图.但是,它也不会引发任何错误消息.运行脚本后,应该显示一个GUI,该GUI在左侧显示4个按钮,在右侧显示一个实时图形.该图从文本文件 'sample_graph_data.txt' 接收其输入,该文件与脚本位于同一目录中.脚本中有什么问题以及如何使它起作用?

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()

推荐答案

在运行时,问题中的代码确实没有触发错误,但也未按预期运行.有些错误根本不会被触发,因为代码的相应部分从未被调用.
有几个问题:

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:

  • 您需要实际将 FigureCanvas 添加到动画外的 Frame.
  • 始终保留要处理的对象的引用.尤其是动画必须保持活力.最好通过使用 self 使其成为类属性来实现.
  • 您需要将框架实际放置到根窗口中.可以使用 pack .
  • 在 FuncAnimation 中,您不能调用函数来制作动画,而只是将其作为参数提供.此外,您需要提供一定数量的帧数以开始动画.FuncAnimation(fig, self.animate_graph, frames=12) 而不是 FuncAnimation(fig, self.animate_graph(someargument))
  • 动画函数需要一个参数,它是帧编号(或由 frames 参数给出的列表中的列表条目).如果需要,您可以提供其他参数(在这种情况下,请参考文档).
  • You need to actually add the FigureCanvas to the Frame 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 of 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). 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()

这篇关于将matplotlib画布嵌入到tkinter GUI中-图未显示,但未引发任何错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆