ami_GS's diary

情報系大学院生の備忘録。ネットワークの勉強にハマっています。

matplotlibの複数subplotをアニメーションで動かすヤツ

はじめに

こんにちは、GWですが周りの人の予定が合わなくて引きこもってるマンです。

題名の通り、matplotlibでの複数subplotをアニメーションで動かしていこうと思います。
研究で複数チャンネルの信号をリアルタイムで見たいと思い、書いてみたものです。

matplotlibとは?

簡単に言うとMATLABのplot系と同じような処理ができるようになるライブラリです。
データはnumpyの型をそのまま使えます。
少々速度に問題がありそうですが、MATLABが無かったり、サクッとプロットを出したい人には便利かも。

コード

matplotlibでアニメーションをする際には、matplotlib.animation.FuncAnimation()関数を使います。
引数にジェネレータ関数を取るので若干複雑(に見える)かも知れません。


コードは以下のとおり。

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

channelNum = 3       #チャンネル数
samplingrate = 100   #サンプリングレート
sample = 10          #1回のループで取るサンプル数
XMIN, XMAX = 0, 2    #x軸(時間を表す)
YMIN, YMAX = -1, 1   #y軸
INTERVAL = 1000/samplingrate*sample  #アニメーションさせる速さ(ms)
TIME = np.linspace(XMIN, XMAX, samplingrate*(XMAX-XMIN)) #x軸にサンプル点を置いておく

fig = plt.figure()
ax = []
plots = []
ydata = []

for i in range(channelNum):
    tmpax = fig.add_subplot(channelNum,1,i) #チャンネル数だけサブプロット作成
    tmpax.set_xlim(XMIN,XMAX)
    tmpax.set_ylim(YMIN, YMAX) #x,y軸設定
    ax.append(tmpax)
    ydata.append(np.zeros(0))
    plots.append(tmpax.plot(np.zeros(0), ydata[i])[0]) #チャンネルごとのプロット領域にデータをセット

def gen():
    while True:
        data = np.random.rand(sample, channelNum)*2-1  #チャンネルごとにsample分だけランダムな値を取る
        if ydata[0].shape[0] + len(data[:, 0]) >= len(TIME):
            initData() #プロットが右端まで達したらデータ初期化
        yield data

def initData():
    for i in range(channelNum):
        ydata[i] = np.zeros(0) #空にする

def updataData(data):
    for i in range(channelNum):
        ydata[i] = np.append(ydata[i], data[:, i])
        plots[i].set_data(TIME[:ydata[i].shape[0]], ydata[i])

    return plots  #データが格納された配列を返す

if __name__ == "__main__":
    #updateDataに第3引数のジェネレータ(gen)から返されたデータが引数として渡される
    #Macの場合はblit=Falseでないと動かない?
    ani = animation.FuncAnimation(fig, updataData, gen, blit=False, interval=INTERVAL)
    plt.show()

このような感じになります。

channelNum=6でプロットした物が以下になります。
f:id:ami_GS:20140504153901p:plain

アニメーションするのは1つで結構という方はchannelNumを1にしてください。
channelNumが3くらいであれば問題なく動くのですが、10くらいの大きさになると結構遅くなるので注意。

最後に

もしチャンネル数を多くした時の速度が気になるのであれば、tkinter, pyside等のGUIを使ってキャンバスに書き込んだほうが速いと思います。

今回はmatplotlibの紹介ということで許してちょんまげ!