使用Tkinter和pylab / matplotlib嵌入的播放,暂停,停止可用性的彩色情节动画:无法更新图形/画布? [英] color plot animation with play, pause, stop cabability using Tkinter with pylab/matplotlib embedding: can't update figure/canvas?

查看:177
本文介绍了使用Tkinter和pylab / matplotlib嵌入的播放,暂停,停止可用性的彩色情节动画:无法更新图形/画布?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看了,但没有找到足够具体的问题,如果重复这一点,那就很抱歉。
目标:使用pylab的pcolor绘制的不同矩阵数据不断更新数字的GUI,以便运行动画。但是用户应该可以通过Tkinter小部件按钮来播放,暂停和停止动画。

I've looked but didn't find previous questions specific enough, so sorry if this is repeated. Goal: GUI to continuously update figure with different matrix data plotted by pylab's pcolor such that there is a running animation. But user should be able to play, pause, stop animation by Tkinter widget buttons.

在使用set_array(),draw()和canvas获得matplotlib的答案之前.manager.after()...,我有工作代码,可以让我开始动画,但我无法弄清楚如何停止或暂停它,当只使用matplotlib功能,所以我决定使用Tkinter straigt而不是matplotlib的Tcl / Tk包装器。这里是工作代码只是为了踢,但万一有人有任何想法。但继续寻找真正的问题。

Before I get an answer for matplotlib using set_array(), draw(), and canvas.manager.after() ..., I have working code that enables me to start animation, but i can't figure out how to stop or pause it, when just using matplotlib capabilities, so I decided to use Tkinter straigt up instead of matplotlib's Tcl/Tk wrapper. Here is working code just for kicks though in case someone has any ideas. But continue for real question.

# mouse click the "Play" button widget to play animation
# PROBLEMS:
# 1. can't pause or stop animation. once loop starts it cant be broken
# 2. set_array attribute for pcolor PolyCollection object only updates the matrix
# C of pcolor, however for my actual application, I will be using pcolor(x,y,C)
# and will have new x,y, and C per plot. Unlike line object, where set_xdata and
# set_ydata are used, I can't find an analogy to pcolor. If I were updating an
# image I could use set_data(x,y,C), but i am not importing an image. I assume
# pcolor is still my best bet unless (as in Matlab) there is an equivalent
# image(x,y,C) function?

import time as t
from pylab import *
from matplotlib.widgets import Button
ion()
def pressPlay(event):
    #fig=figure()
    ax = subplot(111)
    subplots_adjust(bottom=0.2)
    c=rand(5,5)
    cplot=pcolor(c)
    draw()
    for i in range(5):
        c=rand(5,5)
        cplot.set_array(c.ravel())
        cplot.autoscale()
        title('Ionosphere '+str(i+1))
        t.sleep(3)
        draw()
axPlay = axes([0.7, 0.05, 0.1, 0.075])
bPlay = Button(axPlay, 'Play')
bPlay.on_clicked(pressPlay)

Btw:在导入pylab时,TkAgg后端会自动设置为在matplotlib中使用......我想。或者以某种方式我自动使用TkAgg。我正在运行Linux,Python 2.6.4,Ipython 0.10。

Btw: in importing pylab the TkAgg backend is automatically set for use in matplotlib... i think. Or somehow I automatically use TkAgg. I am running Linux, Python 2.6.4, Ipython 0.10.

我操纵了从Daniweb IT讨论社区找到的代码,以便使用Tkinter和update_idletasks()函数,我可以播放,播放,停止更改标签小部件的颜色。只要安装了Tkinter,就可以在python上单独运行。没有使用matplotlib或pylab。这是工作代码和我质疑的最终代码的主干。

I manipulated code found from Daniweb IT Discussion Community so that using Tkinter and the update_idletasks() function I can play, plause, stop the changing colors of a label widget. This can be run on python alone as long as Tkinter is installed. No matplotlib or pylab used. This is working code and the backbone of the final code I question.

# This is meant to draw Start and Stop buttons and a label
# The Start button should start a loop in which the label
# is configured to change color by looping through a color list.
# At each pass through the loop the variable self.stop is checked:
# if True the loop terminates.
# The Stop button terminates the loop by setting the
# variable self.stop to True.
# The Start button restarts the animation from the beginning
# if Stop was hit last, or restarts the animation from where it left off
# if pause was hit last.
# The loop also terminates on the last color of the list, as if stop were hit


from Tkinter import *
colors = ['red','green','blue','orange','brown','black','white','purple','violet']
numcol=len(colors)
class SGWidget(Frame):
    def __init__(self, parent=None):
        Frame.__init__(self, parent)
        self.top_frame = Frame(bg='green')
        self.top_frame.grid()
        # enter event loop until all idle callbacks have been called.
        self.top_frame.update_idletasks()
        self.makeToolbar()
        # construct a label widget with the parent frame top_frame
        self.label = Label(self.top_frame,text = 'Text',bg='orange')
        self.label.grid()
 # initialize (time index t)
        self.t=0

    def makeToolbar(self):
        self.toolbar_text = ['Play','Pause','Stop']
        self.toolbar_length = len(self.toolbar_text)
        self.toolbar_buttons = [None] * self.toolbar_length

        for toolbar_index in range(self.toolbar_length):
            text = self.toolbar_text[toolbar_index]
            bg = 'yellow'
            button_id = Button(self.top_frame,text=text,background=bg)
            button_id.grid(row=0, column=toolbar_index)
            self.toolbar_buttons[toolbar_index] = button_id

            def toolbar_button_handler(event, self=self, button=toolbar_index):
                return self.service_toolbar(button)

            # bind mouse click on start or stop to the toolbar_button_handler
            button_id.bind("<Button-1>", toolbar_button_handler)

    # call blink() if start and set stop when stop            
    def service_toolbar(self, toolbar_index):
        if toolbar_index == 0:
            self.stop = False
            print self.stop
            self.blink()
        elif toolbar_index == 1:
            self.stop = True
            print self.stop
        elif toolbar_index == 2:
            self.stop = True
            print self.stop
            self.t=0

    # while in start, check if stop is clicked, if not, call blink recursivly
    def blink(self):
        if not self.stop:
            print 'looping',self.stop
            self.label.configure(bg=colors[self.t])
            self.t += 1
            if self.t == numcol: # push stop button
                self.service_toolbar(2)
            self.label.update_idletasks()
            self.after(500, self.blink)

if __name__ == '__main__':
    SGWidget().mainloop()

然后,在matplotlib示例embedding_in_tk.html的帮助下, http:/ /matplotlib.sourceforge.net/examples/user_interfaces/embedding_in_tk.html ,我操纵了前面的代码来动画连接到pcolor图形的画布。但是,使用canvas.get_tk_widget()更新画布并不能实现我所假设的技巧,因为之前的命令会重新绘制pcolor()。所以我猜我每次重新绘制时都必须重新连接画布和图形?但我不知道怎么做。我希望我甚至可以使用update_idletasks()????

Then, with help from matplotlib example embedding_in_tk.html, http://matplotlib.sourceforge.net/examples/user_interfaces/embedding_in_tk.html, I manipulated the previous code to animate a canvas connected to the pcolor figure. However, updating the canvas with canvas.get_tk_widget() doesn't do the trick I assume because of the command before it that re-plots pcolor(). So I'm guessing I have to reconnect the canvas with the figure every time I re-plot? But I don't know how. I hope I'm even on the right track using update_idletasks()???

所以,使用下面的代码,我看到的所有代码都是相同的情节。循环播放,而不是更新的数字?这是我的主要问题和疑问。

So, with the following code, all I see is the same plot when the code is looping through Play, instead of an updated figure? This is my main problem and question.

from pylab import *
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from Tkinter import *

colors=[None]*10
for i in range(len(colors)):
    colors[i]=rand(5,5)
    #colors = ['red','green','blue','orange','brown','black','white','purple','violet']
numcol=len(colors)

class App(Frame):
    def __init__(self,parent=None):
        Frame.__init__(self,parent)
        self.top=Frame()
        self.top.grid()
        self.top.update_idletasks()

        self.makeWidgets()
        self.makeToolbar()

    def makeWidgets(self):
        # figsize (w,h tuple in inches) dpi (dots per inch)
        #f = Figure(figsize=(5,4), dpi=100)
        self.f = Figure()
        self.a = self.f.add_subplot(111)
        self.a.pcolor(rand(5,5))
        # a tk.DrawingArea
        self.canvas = FigureCanvasTkAgg(self.f, master=self.top)
        self.canvas.get_tk_widget().grid(row=3,column=0,columnspan=3)
        self.bClose = Button(self.top, text='Close',command=self.top.destroy)
        self.bClose.grid()
        #self.label = Label(self.top, text = 'Text',bg='orange')
        #self.label.grid()
        # initialize (time index t)
        self.t=0

    def makeToolbar(self):
        self.toolbar_text = ['Play','Pause','Stop']
        self.toolbar_length = len(self.toolbar_text)
        self.toolbar_buttons = [None] * self.toolbar_length

        for toolbar_index in range(self.toolbar_length):
            text = self.toolbar_text[toolbar_index]
            bg = 'yellow'
            button_id = Button(self.top,text=text,background=bg)
            button_id.grid(row=0, column=toolbar_index)
            self.toolbar_buttons[toolbar_index] = button_id

            def toolbar_button_handler(event, self=self, button=toolbar_index):
                return self.service_toolbar(button)

            button_id.bind("<Button-1>", toolbar_button_handler)

    # call blink() if start and set stop when stop            
    def service_toolbar(self, toolbar_index):
        if toolbar_index == 0:
            self.stop = False
            print self.stop
            self.blink()
        elif toolbar_index == 1:
            self.stop = True
            print self.stop
        elif toolbar_index == 2:
            self.stop = True
            print self.stop
            self.t=0

    # while in start, check if stop is clicked, if not, call blink recursivly
    def blink(self):
        if not self.stop:
            print 'looping',self.stop
            self.a.pcolor(colors[self.t])
            #draw()
            #self.label.configure(bg=colors[self.t])
            self.t += 1
            if self.t == numcol: # push stop button
                self.service_toolbar(2)
            self.canvas.get_tk_widget().update_idletasks()
            #self.label.update_idletasks()
            self.after(500, self.blink)

#root = Tk()
app=App()
app.mainloop()

感谢您的帮助!

推荐答案

在您的闪烁功能中添加 self.canvas.show()在调用空闲任务之前:

In your blink function, add a self.canvas.show() before calling idle tasks:

self.canvas.show() # insert this line
self.canvas.get_tk_widget().update_idletasks()

这篇关于使用Tkinter和pylab / matplotlib嵌入的播放,暂停,停止可用性的彩色情节动画:无法更新图形/画布?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆