はじめに
(※windows向けのエントリです)
これまで,C++でgnuplotを使う,ということで幾つかエントリを経てgnuplotを便利に使えるクラスを作成してきました.
ただ,ヘッダファイル・ソースファイルを取って来てほげほげ…とやって,更に何のメンバがあるんだろう…ってふがふがやっていると,使う気も失せてくると思います.検索して来られる方が一番多い内容でしたので,簡単に使って頂けるようにまとめてみました.
利用に際して
windows版gnuplotに同梱されているpgnuplot.exeが必要です.ここにパイプを通して動作させる仕組みになっています.以下のURLから適当なバージョンのものをDL・展開して,適当な場所に配置した後,環境変数を通してください.
Source Forge: http://sourceforge.net/projects/gnuplot/files/
利用例
簡単な例として,sinを一周期だけ描いてみます.
#include <vector> #include <algorithm> #include <cmath> #include "gnuplot.h" int main() { using namespace std; using namespace gnuplot; vector<double> x, y; for (int i = 0; i < 628; x.push_back(i*0.01), i++); transform(x.begin(), x.end(), back_inserter(y), sin); CGnuplot gp; gp.SetLabel("x", "sin(x)"); gp.Plot(x, y); gp.DumpToPng("sin"); __KEYWAIT__; return 0; }
出力:
WEB上でも見れるようにpngで出力しましたが,DumpToEpsを使えばeps出力も可能です.DumpToFileで数値データとして吐き出すことも出来ます.vectorを使っていますが,配列でもプロットできるようになっています.
#include <cmath> #include "gnuplot.h" int main() { using namespace std; using namespace gnuplot; double x[100], y[100]; for (int i = 0; i<100; i++) { x[i] = 0.0628*i; y[i] = sin(x[i]); } CGnuplot gp; gp.SetLabel("x", "sin(x)"); gp.SetPlotType(CGnuplot::PLOT_TYPE_LINES_POINTS); gp.Plot(x, y); gp.DumpToPng("sin"); __KEYWAIT__; return 0; }
ただ,次に紹介するMultiplotは配列によるプロットをサポートしていません.後日更新します(多分).
x軸が揃った複数プロットは次のようになります.
#include <vector> #include <algorithm> #include <cmath> #include "gnuplot.h" int main() { using namespace std; using namespace gnuplot; vector<double> x, y1, y2; for (int i = 0; i < 628; x.push_back(i*0.01), i++); transform(x.begin(), x.end(), back_inserter(y1), sin); transform(x.begin(), x.end(), back_inserter(y2), cos); CGnuplot gp; gp.SetTitle("Trigonometric Functions"); gp.Command("set key left bottom"); gp.SetLabel("x", "y"); gp.SetXRange(0, 6.28); gp.SetYRange(-1, 1); SemiMultiPlot plotData; plotData.push_back(make_pair("sin(x)", y1)); plotData.push_back(make_pair("cos(x)", y2)); gp.Multiplot(x, plotData); gp.DumpToEps("trigonometric"); __KEYWAIT__; return 0; }
結果(EPS出力したものをPNGに変換しました):
SemiMultiPlotは vector
また,x軸のプロット用ベクトルが異なる状況もあるかもしれません.その際は次のようにします.
#include <vector> #include <algorithm> #include <cmath> #include "gnuplot.h" int main() { using namespace std; using namespace gnuplot; vector<double> x1, x2, y1, y2; for (int i = 0; i <= 628; x1.push_back(i*0.01), i++); for (int i = 0; i <= 10; x2.push_back(i*0.628), i++); transform(x1.begin(), x1.end(), back_inserter(y1), sin); transform(x2.begin(), x2.end(), back_inserter(y2), cos); CGnuplot gp; gp.SetTitle("Trigonometric Functions"); gp.Command("set key left bottom"); gp.SetLabel("x", "y"); gp.SetXRange(0, 6.28); gp.SetYRange(-1, 1); MultiPlot plotData; plotData.push_back(svv("sin(x)", x1, y1)); plotData.push_back(svv("cos(x)", x2, y2)); gp.Multiplot(plotData); gp.DumpToEps("trigonometric2"); __KEYWAIT__; return 0; }
MultiPlotはvector
三次元プロットを行いたい場合には次のように行います.これについては配列でも出来るので,配列を用いて書いておきます.もちろんvector等でも同様にプロットすることが可能です.
#include <cmath> #include "gnuplot.h" int main() { using namespace std; using namespace gnuplot; double x[1200], y[1200], z[1200]; for (int i = 0; i<1200; i++) { if (i < 1000) { double t = 0.1*i, s = 1 - 0.001*i; x[i] = s * cos(t); y[i] = s * sin(t); z[i] = t; } else { x[i] = 0; y[i] = 0; z[i] = 100-(i-1000); } } CGnuplot gp; gp.SetYRange(-2, 2); gp.SetXRange(-2, 2); gp.Plot(x, y, z); gp.DumpToFile("kinoko"); __KEYWAIT__; return 0; }
ただ,これでは3次元に点をプロットしているだけなので,面プロットも欲しいと思います.その場合は次のように書きます.
#include <vector> #include <cmath> #include "gnuplot.h" int main() { using namespace std; using namespace gnuplot; vector<double> x, y; vector<vector<double> > z; for (int i=0; i<100; x.push_back(i*0.1), y.push_back(i*0.1), i++); for (int i=0; i<100; i++) { vector<double> _z; for (int j=0; j<100; j++) { _z.push_back(sin(x[i])*cos(y[j])); } z.push_back(_z); } CGnuplot gp; gp.Plot(x, y, z); __KEYWAIT__; return 0; }
boost::multi_arrayを使っても同様にできます.#ifdef USE_BOOSTの中に書きこまれていますので,#define USE_BOOSTをgnuplot.hをインクルードする前に書きこんでください.コードはこちらのほうがシンプルになりますね.
#define USE_BOOST #include <vector> #include <cmath> #include "gnuplot.h" int main() { using namespace std; using namespace gnuplot; vector<double> x, y; boost::multi_array<double, 2> z(boost::extents[100][100]); for (int i=0; i<100; x.push_back(i*0.1), y.push_back(i*0.1), i++); for (int i=0; i<100; i++) { for (int j=0; j<100; j++) { z[i][j] = sin(x[i])*cos(y[j]); } } CGnuplot gp; gp.Plot(x, y, z); __KEYWAIT__; return 0; }
最後に
機能を追加次第,このエントリを更新していきたいと思います.バグ・要望等ございましたらコメントして頂けると嬉しいです.