Bluepostech

まじめなことを書きます

【gnuplot】for文が使えないときにgnuplotでループを使う方法

gnuplotで、プロットしたグラフをアニメにしたいことは多い。

最近のgnuplotにはfor文が実装されている。ところが古いバージョンではfor文は使うことができない。その場合に考えられうる方法は主に2つある。

ひとつは、reread文を使うという方法。forがない時代のプログラム言語でやっていたように、「条件が満たされればループを抜ける」ということを手書きで表現するのである。

サンプルスクリプトが次だ。次のスクリプトをファイルに保存してgnuplotで流せば、sin波が進んでいく画像がコマ撮り写真のように1枚ずつ出力される。

set terminal pngcairo
set xrange [0:7]
set yrange [-1.5:1.5]

if (exist('i')==0 || i<0) i=0
phase=i*0.314

set output sprintf('smp/smp%03d.png',i)
set title sprintf('sample %03f sec',phase)
show title
plot sin(x-phase)

if(i<100) pause 0.1;i=i+1;reread
i=-1

rereadというコマンドは、そのスクリプトを最初からやり直すということを意味する。ただし他の言語のように「ある行番号まで飛ぶ」とかそういうことはできず、最初からやり直される。

なのでループする部分だけ別のファイルにして、メインのスクリプトから呼び出す、ということが必要になるんじゃないかと直感的には感じる。しかし実は変域などの設定にはそんなに時間はかかっていない。なので普通にスクリプトを最初から最後までやり直す方法でいいだろう。

これで出力したpngImageMagickで20サンプルをgifアニメにしたものが次だ。

f:id:bluepost69:20151204221345g:plain

このpngファイルをSSHサーバ上で100枚プロットするのにかかった時間は14秒だった。

もうひとつは、シェルスクリプトのループを使うという方法。

echo 100
mkdir smp1
for ((n=0;n<=100;n++))
do
phase=$n*0.314
echo $n
gnuplot -e "i=${n};
phase=${phase};
set terminal pngcairo;
set output sprintf('smp1/smp%03d.png',i);
set xrange [0:7];
set yrange [-1.5:1.5];
;
set title sprintf('sample %03f sec',phase);
plot sin(x-phase)"
done

直感的には後者のほうがgnuplotを閉じたり開いたりするので時間がかかりそうだが、実は後者のほうが2~3倍くらい速く、同じ100枚プロットに要した時間は5秒だった。