変化するデータファイルをリアルタイムにプロットするスクリプト

シミュレーションなどでデータをファイルに出力する際,リアルタイムにデータをプロットしたい場合がある.gnuplot を popen し,自動的に replot によって描画を更新する python スクリプトを作ってみた.

  • たぶん linux 限定ですorz... cygwin 上でなら使えるかも.

itplot

os.popen でプロセスを開いて,write メソッドで書き込み,flush メソッドでフラッシュする.前半はコマンドラインオプションのパース.

#!/usr/bin/python
import os,time,sys

usage='''iterative graph plotter using gnuplot
  usage: itplot [OPTION] PLOTLINE
    OPTION:
      -s XXX  setting line
      -i T    iteration interval (second)
      -help   show help
  example:
    itplot hoge.dat using 3:4
    itplot -s 'set xrange [-1.5:1.5];set yrange [-1.5:1.5]' hoge.dat
    itplot '"< tail -100 trajectory.dat"' u 1:3 w lp'''

# default setting:
setting='set key right bottom'
setting=setting+'; min(x,y)=x<=y?x:y; max(x,y)=x>=y?x:y'

pline=''
tsleep=1.0

it= iter(sys.argv)
it.next() # skip exec name
while True:
  try:
    a= it.next()
    if a=='-help' or a=='--help': print usage; sys.exit(0)
    elif a=='-s': setting=setting+'; '+it.next()
    elif a=='-i': tsleep=float(it.next())
    elif os.path.exists(a): pline=pline+' "'+a+'"'
    else: pline=pline+' '+a
  except StopIteration:
      break

print 'plot '+pline

g= os.popen('gnuplot -noraise','w')
g.write(setting+'\n')
g.write('plot '+pline+'\n')
g.flush()

try:
  while True:
    g.write("replot\n")
    g.flush()
    time.sleep(tsleep)
except KeyboardInterrupt:
    g.close()

使い方

itplot -i 0.1 out.dat w l

とすれば,out.dat を直線で (w l) プロットし,0.1秒ごとに更新しつづける."out.dat w l" は gnuplot に直接送られるので(ただしファイル名はクォートされる),

itplot -i 0.1 out.dat u 1:3 w l, out.dat u 1:4 w lp

みたいなこともできる(out.dat の1:3行を直線でプロット,out.datの1:4行を点と直線でプロット).
out.dat がリアルタイムに更新されるファイルなら,自動的にグラフが更新されて行く.

itplot -s 'set xrange [-1:1]' -i 0.1 out.dat w l

こうすると,x方向のプロット範囲が[-1:1]で固定される.-s '...' で指定したものは,gnuplot の plot コマンド以前に実行される.

なお,終了はCtrl+Cで.

例:リサージュ

C++ でリサージュカーブをデータで出力するプログラムを書き,それをリアルタイムに描画してみる.

#include <fstream>
#include <cmath>
#include <unistd.h>
using namespace std;

int main(int argc, char**argv)
{
  ofstream ofs("out.dat");
  for (double t(0.0);t<10000.0;t+=0.01)
  {
    ofs<<cos(M_PI*t)<<" "<<sin(2.0*M_PI*t)<<endl;
    usleep(10000);
  }
  return 0;
}

こんな感じで書いて保存,実行.
別の端末を開いて,同じディレクトリで

itplot -i 0.1 -s 'set xrange [-1.2:1.2]; set yrange [-1.2:1.2]'  out.dat w l lt 3

と実行すると,リサージュ曲線がプロットされる.
でも,これだと2周目以降はカーブが重なってしまうので,

itplot -i 0.1 -s 'set xrange [-1.2:1.2]; set yrange [-1.2:1.2]'  '"< tail -40 out.dat"' w l lt 3

のようにして,out.dat の最後の40行だけ抽出し,プロットする.すると,オシロスコープでリサージュを観察してるような感じになる.