2014-01-13 18 views
8

我試圖實現一個輸出動畫圖的函數。python matplotlib:無法從函數內調用FuncAnimation

如果我採取simple_anim.py(從matplotlib例子)作爲基料:

""" 
A simple example of an animated plot 
""" 
import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.animation as animation 

fig, ax = plt.subplots() 

x = np.arange(0, 2*np.pi, 0.01)  # x-array 
line, = ax.plot(x, np.sin(x)) 

def animate(i): 
    line.set_ydata(np.sin(x+i/10.0)) # update the data 
    return line, 

#Init only required for blitting to give a clean slate. 
def init(): 
    line.set_ydata(np.ma.array(x, mask=True)) 
    return line, 

ani = animation.FuncAnimation(fig, animate, np.arange(1, 200), init_func=init, 
    interval=25, blit=True) 
plt.show() 

有效它的工作原理。

但是,如果我關閉這個代碼在函數內部(以提供不斷變化的參數,以及避免做用於每個可能的參數值明確的文件):

""" 
A simple example of an animated plot 
""" 
import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.animation as animation 

def a(): 
    fig, ax = plt.subplots() 

    x = np.arange(0, 2*np.pi, 0.01)  # x-array 
    line, = ax.plot(x, np.sin(x)) 

    def animate(i): 
     line.set_ydata(np.sin(x+i/10.0)) # update the data 
     return line, 

    #Init only required for blitting to give a clean slate. 
    def init(): 
     line.set_ydata(np.ma.array(x, mask=True)) 
     return line, 

    ani = animation.FuncAnimation(fig, animate, np.arange(1, 200), init_func=init, 
     interval=25, blit=True) 
    plt.show() 

,然後調用函數,該圖情節保持白色。事實上,它永遠不會進入有生命的功能。

我知道我錯過了一些信息,這就是爲什麼它不起作用。 有人可以給我一些提示嗎?

非常感謝你,

安德烈斯

+1

兩種代碼都適合我。請同時發佈調用'a'的代碼。 – Nabla

回答

15

,出現這種情況的原因是,定時器和回調,其更新的窗口是對象ani的屬性。如果你沒有參考它,那麼收集垃圾ani,你的計時器/回調消失。

的解決辦法是讓你的函數返回ani並保持對它的引用在代碼:

def a(...): 
    # stuff 
    ani = animation.FuncAnimation(...) 
    # more stuff 
    return ani 

outer_ani = a(...) 

這個問題(見github #1656)已經討論過,但沒有得到解決。

+0

但是不會'plt.show()'阻塞,直到窗口關閉?函數'a()'僅在'plt.show()'返回後保留。在那之前'ani'的垃圾回收不可能發生。 – Nabla

+0

'plt.show()'可以是非阻塞的,例如,如果您在shell中以交互方式運行代碼 – tacaswell

+0

使用matplotlib 1.3.0和python 3.2.5'plt.show()'在任何情況下都會阻塞除非我提供'block = False'作爲參數,否則我只能在交互模式下顯示劇情,並且只有在shell閒置等待用戶輸入時才保持動畫。即使在這種情況下,這個問題的兩個代碼塊仍然適用於我。這個問題可能存在版本依賴性,還是我錯過了明顯的東西? – Nabla

1

正如tcaswell的良好答案所暗示的,問題代碼的行爲是未定義的,因爲它依賴於已被刪除並可用於垃圾回收的對象。

實際上,這種未定義的行爲在不同的GUI後端中會有不同的表現。對於某些用戶(例如this "duplicate" question),在IDLE中使用Wx後端或在Windows上使用默認的Pylab快捷鍵時,未定義的代碼似乎有效(我說「似乎」,因爲它實際上不工作,而是運氣得到期望的結果)。在具有默認Qt後端的Canopy GUI中運行時,代碼不起作用。 Qt和Wx具有非常不同的體系結構和垃圾收集。 (在Canopy中,可以在Preferences菜單的Python選項卡中更改GUI後端;如果將其更改爲Wx,那麼未定義的代碼似乎也能正常工作,但這又不能使其正確)。