Python tkinter中的两个动画同时出现

Python tkinter中的两个动画同时出现,python,animation,tkinter,Python,Animation,Tkinter,我想让两个动画同时工作 这是我的密码: import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg import matplotlib.animation as animation import tkinter as tk f = plt.figure(figsize=(6, 2), dpi=100) f1 = plt.figure(figsize=(4, 2),

我想让两个动画同时工作

这是我的密码:

import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.animation as animation
import tkinter as tk

f = plt.figure(figsize=(6, 2), dpi=100)
f1 = plt.figure(figsize=(4, 2), dpi=100)

def animate(i):
    a = f.add_subplot(111)
    x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    y = [3, 5, 2, 7, 3, 5, 4, 6, 2, 2]
    a.plot(x, y)

def animate1(j):
    a1 = f1.add_subplot(111)
    x1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    y1 = [6, 1, 4, 9, 4, 2, 5, 1, 2, 4]
    a1.plot(x1, y1)

class Figure(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.config(background='blue')

        canvas = FigureCanvasTkAgg(f, self)
        canvas.draw()
        canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)

class Figure1(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.config(background='blue')

        canvas = FigureCanvasTkAgg(f1, self)
        canvas.draw()
        canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)


class Calculator(tk.Tk):
        def __init__(self, *args, **kwargs):
            tk.Tk.__init__(self, *args, *kwargs)
            tk.Tk.wm_title(self, 'Beam calculator')
            container = tk.Frame(self)
            container.pack(side='top', fill='both', expand=True)
            bfig = Figure(container, controller=self)
            bfig.grid(row=0, column=0, sticky="nsew")
            bfig1 = Figure(container, controller=self)
            bfig1.grid(row=1, column=0, sticky="nsew")


if __name__ == '__main__':

    app = Calculator()
    app.geometry('1280x720')
    ani = animation.FuncAnimation(f, animate, interval=1000)
    ani1 = animation.FuncAnimation(f1, animate1, interval=1000)
    app.mainloop()
但只有第二个数字出现

我发现了以下主题:


但是我不知道如何使它正常工作。

有三件小事妨碍了代码的工作:

  • 使用网格时,您需要:

  • bfig1=Figure(容器,控制器=self)
    更改为
    bfig1=Figure1(容器,控制器=self)
    。否则,画布永远不会附着到图
    f1

  • *kwargs
    应该是
    **kwargs
    tk.tk.\uuuu_uuinit_uuu(self,*args,*kwargs)
    行中。 请参见
    *args
    **kwargs
    的含义

  • 这些是运行代码所需的最小更改


    您还可以使用许多其他更改来改进代码

    一个大问题是
    a=f.add_子图(111)
    不应放在
    animate
    函数中。这将在图形中创建一个轴对象
    a
    ,即
    f
    。通常每个图有一个轴和一个图形。(请参见。)由于为动画的每个帧调用一次
    animate
    ,因此您不希望为每个帧创建新的轴。下面的代码建议如何在全局范围内定义一次
    a


    另一个主要的编程原则是首字母缩写

    虽然一开始复制代码可能很容易,但从长远来看,它会使维护变得更容易 更难修改代码。例如,假设您决定要添加 将一些代码添加到
    类中。因为您有两个几乎相同的
    类,您可能必须向
    图1
    添加相同的代码。及 如果您以后发现该代码中存在错误,则必须修复这两个代码中的错误 地方也一样。因为每一次编辑都需要完成,所以您的生产力会减半 两次。如果您忘记在某个地方执行此操作,则会引入另一个bug

    您可以通过泛化
    动画
    图形
    使您的代码更加枯燥,以便 可以删除
    动画1
    图1
    。你所需要做的就是添加一个额外的参数 到函数(例如,
    f
    )来概括代码并允许代码 重新使用(请参阅下面的代码以了解我的意思。)


    使用带编号的变量名几乎总是一个坏主意。 通常应使用
    列表
    dict
    代替编号变量。 由于编号变量名通常以相同的方式使用, (即对
    x1
    执行此操作,对
    x2
    执行相同操作,对
    x3
    执行相同操作,等等。) 使用带编号的变量会导致代码重复,这与DRY原则背道而驰。 如果使用列表来收集一个对象中的所有数字变量,则可以使用循环一次处理所有数字变量:

    for x in xs:
        do_something(x)
    

    性能提示:在动画中可能出现的数千次调用
    plt.plot
    plt会使程序明显变慢。每次调用都会生成新的
    Line2D
    对象,这些对象需要在动画的每一帧中重新渲染。为了获得更好的性能,请反复使用相同的
    Line2D
    对象,只需更改
    Line2D
    对象内的ydata即可使matplotlib呈现不同的行:

    line.set_ydata(y)
    

    line.set_ydata(y)
    
    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
    import matplotlib.animation as animation
    import matplotlib.figure as mplfig
    import tkinter as tk
    
    def animate(i, line):
        y = np.random.randint(10, size=len(x))
        line.set_ydata(y)
        return [line]
    
    class Figure(tk.Frame):
    
        def __init__(self, parent, controller, f):
            tk.Frame.__init__(self, parent)
            self.controller = controller
            canvas = FigureCanvasTkAgg(f, self)
            canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)
            canvas.draw()
    
    class Calculator(tk.Tk):
    
        def __init__(self, *args, **kwargs):
            tk.Tk.__init__(self, *args, **kwargs)
            self.wm_title('Beam calculator')
            container = tk.Frame(self)
            container.pack(side='top', fill='both', expand=True)
            for i, f in enumerate(figs):
                bfig = Figure(container, controller=self, f=f)
                bfig.grid(row=i, column=0, sticky="nsew")
                # give the rows equal weight so they are allotted equal size
                container.grid_rowconfigure(i, weight=1)
            # you need to give at least one row and one column a positive weight 
            # https://stackoverflow.com/a/36507919/190597 (Bryan Oakley)
            container.grid_columnconfigure(0, weight=1)
    
    if __name__ == '__main__':
        figs = [mplfig.Figure(figsize=(6, 2), dpi=100),
              mplfig.Figure(figsize=(4, 2), dpi=100)]
        axs = [f.add_subplot(111) for f in figs]
        x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        ys = [[3, 5, 2, 7, 3, 5, 4, 6, 2, 2],
              [6, 1, 4, 9, 4, 2, 5, 1, 2, 4]]
        lines = [ax.plot(x, ys[i])[0] for i, ax in enumerate(axs)]
        for ax in axs:
            ax.set_ylim([0, 10])
    
        app = Calculator()
        app.geometry('1280x720')
        anis = [animation.FuncAnimation(f, animate, interval=1000, fargs=[line])
                for f, line in zip(figs,lines)]
        app.mainloop()