Rust・Gnuplot・ffmpeg での数値計算: 波動方程式とその可視化

引き続き, Rust の勉強を兼ねて数値計算コードをゴリゴリ書き, 可視化している.

動画・コード・ドキュメントへのリンク

動画は次のリンクから見られる.

ドキュメントとコードは GitHub に置いてある.

議題: 可視化

ここで議論 (質問・相談) したいのは可視化だ. 結論からいうと, RustGnuplot の 3 次元プロットを使いたい. Axes3D というのはあるのだが, いろいろ試してみて, これで splot tmp.dat u 1:2:3 with lines を実現できなかった. 私の実装能力の問題ならいいのだが, とにかくどうしたらいいかわからない. 直接 Gnuplot のコマンドを叩きたいのだが, それは RustGnuplot では対応していないように見える: これも私がドキュメントを拾えていないだけならいいのだが, やはりどうしたらいいかはわからない. Command::new() から直接 Gnuplot ワンライナーで実行しようと思ったものの, これはこれでうまくいかない. どうすればいいか, というのが問題だ.

少なくとも matplotlib で mp4 化するのは 1 次元のデータ量でさえ遅かったので, 絶対にやりたくない. それもあって Gnuplot を導入した経緯がある. png 化するくらいならどうか, と思って試してみたが, これも matplotlib 力が低いせいか, 意図通りのプロットが出ない.

そこで諦めて, Python で csv から png を作る gp ファイルを作り, それを Python スクリプト内のコマンド実行で png 化し, それをさらに Python スクリプト内の ffmpeg コマンド実行で mp4 化した.

ffmpeg を Rust 内でコマンド実行するのはできているから, RustGnuplot のように Rust 内で Gnuplot を実行したい. ソースコードを読み, コード量は少ないが, いまの私が理解できるレベルの Rust コードではなく, 機能追加などは夢のまた夢だった. とても厳しい気持ちになっている.

できる限り Rust 内で関係させたいし, Gnuplot のラッパーがほしい. 夢は果てない.

追記: Rust 内での Gnuplot 直接実行

Gnuplot のワンライナーを実行する形で実装できた. コードの詳細については次のリンク先のファイルを見てほしい.

具体的には次のようなコードで Rust 内で Gnuplot が直接実行できるようになった.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
use std::process::Command;
fn write_png(cnf: &Config, cdata: &CalcData) -> Result<(), Box<dyn error::Error>> {
    let csv_name: String = format!("{}/{:08}.csv", &cnf.dir_name, &cdata.output_num);
    let png_name: String = format!("{}/img.{:08}.png", &cnf.dir_name, &cdata.output_num);
    Command::new("gnuplot")
        .arg("-e")
        .arg(r#"set terminal png;"#)
        .arg("-e")
        .arg(r#"set datafile separator ",""#)
        .arg("-e")
        .arg(r#"set ticslevel 0;"#)
        .arg("-e")
        .arg(r#"set dgrid3d 100,100;"#)
        .arg("-e")
        .arg(format!(
            r#"set zrange [{}:{}]"#,
            &cnf.graph_ulim_min, &cnf.graph_ulim_max
        ))
        .arg("-e")
        .arg(format!(r#"set output "{}""#, &png_name))
        .arg("-e")
        .arg(format!(r#"splot "{}" u 1:2:3 with lines;"#, &csv_name))
        .output()
        .expect("failed to start `gnuplot`");
    Ok(())
}

冗長だが, Gnuplot のスクリプトをワンライナーで実行する形になっている. Gnuplot は詳しくないので Gnuplot を書ける前提なのが厳しいが仕方ない.