使用python matplotlib實現動圖繪製

ai-exception發表於2018-06-13

前言

想寫資料動態視覺化很久了,但是網上竟然沒有一份能直接用的程式碼,昨天終於狠下心來死啃了一波開發者文件搞定了這部分,貼一篇blog記錄一下希望可以幫到你。

思路

動圖的核心函式是matplotlib.animation.FuncAnimation,基本用法:

anim = animation.funcanimation(fig, animate, init_func=init, frames=100, interval=20, blit=true)
# fig: 是我們建立的畫布
# animat: 是重點,是我們每個時刻要更新圖形物件的函式,返回值和init_func相同
# init_func: 初始化函式,其返回值就是每次都要更新的物件,
#    告訴FuncAnimation在不同時刻要更新哪些圖形物件
# frames: 相當於時刻t,要模擬多少幀圖畫,不同時刻的t相當於animat的引數
# interval: 重新整理頻率,毫秒
# blit: blit是一個非常重要的關鍵字,它告訴動畫只重繪修改的部分,結合上面儲存的時間,
#    blit=true會使動畫顯示得會非常非常快

動圖繪製的關鍵是動態更新資料並重新整理影象,更新資料需要寫一個animat函式,看具體實現:

實現

給出程式碼及對應註釋,你應該會秒懂:

# -*-coding:utf-8-*-
import random
from matplotlib.backends.backend_agg import FigureCanvas




from matplotlib import pyplot as plt
from matplotlib import animation
import numpy as np
import seaborn as sns
from matplotlib.image import imread











gesture_i = [0] * 2200
gesture_q = [0] * 2200
acc_first = [0] * 6
acc_second = [0] * 6

acc_first_max_index = 0
acc_second_max_index = 0
acc_first_max = 0
acc_second_max = 0

cur_data_count = 0

update_first_flag = False
update_second_flag = False








name_list = ["Static", "Approach", "Apart", "Click", "Flip", "Circle"]

# 建立畫布,包含4個子圖
fig = plt.figure(figsize=(15, 10))

bgimg=imread("bac2.jpg")#設定背景圖片
fig.figimage(bgimg,resize=True)#設定視窗自適應(背景圖片)



ax1 = fig.add_subplot(2, 2, 1)
ax1.set_facecolor('none')#設定該子圖背景透明,其他子圖同理


ax2 = fig.add_subplot(2, 2, 3)
ax2.set_facecolor('none')



ax3 = fig.add_subplot(2, 2, 2)
ax3.set_facecolor('none')

ax4 = fig.add_subplot(2, 2, 4)
ax4.set_facecolor('none')

# 繪製初始圖形
bar1 = ax3.bar(range(len(acc_first)), acc_first, color='rgb', tick_label=name_list)


bar2 = ax4.bar(range(len(acc_first)), acc_first, color='rgb', tick_label=name_list)


x = np.arange(0, 2200, 1)  # x軸

ax1.set_ylim(-1, 1)#設定y軸範圍為-1到1
line1, = ax1.plot(x, gesture_i,color='coral')

ax2.set_ylim(-1, 1)
line2, = ax2.plot(x, gesture_q,color='coral')

#初始化函式
def init():
    # 構造開始幀函式init
    # 改變y軸資料,x軸不需要改
    line1.set_ydata(gesture_i)
    line2.set_ydata(gesture_q)
    bar1 = ax3.bar(range(len(acc_first)), acc_first, color='rgb', tick_label=name_list)
    bar2 = ax4.bar(range(len(acc_second)), acc_second, color='rgb', tick_label=name_list)

    ax1.set_xlabel("I")
    ax2.set_xlabel("Q")

    return line1, line2, ax1  # 注意返回值,我們要更新的就是這些資料

#更新影象的函式
def animate(i):
    #注意這裡必須要用global宣告,不然可能出現無法動態更新資料的情況
    global gesture_i
    global gesture_q
    global update_first_flag
    global update_second_flag

    line1.set_ydata(gesture_i)

    ax3.cla()
    bar1 = ax3.bar(range(len(acc_first)), acc_first, color='rgb', tick_label=name_list)
    ax3.legend()

    ax4.cla()
    bar2 = ax4.bar(range(len(acc_second)), acc_second, color='rgb', tick_label=name_list)
    ax4.legend



    return line1, line2, ax1





def draw_view():
# 呼叫FuncAnimation函式生成動畫。引數說明:
# fig 進行動畫繪製的figure
# func 自定義動畫函式,即傳入剛定義的函式animate
# frames 動畫長度,一次迴圈包含的幀數
# init_func 自定義開始幀,即傳入剛定義的函式init
# interval 更新頻率,以ms計
# blit 選擇更新所有點,還是僅更新產生變化的點。應選擇True,但mac使用者請選擇False,否則無法顯示動畫
    ani = animation.FuncAnimation(fig=fig,
                                  func=animate,
                                  frames=100,
                                  init_func=init,
                                  interval=100,
                                  blit=False)
    plt.show()


if __name__ == '__main__':
    draw_view()

說明:實現動態資料視覺化的思路是將繪製影象所用的資料寫成全域性變數,然後動態更新你的資料,UI層會一幀一幀地重新整理影象,這樣只要你的資料在變,影象就會是變化的,給一張效果圖:
這裡寫圖片描述

相關文章