PGPLOTでGIFアニメーションを作る

以前矢島君が自身のホームページで紹介してくれたGIFアニメーションの作成方法は、
1つのFORTRANコードで、次々に名前の異なった画像ファイルを吐き出すという巧みな方法を使っています。
FORTRANやC等の高級な言語では、ソース内で出力ファイル名を次々に変えることは
ちょっと難しいテクニックで、矢島君の方法ではソースによって使えないこともありました。
これから紹介する方法はFORTRAN(もちろんCにも応用可)とシェルスクリプトを使った、
おそらく普遍性のある方法です。

基本方針

この方法の基本的な方針は以下の通りです。

1.時間発展ルーチン内で「plot.gif」という名前のファイルを定期的に吐き出す。
2.裏でシェルスクリプトをまわしておき、同じディレクトリ内にplot.gifという名前のファイルが
  出現したら、連番をつけてanime/というディレクトリ内に格納する。
3.anime/ディレクトリにできた全GIFファイルをアニメーションにまとめる。


それでは、一つずつサンプルを見ながら解説します。

1.plot.gifの出力

まずは以下のソースファイルを同じディレクトリ内にダウンロードしてください。
sample.f(ソースコード)
winit1200.d(データファイル)
init.d(データファイル)
Makefile(メイクファイル)
com6.h(ヘッダファイル。ただしダウンロードするとc6.txtという名前になるので、com6.hに名前を変えること。)
anim.sh(bash用シェルスクリプト)
anim_csh.sh(tcsh用シェルスクリプト)
ソースコードは大雑把に見て次のような構造をしています。

(メインプログラム)
c========= PGPLOT REALTIME DRAWING ============
c IF (PGOPEN('?').LT.1) then
c ENDIF
c CALL PGENV(-4.5,4.5,-1.,3.5,1,-2)
c==============================================


......................(略)................................

do 150 it=1,nt

call symp(......)

......................(略)..............................

if (mod(it,istep).eq.0) then
call plot(x,y,xw,yw,t,vcy,it,nt)
endif

150 continue
c========= PGPLOT REALTIME DRAWING ============
c call pgclos
c==============================================

end

......................(略)................................

(サブルーチン)
cccccccccccccccccccccccccccccccccccccccccccccccccccccccc
subroutine plot(....................)
cccccccccccccccccccccccccccccccccccccccccccccccccccccccc

c========= PGPLOT REALTIME DRAWING ============
IF (PGOPEN('plot.gif/GIF').LT.1) then
ENDIF
CALL PGENV(-3.5,3.5,-1.,3.5,1,-2)
c===============================================


......................(略)................................

c========= PGPLOT REALTIME DRAWING ============
call pgclos
c==============================================

end

istep毎にplotルーチンを呼び出して系全体のスナップショットを表示する内容になっています。
ここで「PGPLOT REALTIME DRAWING」という部分がいくつかありますが、
リアルタイムアニメを出力するときはサブルーチンplot内、GIFファイルを出力するときはメインプログラム内
の「PGPLOT REALTIME DRAWING」部分をすべてコメントアウトします。

上の例ではGIFファイルを出力したいので、メインプログラム内がコメントアウトされています。これで、plotルーチンが
呼ばれるたびにplot.gifというファイルが作成されます(PGOPEN内の引数に注意!)。

2.anim.shの使い方

ターミナル上で「make」コマンドを打つと、Makefileの中身にしたがってコンパイルが行われ、
同じディレクトリ内に「main」という名前の実行ファイルができます。mainを実行すれば
istep毎にplot.gifというファイルが出力されますが、時間が経つごとにplot.gifは上書きされてしまいます。
そこで、mainを実行する前に前もってシェルスクリプト anim.sh(tcshの場合はanim_csh.sh)を実行しておいて、plot.gifに連番をつけて
GIFファイル用のディレクトリに格納しましょう。スクリプトの内容は以下の通りです。

anim.sh(bash用)とanim_csh.sh(tcsh用)
#! /bin/bash

i=1

while [ 1 ]
do
if [ -r plot.gif ]
then
mv plot.gif ./anime/${i}.gif
echo ${i}
i=`expr $i + 1`
fi
done
#! /usr/bin/tcsh

i=1

while ( 1 )
if ( -r plot.gif ) then
mv plot.gif ./anime/${i}.gif
echo ${i}
@ i += 1
endif
end

一行目の#!の後には自分が使っているシェルのパスを書きます。自分が使ってるシェルは「echo $SHELL」で、
そのシェルのパスは「which (シェル名)」でわかります。例えば殆どの人はyuragiでtcshを使っていますが、
「which tcsh」というコマンドを打つと「/usr/bin/tcsh」と表示されますので、yuragiなら「#! /usr/bin/tcsh」と
書くわけです。
このスクリプトのアルゴリズムは、「常にディレクトリ内を監視して、もしplot.gifという名前のファイルが出現したら、
i.gif(iは1以上の整数)という名前をつけてanimeディレクトリの下に格納し、
iを標準出力に表示した後、iに1を加える。
」となります。
ちなみに上記のスクリプトは左がbash用、右がtcsh用です。
このスクリプトを実行形式にするために「chmod 755 anim.sh」というコマンドを打ってください。
あとはmainを実行する前に必ずanime/ディレクトリを作ってから、
「nice -n +19 ./anim.sh」というコマンドでanim.shを実行しておきます

3.GIFアニメーションの作成

サンプルプログラムでは50フレーム作成したら、プログラムが終了するようになっています。
anime/ディレクトリに移動すると1〜50.gifというファイルができています。
あとはこれをアニメーションGIFファイルにまとめましょう。以下のスクリプトをanime/ディレクトリに
保存してください。
gifanim.sh
このスクリプトの中身は以下のようになっています。

#! /bin/bash

whirlgif -time 10 `perl -e 'for($j=1;$j<=50;$j++){print "$j.gif "}'` >test.gif

これは矢島君のページにあるhenkanファイルの中身をうまく書き直したものです。
これはbashとtcshで共通です。これもやはり「chmod 755 gifanim.sh」で実行形式にしてから
「./gifanim.sh」で実行します。すると同じディレクトリ内にtest.gifというファイルができるので
あとはNetscapeやxanimで再生してください。

まとめ

今までの手順をまとめると次のようになります。

1.サンプルプログラムのように、コードを組む。plotルーチンを作っている場合は
  サブルーチンの中にPGOPENやPGENV命令を書き、PGOPENの引数は('plot.gif/GIF')
  にする。
2.makeで実行ファイルmainを作る。
3.anime/ディレクトリを作成し、anim.shを実行する。
4.mainを実行するとanime/ディレクトリ内にGIFファイルが何枚かできるはず。
5.anime/ディレクトリに移動して、gifanim.shを実行すれば、アニメーションファイルtest.gifができる。
6.必ずanim.shのプロセスをkillすること!!(topコマンドでPIDはわかる)