注: 在“實驗設計與數據處理”的課后作業中,有一個數據可視化的作業,利用課程上學習的某種方法找一個二維函數的最大值,並將這個尋找的過程可視化。在作業里面利用了Matplotlib的Animation類實現可視化的動態展示。
1、引言
利用Animation類制動畫主要是參考了官方的教程:Matplotlib-Animation。為了更加清析說明Animation類是如何實現動畫的,本文只簡單地介紹一個點沿着sin函數運動的例子,分析一下Animation實現動畫的原理。其它復雜的動畫同樣也是據此原理,可以實現下面的動畫效果。第3幅圖是作業的一個效果圖。
sin函數點運動 | 二階擺鍾(官方例子) |
---|---|
![]() |
![]() |
![]() |
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()
![]() |
![]() |
圖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的倍數幀顯示為五角星形狀。
![]() |
![]() |
圖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,
總結
本文制作動畫主要用到了Matplotlib的Animation類,雖然講的例子比較簡單,但是據此簡單的原理,足以實現復雜的動畫效果。