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でプロットした物が以下になります。
アニメーションするのは1つで結構という方はchannelNumを1にしてください。
channelNumが3くらいであれば問題なく動くのですが、10くらいの大きさになると結構遅くなるので注意。
最後に
もしチャンネル数を多くした時の速度が気になるのであれば、tkinter, pyside等のGUIを使ってキャンバスに書き込んだほうが速いと思います。
今回はmatplotlibの紹介ということで許してちょんまげ!