将matplotlib动画嵌入到tkinter框架中

10

我正在开发一个简单的谐振模拟器,用于模拟物体随时间振动的情况。目前已经成功获取了数据,并在tkinter框架内绘制出了静态图形。但是,我的目标是将其显示为随时间变化的动画。

为了方便起见,我使用以下代码创建了一个程序的模型:

#---------Imports
from numpy import arange, sin, pi
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import tkinter as Tk
from tkinter import ttk
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
#---------End of imports

fig, ax = plt.subplots()

x = np.arange(0, 2*np.pi, 0.01)        # x-array
line, = ax.plot(x, np.sin(x))

def animate(i):
    line.set_ydata(np.sin(x+i/10.0))  # update the data
    return line,

ani = animation.FuncAnimation(fig, animate, np.arange(1, 200), interval=25, blit=False)
#plt.show() #What I want the object in tkinter to appear as

root = Tk.Tk()

label = ttk.Label(root,text="SHM Simulation").grid(column=0, row=0)

canvas = FigureCanvasTkAgg(fig, master=root)
canvas.show()
canvas.get_tk_widget().grid(column=0,row=1)

Tk.mainloop()
这段代码将在tkinter框架中显示所需的动画,当plt.show()被取消注释时。我希望能够将该动画嵌入到tkinter框架中。我已经查看了matplotlib网站上的所有动画示例,但都没有帮助。我还在Embedding an animated matplotlib in tk上查询过,但那个把tkinter按钮置于pyplot图形之内,我想要把图形放在tkinter框架里面。所以,为澄清起见,我想将plt.show()产生的动画放置在一个tkinter框架中,即root = tk()
3个回答

9

我修改了你的代码:

#---------Imports
from numpy import arange, sin, pi
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import tkinter as Tk
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
#---------End of imports

fig = plt.Figure()

x = np.arange(0, 2*np.pi, 0.01)        # x-array

def animate(i):
    line.set_ydata(np.sin(x+i/10.0))  # update the data
    return line,

root = Tk.Tk()

label = Tk.Label(root,text="SHM Simulation").grid(column=0, row=0)

canvas = FigureCanvasTkAgg(fig, master=root)
canvas.get_tk_widget().grid(column=0,row=1)

ax = fig.add_subplot(111)
line, = ax.plot(x, np.sin(x))
ani = animation.FuncAnimation(fig, animate, np.arange(1, 200), interval=25, blit=False)

Tk.mainloop()

1
强调关键修改和原因可以使这个答案更有用。 - Niko Pasanen

3

根据user151522的答案,第一次尝试并没有成功,我做了一些修改来适用于Python 3.7:

#---------Imports

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

import tkinter as tk
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
#---------End of imports



from tkinter import Frame,Label,Entry,Button


class Window(Frame):

    def __init__(self, master = None):
        Frame.__init__(self, master)
        self.master = master
        self.init_window()


    def Clear(self):      
        print("clear")
        self.textAmplitude.insert(0, "1.0")
        self.textSpeed.insert(0, "1.0")       


    def Plot(self):
        self.v = float(self.textSpeed.get())
        self.A = float(self.textAmplitude.get())


    def animate(self,i):
        self.line.set_ydata(self.A*np.sin(self.x+self.v*i))  # update the data
        return self.line,


    def init_window(self):



        self.master.title("Use Of FuncAnimation in tkinter based GUI")
        self.pack(fill='both', expand=1)     

        #Create the controls, note use of grid

        self.labelSpeed = Label(self,text="Speed (km/Hr)",width=12)
        self.labelSpeed.grid(row=0,column=1)
        self.labelAmplitude = Label(self,text="Amplitude",width=12)
        self.labelAmplitude.grid(row=0,column=2)

        self.textSpeed = Entry(self,width=12)
        self.textSpeed.grid(row=1,column=1)
        self.textAmplitude = Entry(self,width=12)
        self.textAmplitude.grid(row=1,column=2)

        self.textAmplitude.insert(0, "1.0")
        self.textSpeed.insert(0, "1.0")
        self.v = 1.0
        self.A = 1.0


        self.buttonPlot = Button(self,text="Plot",command=self.Plot,width=12)        
        self.buttonPlot.grid(row=2,column=1)

        self.buttonClear = Button(self,text="Clear",command=self.Clear,width=12)
        self.buttonClear.grid(row=2,column=2)


        self.buttonClear.bind(lambda e:self.Clear)



        tk.Label(self,text="SHM Simulation").grid(column=0, row=3)

        self.fig = plt.Figure()

        self.x = 20*np.arange(0, 2*np.pi, 0.01)        # x-array


        self.ax = self.fig.add_subplot(111)
        self.line, = self.ax.plot(self.x, np.sin(self.x))        


        self.canvas = FigureCanvasTkAgg(self.fig, master=self)
        self.canvas.get_tk_widget().grid(column=0,row=4)


        self.ani = animation.FuncAnimation(self.fig, self.animate, np.arange(1, 200), interval=25, blit=False)




root = tk.Tk()
root.geometry("700x400")
app = Window(root)
tk.mainloop()

1

希望这个答案能够被允许。这是我最初发现这个问题时真正感兴趣的答案,即“将Matplotlib动画嵌入基于tkinter的GUI”。

给出前一个截图的代码已经被扩展,在这个代码中,画布已经放置在类定义内部,连同两个命令按钮的一些代码,这些按钮实际上并没有做“任何事情”,但这个结构为可能的进一步开发提供了便利。

以下截图是使用扩展代码生成的

从基于tkinter的GUI中运行的SHM动画的屏幕截图

用于上述截图的扩展代码如下。


from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

import tkinter as tk
from tkinter import Frame,Label,Entry,Button
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

class Window(Frame):

    def __init__(self, master = None):
        Frame.__init__(self, master)
        self.master = master
        self.init_window()


    def Clear(self):
        x=0

#    def Plot(self):
#        x=0

    def init_window(self):


        def animate(i):
           self.line.set_ydata(np.sin(self.x+i/10.0))  # update the data
           return self.line,

        self.master.title("Use Of FuncAnimation in tkinter based GUI")
        self.pack(fill='both', expand=1)     

#Create the controls, note use of grid

        self.labelSpeed = Label(self,text="Speed (km/Hr)",width=12)
        self.labelSpeed.grid(row=0,column=1)
        self.labelAmplitude = Label(self,text="Amplitude",width=12)
        self.labelAmplitude.grid(row=0,column=2)

        self.textSpeed = Entry(self,width=12)
        self.textSpeed.grid(row=1,column=1)
        self.textAmplitude = Entry(self,width=12)
        self.textAmplitude.grid(row=1,column=2)


#        self.buttonPlot = Button(self,text="Plot",command=self.Plot,width=12)
        self.buttonPlot = Button(self,text="Plot",width=12)
        self.buttonPlot.grid(row=2,column=1)
        self.buttonClear = Button(self,text="Clear",command=self.Clear,width=12)
        self.buttonClear.grid(row=2,column=2)

#        self.buttonClear.bind(lambda e:self.Plot)
        self.buttonClear.bind(lambda e:self.Clear)



        tk.Label(self,text="SHM Simulation").grid(column=0, row=3)

        self.fig = plt.Figure()

        self.x = np.arange(0, 2*np.pi, 0.01)        # x-array


        self.ax = self.fig.add_subplot(111)
        self.line, = self.ax.plot(self.x, np.sin(self.x))        


        self.canvas = FigureCanvasTkAgg(self.fig, master=self)
        self.canvas.get_tk_widget().grid(column=0,row=4)


        self.ani = animation.FuncAnimation(self.fig, animate, np.arange(1, 200), interval=25, blit=False)




root = tk.Tk()
root.geometry("700x400")
app = Window(root)
tk.mainloop()


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接