简体   繁体   English

Tkinter 中的动画 Matplotlib 图

[英]Animated Matplotlib Plot in Tkinter

I'm really struggling with an live Plot using FuncAnimation and Tkinter.我真的很挣扎使用 FuncAnimation 和 Tkinter 的实时绘图。 I'm not sure what info is needed to reproduce the problem.我不确定重现问题需要什么信息。 Please forgive me if anything is missing.如有遗漏请见谅。 In a stripped down version it works fine:在精简版中,它工作正常:

from numpy.random import normal
from numpy import exp
def fn(x):
    A=3e-8
    B=6e3
    Inoise = 1e-10
    if x == 0:
        I = Inoise
    elif A*x**2*exp(-B/x) < Inoise:
        I = Inoise
    else:
        I = A*x**2*exp(-B/x)
    return normal(1,0.4,1)[0]*I

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg,NavigationToolbar2Tk
from matplotlib.animation import FuncAnimation
from matplotlib.pyplot import Figure
from tkinter import Frame

from queue import Queue
class LivePlotWindow(Frame):
    def __init__(self, master,xlabel='',ylabel='',logx=False,logy=False):
        Frame.__init__(self, master)
        self.pack(fill='both', expand=1)     
        self.fig = Figure()
        self.ax = self.fig.add_subplot(111)
        self.canvas = FigureCanvasTkAgg(self.fig, master=self)   
        self.toolbar = NavigationToolbar2Tk(self.canvas, self)
        self.toolbar.update()
        self.canvas.get_tk_widget().pack()
        self.xlabel = xlabel
        self.ylabel = ylabel
        self.logx = logx
        self.logy = logy
        self.q = Queue()
        self._axini()

    def _axini(self):
        self.ax.cla()
        self.ax.set_xlabel(self.xlabel)
        self.ax.set_ylabel(self.ylabel)
        if self.logx==True:
            self.ax.set_xscale('log', nonposx='clip')
        if self.logy==True:
            self.ax.set_yscale('log', nonposy='clip')
        self.fig.tight_layout()

    def _update(self,i):
        print(i)
        [x,y] = self.q.get(block=True) 
        print([x,y])
        self.ax.plot(x,y,'b.')  # update the data

    def run(self,ncalls):
        self._axini()
        print(ncalls)   
        self.ani = FuncAnimation(self.fig, self._update, range(ncalls-1), interval=100, repeat=False)
        print(ncalls)

    def addP(self,x,y):
        self.q.put([x,y])

    def stop(self):
        self.ani.event_source.stop()

from tkinter import Tk
root = Tk()
root.title('Kennlinien-Messprogramm')
root.geometry('700x500')
plot = LivePlotWindow(root,'Voltage in V','Current in A',logy=True)

n=100
plot.run(n)
for i in range(n):
    plot.addP(i*10,fn(i*10))
root.mainloop()

But when I'm integrating it in a GUI with menu, its just not calling the animation function.但是当我将它集成到带有菜单的 GUI 中时,它只是不调用动画函数。 It seems when I pass my Plot object as a command call its not working anymore?似乎当我将 Plot 对象作为命令调用传递时,它不再工作了? If I call the start function directly it wortks.如果我直接调用 start 函数,它会起作用。 I have no idea why:我不知道为什么:

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg,NavigationToolbar2Tk
from matplotlib.animation import FuncAnimation
from matplotlib.pyplot import Figure
from tkinter import Tk,Frame,Menu

from queue import Queue
class LivePlotWindow(Frame):
    def __init__(self, master,xlabel='',ylabel='',logx=False,logy=False):
        Frame.__init__(self, master)
        self.pack(fill='both', expand=1)     
        self.fig = Figure()
        self.ax = self.fig.add_subplot(111)
        self.canvas = FigureCanvasTkAgg(self.fig, master=self)   
        self.toolbar = NavigationToolbar2Tk(self.canvas, self)
        self.toolbar.update()
        self.canvas.get_tk_widget().pack()
        self.xlabel = xlabel
        self.ylabel = ylabel
        self.logx = logx
        self.logy = logy
        self.q = Queue()
        self._axini()

    def _axini(self):
        self.ax.cla()
        self.ax.set_xlabel(self.xlabel)
        self.ax.set_ylabel(self.ylabel)
        if self.logx==True:
            self.ax.set_xscale('log', nonposx='clip')
        if self.logy==True:
            self.ax.set_yscale('log', nonposy='clip')
        self.fig.tight_layout()

    def _update(self,i):
        print(i)
        [x,y] = self.q.get(block=True) 
        print([x,y])
        self.ax.plot(x,y,'b.')  # update the data

    def run(self,ncalls):
        self._axini()
        print(ncalls)   
        self.ani = FuncAnimation(self.fig, self._update, range(ncalls-1), interval=100, repeat=False)
        print(ncalls)

    def addP(self,x,y):
        self.q.put([x,y])

    def stop(self):
        self.ani.event_source.stop()

from tkinter import Tk
root = Tk()
root.title('Kennlinien-Messprogramm')
root.geometry('700x500')
plot = LivePlotWindow(root,'Voltage in V','Current in A',logy=True)

def start(menu,plot):
    menu.entryconfig('\u25B6', state='disabled')
    menu.entryconfig('\u25A0', state='normal')
    n=100
    plot.run(n)
    for i in range(n):
        plot.addP(i*10,fn(i*10))

def stop(menu,plot):
    plot.stop
    menu.entryconfig('\u25B6', state='normal')
    menu.entryconfig('\u25A0', state='disabled')

menu = Menu(root)
root.config(menu=menu)
menu.add_command(label='\u25B6', command=lambda: start(menu,plot))
#menu.entryconfig(1, fg='green')
menu.add_command(label='\u25A0', command=lambda: stop(menu,plot))
menu.entryconfig('\u25A0', state='disabled')

#start(menu,plot)

root.mainloop()

Any help would be highly appreciated!任何帮助将不胜感激! ;) ;)

I've found a solution, although I don't know how smart it is... Now I just continously plot xdata and ydata.我找到了一个解决方案,虽然我不知道它有多聪明......现在我只是不断地绘制 xdata 和 ydata。 Since I pass the reference, its updating any changes outside the plot class.由于我传递了引用,它会更新绘图类之外的任何更改。 However, I redraw the hole plot every time...但是,我每次都重新绘制孔图......

from tkinter import Frame
from matplotlib.pyplot import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.animation import FuncAnimation
class LivePlotWindow(Frame):
    def __init__(self, master, xdata, ydata, xlabel='',ylabel='',logx=False,logy=False):
        Frame.__init__(self, master)
        self.pack(fill='both', expand=1)     
        self.fig = Figure()
        self.ax = self.fig.add_subplot(111)
        self.ax.set_xlabel(xlabel)
        self.canvas = FigureCanvasTkAgg(self.fig, master=self)   
        self.canvas.get_tk_widget().pack()
        self.xdata = xdata
        self.ydata = ydata
        self.xlabel = xlabel
        self.ylabel = ylabel
        self.logx = logx
        self.logy = logy
        self.ani = FuncAnimation(self.fig, self._update, interval=500)

    def _update(self,i):
        self.ax.cla()
        self.ax.set_xlabel(self.xlabel)
        self.ax.set_ylabel(self.ylabel)
        if self.logx:
            self.ax.set_xscale('log', nonposx='clip')
        if self.logy:
            self.ax.set_yscale('log', nonposy='clip')
        #if self.millikan:
        #    self.ax.plot(1/self.xdata,self.ydata)
        #else:
        self.ax.plot(self.xdata,self.ydata,'b.')  # update the data
        self.fig.tight_layout()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM