GNUPlotを使ってリアルタイムでグラフを描いてみよう
実行ファイルを作成し,シミュレーションなどの数値をテキストファイルに書き込み,Excelで読み込んでグラフを描くことはできる.しかし,例えば,パラメータの数値を変化させて違いを知りたいときは,これらの一連の作業が煩わしいと感じるため,シミュレーションの結果を見ながらパラメータを調整する場合,現在の状態を含めて,グラフィカルに確認できる手段が欲しくなる.
古のシステムであれば,簡単なコマンドをソースファイルに記述して,画面に直接グラフを描くこともでき,シミュレーションの過程や結果を簡単に確認することもできたが,今はそこまで簡単でもなくなっている.
ここで扱うテクニックは,皆さんが卒業論文などでシミュレーション,データ解析を行う上でも利用できる実用的なものですので,ぜひマスターしよう.
実験した直後にすぐ解析,条件を変えてシミュレーションをすることで,より多くの知見を得ることができるはずである.
グラフィックについて
画面のある座標から別の座標まで線分を引くことを考えてみよう.
現状のシステムでは,Windowsであれ,Mac(Linux)であれ,デスクトップに直に線分を描くことはせず,あるウィンドウが立ち上がって,そのウインドウの枠内の座標に対して線分を描いている.
ウィンドウをマウスで動かせば,ウィンドウ内の線分も同様に動くことが確認できる.
コーディングして線分を描くように記述をして作った実行ファイルが,グラフィックボードを直接コントロールして線分を描いているのではないことを知っておいて欲しい.
では,何をしているかと言うと,実行ファイルはOSに働き掛け,OS内のライブラリを呼び出してCPUからバスを介し,グラフィックボード内のGPUに働きかけて描画を行っているのである.
実行ファイルとOSの間にAPI(Application Programming
Interface)の関係があり,実行ファイルはアーキテクチャ内の動作をコントロールしなくても,OSにコマンドを送るだけで動作する.
先の動作については,ある大きさのウインドウを開く,ウィンドウ内の座標において線を描画する,というタスクが実行されていると考えればよい.
従って,C/C++言語そのものにグラフィックを描く機能は備わっていないこと※を留意しておこう.
※C/C++言語は,OSそのものを作ることもできることからAPIを作ることもでき,あるいはAPIをまとめたミドルウェア(プログラム間の通信など司る)を作ることもでき,ハードウェアを動作させるドライバを作ることもできるので,厳密にはC/C++言語にグラフィックを描くことができないというのは間違いであるが,説明の関係上,上記のように記した.
すなわち,コーデイング上は,APIを呼び出すためのコマンドとなる記述をしていることとなる.
従って,このコマンドを示す関数を持ったヘッダファイルやライブラリを適宜インクルード,リンクすればグラフィックを使うことができるのである.初めに説明した古のシステムであれば,関数1行で描けたものが簡単でなくなったと考えればよい.
しかも,このヘッダファイルやライブラリが難物で,OS,開発環境(プログラミング言語を扱うソフトウェア群),OpenGL(グラフィックライブラリ)などのバージョンなどによる仕様変化により,意図しない描画になるような不具合も発生するのである.
そこで,グラフィックを扱うための手法についていくつか紹介しよう.
アイディア1:描画に長けたソフトウェアを利用する
そこで,確実にグラフィックを扱うには,確実に描画できるソフトウェアにデータを送るということを考えればよく,これまでの授業で扱ったのは,テキストファイルに書き出し,手動でExcelに読み込みグラフを描いていたが,これを自動化するものである.
GNUPlotというソフトウェアがあり,これにデータを送り込むのも一策であるが,これが無くなる,容易に使えなくなる可能性もないわけではなく,また,仕様が変わる可能性もある.また,大変美しい描画をするため,若干時間がかかるのも手軽な運用にはやや向かないとも言われている.
http://www.gnuplot.info/
商用ソフトウェアにMATLAB,よく似た無料のscilabがあり,MATLABとscilabには違いがあるため,これらの差を埋め合わせるMAT@scilabというツールもある.
https://jp.mathworks.com/products/matlab.html
https://www.scilab.org/
https://www.vector.co.jp/download/file/data/edu/fh691392.html
これらに対して,自作のプログラムのデータを送り込む方法もある.授業では扱わないが関心のある学生は,ぜひ試してほしい.(GNUPlotは扱う.)
Excelで生成されるグラフは,そのままでは科学技術に関する資料にすることは難しく,かなり体裁を整えなければならないので,Excelで数値データをまとめ,上記に挙げたようなソフトウェアに読み込ませるのも有効であると考えられる.
アイディア2:描画に長けた言語のライブラリを使う
本授業の3回目でpythonを利用した.現在pythonは裾野の広いユーザに支えられ,多くのライブラリが実装できる.その中に,グラフの描画に適したライブラリmatplotlibがあり,これを利用する.(さらに綺麗にしたければseabornというライブラリもある.)
アイディア1と異なるのは,C/C++の開発環境でコーディング,コンパイルを行うが,コンパイルの際,pythonのインタープリターを呼び出して描画する機能を組み込む点である.
さらに加えると,pythonのコマンドを呼び出すためのヘッダ,ライブラリを自作するか,ネットで流通しているもので著作権の問題のないもの※を利用するかを考える必要がある.
※ソフトウェア開発の世界ではオープンであることを良しとする文化もある.プログラマ相互が技術を享受し提供する関係である.
しかしながら,著作権について細かく見ていくと,著作権を主張しない,自由に使ってよいが著作権は放棄しない,改変しないで欲しい,個人利用のみ自由,費用は発生しないが一報して欲しい,費用が発生する(初期費用のみ,期間あり)など様々なものがある.readme.txt(昔はreadme.docもあったが初期のwordが拡張子を被せてしまった)などをよく読んで利用するのが作法である.
アイディア3:正攻法
C/C++で描画のためのヘッダやライブラリを作るというのももちろん有効である.敷居は高いが一旦作ればしばらく使うことができる.あるいは開発環境として,Visual
Studio(C/C++/C#)やC/C++ Builderを用い,例えばWindows用のAPIや.NET
Framework(CLI:共通言語基盤)などOSに依存するライブラリを内蔵しているものを用いることもできるが,有償である.およそ14万円,17万円であり,個人で使うには少々覚悟が必要なものでもある.もちろんOSのマイナーバージョンが上がれば,これに関するライブラリを使えるようなサポートがあるため,商用ソフトウェアの開発には必須のツールでもある.
12/17実施の手順
本授業では簡単なアイディア1に則って,進めていく.
今までは,FILEポインタを利用して,テキストファイルを開き,fprintf()関数で数値とカンマやタブ,改行で解をテキストファイルに書き込み,CSVやTSVファイルを作り,エクセルに書き込んでいた.
エクセルのグラフは,何も設定しないと科学技術の分野のグラフとしては大味であり,また,必要な情報も伝えきれない.かなり手を入れないと[らしい]グラフにはならないことを是非知っておいて欲しい.そこで,グラフを簡単に作ってみることにする.
パイプについて
GNUPlotはコマンドラインで操作するタイプのソフトウェアである.ということは,コマンドラインとは文字列であるから,コマンドライン上に文字列を出力すれば,コマンドライン上で動作するソフトウェアを起動できるのである.
ここで,メイン関数と関数の関係を考える.メイン関数から関数名を呼び出し,引数を介して関数に変数を送り,その値を関数内で処理し,returnを記述すれば,その値を結果として関数から取得することができる.
この関係が,コマンドラインと作成した実行ファイルの間にも成り立っている.これまでは,コマンドラインで,実行ファイル名を打ち込むことで作成した実行ファイルが動作するというものであった.
これに対し,実行ファイル名の後に,先の関数の引数と同様に引数を置けば,実行ファイルに数値や文字列を送り込むことが可能である.同様に,メイン関数内にpopenという関数を記述すれば,コマンドラインに文字列を送り込むことができるので,コマンドラインで起動できるソフトウェアを動亜させることが可能である.
このようなテクニックをパイプと呼んでいる.
1.GNUPlotを用意する.
以下のサイトから,自身のPCの環境(Win?,Mac?,Ver?)に合わせたものを探してダウンロードする.必ずしも最新を探す必要な無く,安定版,Stable,Bugfixedなどのキーワードで探せばよい.テスト版,α版,β版を選ぶ必要は無く,むしろ何らかの不具合があると思っておくべきである.
http://www.gnuplot.info/
ダウンロードしたらインストールして下さい.GNUPlotは特段操作をしなくても自動的にインストールできる.
Macの場合は幾分手続きが変わります.
A, ターミナルを開いておいて下さい.(コマンドラインを打ち込むためのものです.)
B. パッケージマネージャHomebrewなどをインストールする.
https://brew.sh/index_ja
無くてもよい場合もあるが,不具合が出にくいようである.指示通りでインストールできる.
C.GNUPlotを用意する.
以下のサイトから,自身のPCの環境(Win?,Mac?,Ver?)に合わせたものを探してダウンロードする.
http://www.gnuplot.info/
D. パッケージマネージャ越しにインストールする.
ターミナルなどから,
brew install gnuplot
のようにタイプしてインストールする.パッケージマネージャがほどよく環境設定をしてくれるはずである.
以上で準備ができた.
C言語でGNUPlotを呼び出すプログラム開発
パイプを使うための設定,コマンドをはじめに説明する.
宣言 | |
#include <stdio.h> | /*標準入出力のためのヘッダ*/ |
Main関数内 | |
FILE *gp; | /*コマンドラインとアクセスするためのファイルポインタ*/ |
gp = popen("gnuplot", "w"); | /*パイプを用いてコマンドラインにGNUPlot起動のコマンドを送る.パイプによりコマンドラインとのやりとりの道が開いた状態にしている.*/ |
fprintf(gp, "plot '-' with linespoints\n"); | |
linespoints\n"); | /* GNUPlot起動後のコマンドを逐次記述する*/ |
pclose(gp); | /*パイプのためのポインタを閉じる*/ |
考慮すべきはほぼ上記のことのみである.fprintf関数にコマンドラインに書くべき文字列を配置する.もちろん変数の値を置くこともでき,以下のようにすれば,順次プロットすることが可能である.
fprintf(gp, "%f %f\n", 変数, 変数); |
練習課題
プログラムからGnuplotを呼び出して正弦波を描く
#include <math.h> #include <stdio.h> int main(void) { FILE *gp; int i; double t, dt; /*Gnuplotを起動*/ gp = popen("gnuplot", "w"); fprintf(gp, "plot '-' with linespoints\n"); /*座標の名前を入力*/ fprintf(gp, "set xlabel \"t\"\n"); fprintf(gp, "set ylabel \"sin\"\n"); pi = 4.0 * atan(1.0); n = 100; dt = 2 * pi / (double)n; for (i = 0; i <= n; i++) { t = i * dt; /*Gnuplotのコマンドを実行*/ fprintf(gp, "%f %f\n", x, sin(x)); } /*行頭'e'でGNUPlotはコマンドラインからの読み込みを終了*/ fprintf(gp, "e\n"); /*コマンドラインに上記文字列を書き出し切る*/ fflush(gp); /*Enterを入力まで待つ*/ fgets(buf, sizeof(buf), stdin); pclose(gp); return 0; } |
特段難しいことはやっていないので,ひとまず試そう.
同じ要領で,課題を取り組めばグラフを作成することができる.
なお,各軸の範囲の指定をすることも可能である.省略可であるが,グラフの形式が気になるのであれば試してもよい.GNUPlotは横軸がX軸,縦軸がY軸と決まっている.
fprintf(gp, "set xrange [0:10]\n");
fprintf(gp, "set yrange [0:1]\n");
[0:1]内を適宜調整してみて欲しい.もちろん負の値も設定できる.