Python+Matplotlib制作動畫


注: 在“實驗設計與數據處理”的課后作業中,有一個數據可視化的作業,利用課程上學習的某種方法找一個二維函數的最大值,並將這個尋找的過程可視化。在作業里面利用了Matplotlib的Animation類實現可視化的動態展示。

1、引言

利用Animation類制動畫主要是參考了官方的教程:Matplotlib-Animation。為了更加清析說明Animation類是如何實現動畫的,本文只簡單地介紹一個點沿着sin函數運動的例子,分析一下Animation實現動畫的原理。其它復雜的動畫同樣也是據此原理,可以實現下面的動畫效果。第3幅圖是作業的一個效果圖。

sin函數點運動 二階擺鍾(官方例子)
fig-sin_test1 fig-double_pendulum1
fig-optimization_dichotomy_max

2、動畫實現

這里主講述上面的sin函數點運動的動畫的實現。代碼的運行環境為Python3.6 + Jupyter5.4。

2.1 准備背景

在繪制動畫前,我們需將其sin函數的背景繪制出來。這一步很簡單,與我們平時的繪圖一樣。

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.animation as animation

# 指定渲染環境
%matplotlib notebook
# %matplotlib inline

x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)

fig = plt.figure(tight_layout=True)
plt.plot(x,y)
plt.grid(ls="--")
plt.show()
fig-sin_bg fig2-2-sin_test
圖2-1 sin背景圖 圖2-2 sin函數點運動效果1

2.2 往背景中添加動畫點

這一步代碼稍微多了一點點,且先看代碼,再來解釋。

def update_points(num):
    '''
    更新數據點
    '''
    point_ani.set_data(x[num], y[num])
    return point_ani,

x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)

fig = plt.figure(tight_layout=True)
plt.plot(x,y)
point_ani, = plt.plot(x[0], y[0], "ro")
plt.grid(ls="--")
# 開始制作動畫
ani = animation.FuncAnimation(fig, update_points, np.arange(0, 100), interval=100, blit=True)

# ani.save('sin_test2.gif', writer='imagemagick', fps=10)
plt.show()

上面的代碼中,首先定義了一個update_points函數,用於更新繪制的圖中的數據點。此函數的輸入參數num代表當前動畫的第幾幀,函數的返回,即為我們需要更新的對象,需要特別注意的是:reuturn point_ani,這個逗號一定加上,否則動畫不能正常顯示。當然這里面操作的點對象point_ani我們一般會提前聲明得到:point_ani, = plt.plot(x[0], y[0], "ro")。接下來就是將此函數傳入我們的FuncAnimation函數中,函數的參數說明可以參見官網,這里簡要說明用到的幾個參數。

  • 第1個參數fig:即為我們的繪圖對象.
  • 第2個參數update_points:更新動畫的函數.
  • 第3個參數np.arrange(0, 100):動畫幀數,這需要是一個可迭代的對象。
  • interval參數:動畫的時間間隔。
  • blit參數:是否開啟某種動畫的渲染。

運行上面代碼可以得到如圖2-2所示的動畫效果。

2.3 往動畫中添加其它效果

上面實現的動畫效果還比較單一,我們可以往其中添加一些文本顯示,或者在不同的條件下改變點樣式。這其實也非常簡單,只需在update_points函數中添加一些額外的,你想要的效果代碼即可。

def update_points(num):
    if num%5==0:
        point_ani.set_marker("*")
        point_ani.set_markersize(12)
    else:
        point_ani.set_marker("o")
        point_ani.set_markersize(8)

    point_ani.set_data(x[num], y[num])    
    text_pt.set_text("x=%.3f, y=%.3f"%(x[num], y[num]))
    return point_ani,text_pt,

x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)

fig = plt.figure(tight_layout=True)
plt.plot(x,y)
point_ani, = plt.plot(x[0], y[0], "ro")
plt.grid(ls="--")
text_pt = plt.text(4, 0.8, '', fontsize=16)

ani = animation.FuncAnimation(fig, update_points, np.arange(0, 100), interval=100, blit=True)

# ani.save('sin_test3.gif', writer='imagemagick', fps=10)
plt.show()

我在上面update_points函數中添加了一個文本,讓它顯示點的\((x,\ y)\)的坐標值,同時在不同的幀,改變了點的形狀,讓它在5的倍數幀顯示為五角星形狀。

fig-sin_test1 fig-sin_test3
圖2-3 sin函數點運動效果2 圖2-4 sin函數點運動效果3

再稍微改變一下,可以讓文本跟着點動。只需將上面的代碼update_points函數改為如下代碼,其效果如圖2-4所示。

def update_points(num):

    point_ani.set_data(x[num], y[num])
    if num%5==0:
        point_ani.set_marker("*")
        point_ani.set_markersize(12)
    else:
        point_ani.set_marker("o")
        point_ani.set_markersize(8)
    
    text_pt.set_position((x[num], y[num]))
    text_pt.set_text("x=%.3f, y=%.3f"%(x[num], y[num]))
    return point_ani,text_pt,

總結

本文制作動畫主要用到了MatplotlibAnimation類,雖然講的例子比較簡單,但是據此簡單的原理,足以實現復雜的動畫效果。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM