如何使用 tkinter 嵌入 3d 动画图?

问题描述

我对使用 tkinter 还很陌生,我想制作一个用于练习的小用户界面。我选择绘制洛伦兹系统,同时允许用户配置输入参数。

我已经有一个图表和连接的输入字段,我可以显示静态图。我的下一步是尝试展示一个动画情节。然而,这是我遇到问题的地方。我似乎无法在嵌入的图形中显示动画。在下面的代码中,您可以看到我更改了 plot_animated() 函数以创建新图形和轴,并且效果很好,但是当我将它们更改为使用 self.figureself.ax 时,没有任何显示情节。

以下是我的 UI 实现:

from tkinter import *
from matplotlib import animation
from matplotlib.backends.backend_tkagg import figureCanvasTkAgg
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.pyplot as plt

from lorenz_model import run_lorenz


class LorenzUI:
    input_width = 10

    def __init__(self):
        self.root = Tk()
        self.root.title("Lorenz Attractor")
        self.root.geometry("1290x960")

        self.chart_fr = Frame(self.root)

        self.figure = plt.figure()
        self.figure.tight_layout()
        self.ax = p3.Axes3D(self.figure)
        self.canvas = figureCanvasTkAgg(self.figure,master=self.chart_fr)
        self.canvas.get_tk_widget().grid(row=0,column=0,sticky="nsew")

        self.input_fr = Frame(self.root,relief=RAISED,bd=2)

        self.init_x_lbl = Label(self.input_fr,text="Initial X")
        self.init_x_input = Entry(self.input_fr,width=self.input_width)
        self.init_y_lbl = Label(self.input_fr,text="Initial Y")
        self.init_y_input = Entry(self.input_fr,width=self.input_width)
        self.init_z_lbl = Label(self.input_fr,text="Initial Z")
        self.init_z_input = Entry(self.input_fr,width=self.input_width)

        self.rho_lbl = Label(self.input_fr,text="Rho")
        self.rho_input = Entry(self.input_fr,width=self.input_width)
        self.sigma_lbl = Label(self.input_fr,text="Sigma")
        self.sigma_input = Entry(self.input_fr,width=self.input_width)
        self.beta_lbl = Label(self.input_fr,text="Beta")
        self.beta_input = Entry(self.input_fr,width=self.input_width)
        self.time_lbl = Label(self.input_fr,text="Sim Time")
        self.time_input = Entry(self.input_fr,width=self.input_width)

        self.is_animated = Intvar(value=1)
        self.animate_chk = Checkbutton(self.input_fr,text="Animate?",variable=self.is_animated)
        self.run_btn = Button(self.input_fr,text="Run",command=self.generate_model)
        self.stop_btn = Button(self.input_fr,text="Stop")
        self.reset_btn = Button(self.input_fr,text="Reset Defaults",command=self.set_defaults)

        self.root.rowconfigure(0,minsize=50,weight=1)
        self.root.columnconfigure(0,minsize=800,weight=1)

        self.init_x_lbl.grid(row=0,padx=5,pady=5)
        self.init_x_input.grid(row=0,column=1,pady=5)
        self.init_y_lbl.grid(row=1,pady=5)
        self.init_y_input.grid(row=1,pady=5)
        self.init_z_lbl.grid(row=2,pady=5)
        self.init_z_input.grid(row=2,pady=5)

        self.rho_lbl.grid(row=4,pady=5)
        self.rho_input.grid(row=4,pady=5)
        self.sigma_lbl.grid(row=5,pady=5)
        self.sigma_input.grid(row=5,pady=5)
        self.beta_lbl.grid(row=6,pady=5)
        self.beta_input.grid(row=6,pady=5)
        self.time_lbl.grid(row=7,pady=5)
        self.time_input.grid(row=7,pady=5)

        self.animate_chk.grid(row=8,pady=5)
        self.run_btn.grid(row=9,pady=5)
        self.stop_btn.grid(row=9,pady=5)
        self.reset_btn.grid(row=10,pady=5)

        self.chart_fr.grid(row=0,sticky="nse")
        self.input_fr.grid(row=0,sticky="nsew")

        self.set_defaults()

    @staticmethod
    def __set_default(field,value):
        field.delete(0,END)
        field.insert(0,value)

    def set_defaults(self):
        self.__set_default(self.init_x_input,1.0)
        self.__set_default(self.init_y_input,1.0)
        self.__set_default(self.init_z_input,1.0)
        self.__set_default(self.rho_input,28.0)
        self.__set_default(self.sigma_input,10.0)
        self.__set_default(self.beta_input,2.666667)
        self.__set_default(self.time_input,40.0)
        self.animate_chk.select()

    def generate_model(self):
        x = float(self.init_x_input.get())
        y = float(self.init_y_input.get())
        z = float(self.init_z_input.get())
        rho = float(self.rho_input.get())
        sigma = float(self.sigma_input.get())
        beta = float(self.beta_input.get())
        t = float(self.time_input.get())
        dt = 0.01  # Todo Needed as Input?

        self.model = run_lorenz([x,y,z],t,dt,rho,sigma,beta)

        if self.is_animated.get():
            self.__plot_animated()
        else:
            self.__plot_static()

    def __plot_animated(self):
        figure = plt.figure()
        ax = p3.Axes3D(figure)
        ax.clear()

        ax.set_xlim3d([min(self.model[0]),max(self.model[0])])
        ax.set_ylim3d([min(self.model[1]),max(self.model[1])])
        ax.set_zlim3d([min(self.model[2]),max(self.model[2])])

        n_frames = len(self.model[0])
        line,= ax.plot(self.model[0,0:1],self.model[1,self.model[2,0:1])

        self.ani = animation.FuncAnimation(figure,self.__animate,n_frames,fargs=(self.model,line),interval=1,blit=False)
        plt.show()

    def __animate(self,num,data,line):
        line.set_data(data[:2,:num])
        line.set_3d_properties(data[2,:num])

    def __plot_static(self):
        self.ax.clear()
        self.ax.plot(self.model[0,:],:])
        self.canvas.draw()

    def run(self):
        self.root.mainloop()

我有一个单独的文件来计算由以下两个函数组成的模型:

import numpy as np
from scipy.integrate import odeint


def f(state,beta):
    x,z = state  # Unpack the state vector
    return sigma * (y - x),x * (rho - z) - y,x * y - beta * z  # Derivatives


def run_lorenz(initial_state,beta):
    times = np.arange(0.0,dt)
    result = odeint(f,initial_state,times,args=(rho,beta))
    return np.array(np.array(result).T)

最后是一个运行应用程序的主文件

from lorenz_ui import LorenzUI


if __name__ == '__main__':
    app = LorenzUI()
    app.run()

所以我真的有两个问题。

  1. 如何让动画显示在嵌入图形中而不是创建一个新图形?
  2. 如果您运行此程序,您将看到该图仅显示在可用空间的右上角,它如何使其增长并填满所有可用空间?

在此先感谢您的帮助。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...