gnuplotで動的なグラフを作ってみた
![](https://lv73.net/wordpress/wp-content/uploads/2020/11/gnuplot.png)
1986年に初版が出たgunuplot。現在でも教育や研究機関で使われていることが多く、熱狂的な支持者もいる。
今日はそのgnuplotを使ってアニメーション化したグラフを作ってみたので、それについて書こう。
gnuplotとは?
グラフを作成するソフトウェア。Linux、Windows、macOSなど幅広いOSに対応している。
作成はCUIで行われるため、コマンドを知っている必要があり、習熟にはそれなりの時間と労力は必要。
難易度的にはGeoGebraの方がGUIなので、直感的に使える。
GeoGebra |無料で使える数学アプリ – 全世界で一億人以上の学生・教師が利用
Wikipediaによれば、gnuplotをGUIで使えるようにするフロントエンドアプリケーションもあるらしい。
作ってみたもの
gifアニメ
![](https://lv73.net/wordpress/wp-content/uploads/2020/11/tangent-differential.gif)
コード
#初期化
reset
#アニメーション初期設定
set term gif animate optimize delay 4 size 640,480
set output 'movie.gif'
#グラフの範囲
set xr[-0.5:2.5]
set yr[-0.5:4.5]
#x軸、y軸の描画
set style arrow 99 head filled size 0.1,30,70
set arrow 98 from -0.5,0 to 2.5,0 arrowstyle 99
set arrow 99 from 0,-0.5 to 0,4.5 arrowstyle 99
set label 98 "X" at 2.5+0.1,0 center
set label 99 "Y" at 0,4.5+0.1 center
#グラフ外枠のメモリを非表示
set noxtics
set noytics
#set xlabel "x"
#set ylabel "y"
#set zeroaxis lt -1
#凡例の位置
set key below
#arrowのstyleの定義
set style arrow 1 nohead lt 3 lw 1 lc rgb "red"
set style arrow 2 nohead lt 0 lw 1 lc rgb "black"
#変数 点A(s,t),点B(a,b),oはaの初期値
o = 2.0
s = 0.5
t = s * s
g(x) = (a*a-t)/(a-s)*(x-s)+t
f(x) = x*x
k = (o - s)/200
set arrow 3 from s,0 to s,t arrowstyle 2
set arrow 4 from 0,t to s,t arrowstyle 2
set label 1 "a" at s,-0.15 center
set label 2 "f(a)" at -0.15,t center
set label 5 point pt 4 at s,t
set label 7 "A" at s-0.1,t+0.1
set label 10 "O" at -0.1,-0.15
#アニメーションループ
do for [i = 0:200 ] {
a = o - i * k
b = a*a
set arrow 1 from s,t to a,t arrowstyle 1
set arrow 2 from a,t to a,b arrowstyle 1
set arrow 5 from a,0 to a,t arrowstyle 2
set arrow 6 from 0,b to a,b arrowstyle 2
set label 3 "a+h" at a,-0.15 center textcolor rgb "red"
set label 4 "f(a+h)" at -0.15,b center textcolor rgb "red"
set label 6 point pt 4 at a,b
set label 8 "B" at a-0.1,b+0.1
plot f(x) title "f(x)=x^2" lc rgb "black",g(x) title "Tangent" lc rgb "blue"
}
set out
set terminal wxt enhanced
マニュアルやサイトを見ながら作ったので、ソースは汚い。
補足
gnuplotのバージョンは5.2.8を使用。アニメーションを作れるようになるのは4.6以降らしい。
ポイントは2箇所。
set term gif animate optimize delay 4 size 640,480
set output 'movie.gif'
~
set out
ターミナルをgifアニメーションモードに切り替える。
オプション animate はあなたの手元にある gd ライブラリがアニメーション gif の作成をサポートする場合にのみ有効です。作成される画像の表示間隔は、1/100 秒単位で指定できます (デフォルトは 5)。ただし実際の表示間隔は、使用する表示ソフトによって変化します。アニメーションの繰り返し回数も指定できますが、デフォルトは 0 でそれは無限の繰り返しを意味します。アニメーション画像列は、次の set output か set termコマンドによって終了します。オプション optimize は、アニメーションに関する 2 つの効果を持ちます。
1) アニメーション全体を通じて単一のカラーマップが使用されます。これはアニメーションの全てのフレームで使用される全ての色が最初のフレームで定義されている必要があります。
2) 可能ならば、個々のフレームで一つ前のフレームと違う部分のみがアニメーションファイルに保存されます。これはファイルサイズを小さくしてくれますが、透明化機能を使用している場合には働かないかもしれません。
これら両方の最適化はより小さいサイズの出力ファイルを作ろうとするものですが、多分その減少量は、長いアニメーションかまたはフレームサイズがとても小さな場合にのみ意味がある程度でしょう。オプションnooptimize はこれらの効果をいずれも無効にします。各フレームは、個々のカラーマップ (プライベートカラーマップ) を使い、丸ごと保存されていきます。一つ注意しておきますが、最適化されていないアニメーションファイルは外部ユーティリティを使って後処理することができますし、その後処理によって gnuplot の最適化よりも小さなファイルが作られるかもしれません。デフォルトでは nooptimize です。
gnuplot documentation
optimizeはgifを圧縮してファイルサイズを落としてくれる。上記gifでオプションなしだと、1,208KB。オプションありだと659 KBと半分程度に抑えられる。
delayでアニメーションの速度を変更する。
ドキュメントにもある通り、gifを表示するソフト等の環境によって変わる。delayを小さくしても一定以上は表示間隔を小さくすることは出来ない。むしろ小さすぎると遅くなるようなので、だいたい4より大きくするのが良いかも。
#アニメーションループ
do for [i = 0:200 ] {
a = o - i * k
b = a*a
set arrow 1 from s,t to a,t arrowstyle 1
set arrow 2 from a,t to a,b arrowstyle 1
set arrow 5 from a,0 to a,t arrowstyle 2
set arrow 6 from 0,b to a,b arrowstyle 2
set label 3 "a+h" at a,-0.15 center textcolor rgb "red"
set label 4 "f(a+h)" at -0.15,b center textcolor rgb "red"
set label 6 point pt 4 at a,b
set label 8 "B" at a-0.1,b+0.1
plot f(x) title "f(x)=x^2" lc rgb "black",g(x) title "Tangent" lc rgb "blue"
}
コメントにもあるように、do forが繰り返し実行される部分となる。他のプログラム言語と同様、iは0から始まり、200になるまで{}の中身を実行し続ける。
arrowもlabelもタグ(arrow 1とか2とかの数字の部分)はアニメーションでは必須。付けないと、新しく描画し直さず、そのまま残したまま描画していく。ここで結構ハマった。
感想
最初の一つを作るまでは結構時間が掛かった。慣れれば、もっと早く作れるだろう。
前述の通り、GeoGebraの方が導入コストは安く済むし、スライダーで変数を弄ったりも出来る。
gnuplotを使った理由はライセンスに縛られない点に尽きる。ただ実際に触って見て、かなり自由度の高さを感じたので、これからも頑張って使っていきたい。