どうも、Hiro(@hiroloquy)です。
以前、gnuplotのアイコンをgnuplotで再現するという試みの過程に関する記事を書きました。
アイコンの構成要素は軸、グリッド、折れ線グラフと少なく、gnuplot上で再現するのはカンタンでした。そして、思いつき→コーディング→SNS公開のプロセスが非常に短時間だったので、公開時点ではかなり達成感がありました。
しかし、SNSへ公開後にブログ記事を書く中で物足りなさを感じていました。その物足りなさとは、アイコンの「動き」のなさです。アイコンに動きを求めるのはなんですが、やはり動きがあり、アニメーションにした方が面白いなぁと思いました。
そこで本記事では「アイコンを動かす」ことを目的として、以前作成したgnuplotアイコンのプログラムを改造しようと思います。
以降では、アイコンをどのように動かすかのアイデアをもとに、必要な機能をプログラムに追加し、実際に作ったアイコンのアニメーションを紹介します。よければ記事を読んでいただけると幸いです。
アイコンに動きを与えるアイデア
「ではどのような動きを与えるか?」
gnuplotのアイコンを動かす上で、構成要素である3色のグラフに着目しました。
グラフが徐々に現れるアニメーションを過去に作った経験と、アイコンの構成要素が少ないので、グラフに動きを与えるのが無難かと。
なのでgnuplotの3色のグラフが左側から徐々に表示されるアニメーションにしようと思います。
過去に作ったグラフのアニメーションがこちら▼▼▼
プログラムの改良点
グラフのサンプル点のデータの用意
3つの折れ線グラフの折れ点の座標はこのテキストデータに保存されています(以前の記事と同じデータです)。
これを使うことでグラフが描けますが、折れ点の間隔はバラバラのため徐々に表示するアニメーションには不向きです。
そのため、アイコン中のグラフのサンプル点をたくさん保存されたテキストデータを用意する必要があります。サンプル点を用意するためには、折れ線グラフの数式を調べる必要があります。
折れ線グラフを構成する1次関数の傾きと $y$ 切片の計算
折れ線グラフは折れ点を境にいくつかの1次関数で構成されています。そこで、ある隣り合った折れ点2箇所を使えば1次関数 ( $y=ax+b$ ) として傾き $a$ と $y$ 切片 $b$ を計算することができます。
ある2点を通る1次関数は定式化が簡単なので、その式を使って傾きと $y$ 切片を求めることもできます。しかしそれでは面白くないので、今回はgnuplotのフィッティングのコマンド fit
を使用します。
サンプル点生成のアルゴリズム
グラフのサンプル点を生成するためのアルゴリズムの流れはこのようになっています。(図を追加予定)
あとはこれをプログラムにするだけです。
gnuplotでプログラムを作成
プログラム:GitHubで公開
今回作成したプログラムがこちらです(GitHubで公開しています)。
このプログラムには問題点や工夫などを含め、3つのポイントがあるのでそれらについて解説します。
ポイント1:関数 idx による1次元配列の擬似的な2次元化
プログラミング言語には配列 (array) というものがあり、添字を指定することで数値や文字列を呼び出すことができます。数学のベクトルのような1次元もあれば、行列のような多次元の配列もあります。
一方、gnuplotでは1次元配列しかありません。
今回は複数の1次関数の傾きと $y$ 切片を計算するので、2種類のパラメータを1つの配列にまとめて保存する方が良いです。そこで、関数idx()
を定義して1次元配列を擬似的に2次元配列として扱えるようにすれば、傾きと $y$ 切片をセットにして配列に保存することができます。
そもそも、プログラミング言語の多次元配列は1次元配列をベースにしているのでやっていることは同じです。gnuplotにも多次元配列を標準実装して欲しいですね…
ポイント2:累次評価演算子を用いた arrow の連番更新
今回のプログラムでは累次評価演算子と呼ばれる演算子を set arrow
で使用しました。累次評価演算子はカンマ ,
と括弧 ()
で構成されます。例えば
print (a=1, b=2, a+b)
と入力するとします。累次評価演算子はかっこ内のカンマで区切られた複数の式を先頭から順番に実行する演算子であり、
a=1
b=2
print a+b
と同じ結果が得られます。この例の実行結果だと 3
(=1+2) が表示されます。
累次評価演算子の解説記事は下記のサイトがわかりやすいので参考にしてください。
このように、累次評価演算子では複数の計算式を1つにまとめて実行することができます。
そこで set arrow
の番号をあるカウンタ変数(ここではarw_num
)で表し、次のようなコードにすると、番号が連番になるよう更新してくれます。しかもコードの行数が変わらないのでオススメです!
arw_num = 0 # arw -> arrow
set arrow (arw_num=arw_num+1, arw_num) ... # arw_num = 1
...
ポイント3:枠線&長方形による枠線の角欠け対策
このアイコンをPNG出力する際に苦労したのが枠線の角が欠ける問題です。
今回は枠線 (boder
) をデフォルト値よりも太くしたことにより、左上の角が欠けるという問題が発覚しました。qtウィンドウでは角欠けは起きませんでしたが、pngcairoでPNG画像を出力するとこのような問題が起きます。
そこで set border
でグラフの枠線を描くのではなく、長方形の枠線をグラフの枠線の代わりにしようと考え、set object ... rectangle ...
で対処を試みました。すると左上の角欠けは解消できたものの、次は左下の角が欠けました…。
それぞれのコマンドで異なる位置の角が欠けるので、プログラムでは set border
と set object ... rectangle ...
の両方のコマンドを実行しています。これにより線が重なった状態にはなりますが角がかける問題を解消することができました。
出力画像からGIFデモを作成
pltファイル中のPrameter
にあるqtMode
をqtMode==0
にすると、ターミナルはpngcairo
に切り替わってフォルダpngを生成し、その中にPNG画像 img_xxxx.png を出力します。
PNG画像をGIF動画に変換するために、私はFFmpegを使用しました。
1行目でcd
コマンドでディレクトリをpngフォルダに移動し、2行目でFFmpegを実行するとまずdemo.mp4が生成され、さらに3行目を実行するとその動画を使ってdemo.gifを生成します。
cd animate-gnuplot-icon
ffmpeg -framerate 60 -i png/img_%04d.png -vcodec libx264 -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" -r 60 demo.mp4
ffmpeg -i demo.mp4 -filter_complex "[0:v] fps=30,split [a][b];[a] palettegen [p];[b][p] paletteuse" demo.gif
上記コマンドを使って生成したGIF動画が左側です。また右側はプログラム終了時に生成するPNG画像です。
「動き」があるものを見る方がやはりおもしろいですね。
今回作ったプログラムの開発環境はこちらです。
まとめ
今回は、以前gnuplot上で再現したgnuplotのアイコンのグラフを部分的に描画することでアニメーションを作りました。
静止画でつまらないアイコンをアニメーションにするためにフィッティングのコマンド fit
が必要なのは思いもよりませんでしたが、知見が増えてよかったです。
今回作成したスクリプトやデモGIFなどは私のGitHubでも公開しています。英語で書いたREADMEもあるので、そちらも参考にしてみてください。
また、YouTubeにShorts動画としてアップロードしたのでご視聴よろしくお願いします!
コメント