PGPLOT のつかいかた[draft](Windows+MSVC++6.0)


機械学習やシミュレーションを行うとき、実験結果の表示にはグラフの形で描画が望ましいです
しかし、グラフ描画にかける手間は極力避けたいものです

グラフを描画するプログラムには、gnuplot がよく使われます
コマンドラインインタフェースなので、プログラムから呼出ししづらい点と、
コマンド自体が個人的に気に入らないので、別の選択肢を探します

グラフ描画プログラムはそれこそたくさんあります。PLplot、Grace、etc...
今回はなんとなく PGPLOTを使ってみることにします
古いソフトウェアで、もとは FORTRAN で書かれたものなので、導入は少し面倒です

--

PGPLOT のウェブページによると、Windows 環境では GrWin 上で動かすことを
勧めているので、まず GrWin の導入からはじめます。
GrWin のウェブページから適当なファイルをダウンロードして実行するだけです。
インストーラパッケージの形で配布されているので、
基本的にはキーボードに触ることなくインストールは完了します。
インストール時には、PLPLOT ドライバをインストールするように設定します。

GrWin のウェブページ上に情報が乏しいですが、この時点で PGPLOT 用のライブラリや
ヘッダファイルのインストールが完了しています。
例えば、ライブラリファイルは VC++6.0 なら、
"???:\Program Files\Microsoft Visual Studio\VC98\Lib"
にコピーされています。

--

C/C++ のプログラムから PGPLOT のサブルーチンを使用するには、
ライブラリファイルを明示的にリンクする必要があります。
リンクすべきライブラリファイルは、
cpgplot.lib pgplot.lib f2c.lib GrWin.lib
の 4つです。

PGPLOT サブルーチンの宣言は、
cpgplot.h
にありますので、これをプログラムのはじめに include しておきます。

--

PGPLOT サブルーチンの詳細は、以下のページに解説されています。
"PGPLOT Subroutine Description"
日本語翻訳版
FORTRAN と C の両方の形が併記されています。
関数名の関係ですが、C ライブラリの関数名は、"PGOPEN" -> "cpgopen" のように、
FORTRAN 関数名を小文字にして、サフィックス "c" を付けたものになっています。

変数の型には、整数が int、浮動小数点は float のみが使われます。

2 次元行列は、それをエミュレートするような 1 次元行列として定義します。
例えば、2x3 の 2 次元行列 A
    1.0  2.0 4.0
A = 0.0 -1.0 1.0
は、
float A[6] = {1.0f, 2.0f, 4.0f, 0.0f, -1.0f, 1.0f};
のように定義されます。

--

サンプル1("PGPLOT Appendix C" より改変):

#include "cpgplot.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(void){
 int i;
 static float xs[] = {1.0, 2.0, 3.0, 4.0, 5.0 };
 static float ys[] = {1.0, 4.0, 9.0, 16.0, 25.0 };
 float xr[60], yr[60];
 int n = sizeof(xr) / sizeof(xr[0]);

 // (各点座標の計算)
 for(i=0; i<n; i++) {
  xr[i] = 0.1f*i;
  yr[i] = xr[i]*xr[i];
 }

 // PGPLOT の開始
 if(cpgopen("/gw") <= 0) return -1;
 // 環境の設定
 cpgenv(0.0, 10.0, // XMIN, XMAX; x軸範囲
  0.0, 20.0, // YMIN, YMAX; y軸範囲
  0, // JUST; x軸とy軸のスケールを一致させる
  1  // AXIS; 軸、ラベル、目盛の描画設定
  );
 // ラベルの設定
 cpglab("(x)", "(y)", "PGPLOT Example 1: y = x\\u2\\d");
 // 色の変更
 cpgsci(8);
 // マーカの描画
 cpgpt(5, // N; ポイント数
  xs, ys, // マーカ座標
  9 // SYMBOL; 使用するシンボル (fig. B.0 参照)
  );
 // 色の変更
 cpgsci(10);
 // 直線の描画
 cpgline(n, xr, yr);
 // PGPLOT の終了
 cpgend();
 return 0;
}

実行結果:

--

サンプル2(2次元の点のプロットとヒストグラム):

#include "cpgplot.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

// 一様乱数
double random_double(double low, double high){
 return low + (high-low)*(rand()/(double)RAND_MAX);
}
// 正規乱数
double random_reg(double sigma, double avg){
 return sqrt(-2.0*log(random_double(0.01, 1.0))) * sin(2.0*3.141592*random_double(0.0, 1.0)) * sigma + avg;
}
float get_min(float* p, int n){
 float ret = 99999.9f;
 while(n--) if(p[n] < ret) ret = p[n];
 return ret;
}
float get_max(float* p, int n){
 float ret = -99999.9f;
 while(n--) if(p[n] > ret) ret = p[n];
 return ret;
}

#define POINTS 1024
int main(void){
 int i;
 float xr[POINTS], yr[POINTS];
 float xmin, xmax;

 int n = sizeof(xr) / sizeof(xr[0]);

 // (各点座標の計算)
 for(i=0; i<n; i++) {
  xr[i] = (float)random_reg(1.0, 0.0);
  yr[i] = (float)random_reg(1.0, 0.0);
 }
 xmin = get_min(xr, n);
 xmax = get_max(xr, n);

 // PGPLOT の開始
 if(cpgopen("/gw") <= 0) return -1;
 // 環境の設定
 cpgenv(xmin, xmax, // XMIN, XMAX; x軸範囲
  xmin, xmax, // YMIN, YMAX; y軸範囲
  0, // JUST; x軸とy軸のスケールを一致させる
  1  // AXIS; 軸、ラベル、目盛の描画設定
  );
 // ラベルの設定
 cpglab("(x)", "(y)", "PGPLOT Example: Plot");
 // 色の変更
 cpgsci(8);
 // マーカの描画
 cpgpt(n, // N; ポイント数
  xr, yr, // マーカ座標
  2 // SYMBOL; 使用するシンボル (fig. B.0 参照)
  );

 // 色の変更
 cpgsci(1);
 // ヒストグラムの描画
 cpghist(n, // N; ポイント数
  xr, // データ
  xmin, xmax,
  20, // NBIN
  0 // PGFLAG
  );
 // ラベルの設定
 cpglab("(x)", "(y)", "PGPLOT Example: Histgram");

 // PGPLOT の終了
 cpgend();
 return 0;
}

実行結果: