【问题标题】:how to use blit=true for animation subplot in python tkinter如何在 python tkinter 中将 blit=true 用于动画子图
【发布时间】:2020-04-15 18:48:03
【问题描述】:

以下代码是我项目的简化版本,它可以运行和绘制动画,但我必须在动画中添加blit=true 以加快速度(我原来的 UI 要复杂得多,速度慢得多)。我知道动画函数必须返回一系列 Artist 对象。我的subplot_2 中的艺术家对象是什么?我试过subplot_2,a,f,它们都不起作用。非常感谢

from multiprocessing import Process
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
##, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import style
import tkinter as tk
from tkinter import ttk
from tkinter import *
import matplotlib.pyplot as plt
import numpy as np
f = Figure(figsize=(6,6), dpi=100)
subplot_1 = f.add_subplot(211)
subplot_2 = f.add_subplot(212)

LARGE_FONT= ("Verdana", 12)
style.use("ggplot")

def animate(i):
    time = np.random.rand(2, 25)  
    data = np.random.rand(2, 25)   
    a = subplot_2.scatter(time,data,c='blue',s=2)
    #return a

class home(tk.Tk):

def __init__(self, *args, **kwargs):        
    tk.Tk.__init__(self, *args, **kwargs)
    tk.Tk.wm_title(self, "Graph ")       
    self.geometry("1000x1000")

    container = tk.Frame(self)
    container.pack(side="top", fill="both", expand = True)
    container.grid_rowconfigure(0, weight=1)
    container.grid_columnconfigure(0, weight=1)

    self.frames = {}
    F=Graph
    frame=Graph(container, self)
    self.frames[F] = frame
    frame.grid(row=0, column=0, sticky="nsew")
    self.show_frame(Graph)

def show_frame(self, cont):
    frame = self.frames[cont]
    frame.tkraise()
def get_frame(self, frame_class):
    return self.frames[frame_class]
##     
class Graph(tk.Frame):
    def __init__(self, parent, controller):
        global canvas
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text=" ", font=LARGE_FONT)
        label.pack(pady=120,padx=10)
        collectbtn=Button(self,text='collect',command=self.clickstart)
        collectbtn.place(x=200,y=100)
        canvas = FigureCanvasTkAgg(f, self)
##        canvas.draw()
        canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
        canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
    def clickstart(self):
        animate(0)
        #aniplot_photon = animation.FuncAnimation(f, animate, blit=True,interval=100)
        aniplot_photon = animation.FuncAnimation(f, animate, interval=100)
        canvas.draw()
app = home()
app.mainloop()

更新: 感谢威廉的回答,它有效。但是,我还有其他问题,如果这个子图包含许多曲线"subplot_2.scatter(x1..),subplot_2.scatter(x2..),subplot_2.scatter(x3..),subplot_2.scatter(x1..)...",或者一些子图是从不同的线程更新的(制作对象并将它们全局化?),那么很难将所有曲线放入返回列表中。但是,我为上面列出的问题找到了一个简单的解决方案,我可以只使用return [subplot_2],它会更新 subplot_2 内的所有图,但是坐标(x 刻度)会丢失(运行,你会看到)。当我使用return [suplot_2] 时,有没有一种简单的方法可以保持坐标?

    def animate(i):
    time = np.random.rand(2, 25)  
    data = np.random.rand(2, 25)   
    a = subplot_2.scatter(time,data,c='blue',s=2)
    return [subplot_2]

【问题讨论】:

    标签: python-3.x matplotlib animation tkinter


    【解决方案1】:

    matplotlib.pyplot.scatter 返回一个艺术家(准确地说是PathCollection),因此您需要从animate 返回的艺术家存储在a 中。但是,FuncAnimation 需要一个序列艺术家,所以

        return a
    

    不够(因为这是一个艺术家,而不是一个序列)。您可以使用其中一种

        return [a]
    

        return a,
    

    满足“艺术家顺序”的要求。

    【讨论】:

    • 谢谢,在这个 blit=true 中,历史图是不存储的,所以我要绘制不同的,尝试将每次数据存储到一个长列表中,并且每次重新绘制整个列表?
    • 在我的原始项目中,返回[subplot_2]然后返回[a]更容易,所以我不需要指定subplot_2上的每条曲线,但是,这样我就丢失了协调信息在图中,有什么想法可以将这些坐标保留在 subplot_2 上?
    • @adamwu 在示例中,subplot_2 的范围是这样的,您仍然可以在循环之外访问它 - 因此您可以使用 matplotlib.axes.Axes.get_children() 访问由 PathCollections 创建的个人 plt.scatter .
    • 你的意思是我用return [subplot_2],然后用axes.get再次绘制坐标?不是很明白,几行代码会有帮助^_^
    • @adamwu 您无需返回subplot_2 即可访问儿童艺术家,您只需执行artists = subplot_2.get_children()artists 将成为包含所有@的艺术家列表987654338@s 来自subplot_2.scatter(除其他外)。在调用FuncAnimation 后,无论何时需要访问它们,您都可以使用这种方法。
    猜你喜欢
    • 1970-01-01
    • 2021-05-12
    • 2021-06-28
    • 1970-01-01
    • 2015-05-21
    • 2012-10-24
    • 2020-05-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多