#pragma once
/*! @file
@brief gnuplotクラス
@author hecomi
@date July 12, 2010. ver. 1.02
10/07/05 完成
10/07/12 ログプロット/reset/PNG出力追加
10/07/13 マルチプロット
*/
#include <vector>
#include <fstream>
#include <string>
/*! @brief gnuplotを扱うライブラリ
gnuplotを扱うクラスに関するライブラリです.
pgnuplotへとパイプを繋ぎ,関数やデータをgnuplotを用いてプロットする手助けをします.
pgnuplot.exeが環境変数へと登録されている必要があります.
*/
class CGnuplot {
private:
//! プロットする要素の開始位置と終了位置
FILE* Fp;
//! 初期スタイルセットファイル名
static const char* InitialStyleFileName;
//! ファイル書き出し時スタイルセットファイル名
static const char* OutputStyleFileName;
/*! @brief 一時ファイル名 */
const std::string TempFileName;
//! プロットする要素の開始位置と終了位置
template <class Container>
struct PlotInfo
{
Container begin; //!< プロット開始位置
Container end; //!< プロット終了位置
};
/*!
@brief プロットタイプ
PLOT_TYPE_LINES 線のみ
PLOT_TYPE_POINTS 点のみ
PLOT_TYPE_LINES_POINTS 線と点
*/
enum PLOT_TYPE {
PLOT_TYPE_LINES,
PLOT_TYPE_POINTS,
PLOT_TYPE_LINES_POINTS
} PlotType;
//! マルチプロットかどうか
bool IfMultiplot;
//! プロットファイル用ナンバー初期値
static const unsigned int DefaultNo;
//! プロットファイル用ナンバー(Temp(No).dat)
unsigned int No;
//! プロットファイル用ナンバーの最大値
unsigned int MaxNo;
//! ファイル名取得
std::string GetPlotFileName();
/*!
@brief 初期化
*/
void Ini();
/*!
@brief バッファフラッシュ
*/
void Flush();
/*!
@brief プロットコマンド
*/
void Plot();
/*!
@brief 1次元要素をプロットする
@param[in] x プロット情報を格納したxデータ
*/
template <class T>
void PlotX(PlotInfo<T> x)
{
T it = x.begin;
std::ofstream fout(GetPlotFileName().c_str());
if (fout.fail()) {
std::cout << "Error! (@PlotX)" << std::endl;
return;
}
while (it != x.end) {
fout << *it << std::endl;
it++;
}
Plot();
}
/*!
@brief 2次元要素をプロットする
@param[in] x プロット情報を格納したxデータ
@param[in] y プロット情報を格納したyデータ
*/
template <class T>
void PlotXY(PlotInfo<T> x, PlotInfo<T> y)
{
T itX = x.begin, itY = y.begin;
std::ofstream fout(GetPlotFileName().c_str());
if (fout.fail()) {
std::cout << "Error! (@PlotXY)" << std::endl;
return;
}
while (itX != x.end && itY != y.end) {
fout << *itX << " " << *itY << std::endl;
itX++; itY++;
}
Plot();
}
/*!
@brief 3次元要素をプロットする
@param[in] x プロット情報を格納したxデータ
@param[in] y プロット情報を格納したyデータ
@param[in] z プロット情報を格納したzデータ
*/
template <class T>
void PlotXYZ(PlotInfo<T> x, PlotInfo<T> y, PlotInfo<T> z)
{
T itX = x.begin, itY = y.begin, itZ = z.begin;
std::ofstream fout(GetPlotFileName().c_str());
if (fout.fail()) {
std::cout << "Error! (@PlotXYZ)" << std::endl;
return;
}
while (itX != x.end && itY != y.end && itZ != z.end) {
fout << *itX << " " << *itY << " " << *itZ << std::endl;
itX++; itY++; itZ++;
}
Plot();
}
/*!
@brief プロットタイプに応じた文字列を取得
*/
std::string GetPlotType();
public:
/*! @brief コンストラクタ */
CGnuplot();
/*!
@brief コンストラクタ
複数のGnuplotを起動した際に,同名のプロットデータファイルが衝突すると,
所望のプロット結果が得られないので,プロットデータファイル名を指定しなければならない.
@param[in] fileName プロット時に生成するデータファイルの名前
*/
CGnuplot(const char* fileName);
/*! @brief デストラクタ */
~CGnuplot();
/*! @brief 正常に機能しているかどうか */
bool Check();
/*!
@brief printfライクにgnuplotのコマンドを実行
@param[in] format printfに用いるフォーマット
@param[in] ... 可変長引数
*/
void Command(const char* format, ...);
/*!
@brief 関数をプロット
Ex. DrawFunc("sin (x)")
@param[in] format プロット対称関数文字列
*/
void DrawFunc(const char* func);
/*!
@brief 1次元要素をプロットする
@param[in] cont プロット対称コンテナ
*/
template <class T, template <class A, class Allocator = std::allocator<A> > class Container>
void Plot(Container<T> cont)
{
PlotInfo<Container<T>::iterator> pi = { cont.begin(), cont.end() };
PlotX(pi);
}
/*!
@brief 1次元要素をプロットする(配列)
@param[in] cont プロット対称配列
*/
template <class T, int N>
void Plot(T (&cont)[N])
{
PlotInfo<T*> pi = { &cont[0], &cont[N-1] };
PlotX(pi);
}
/*!
@brief 2次元要素をプロットする
@param[in] contX プロット対称コンテナ(x)
@param[in] contY プロット対称コンテナ(y)
*/
template <class T, template <class A, class Allocator = std::allocator<A> > class Container>
void Plot(Container<T> contX, Container<T> contY)
{
PlotInfo<Container<T>::iterator>
piX = { contX.begin(), contX.end() },
piY = { contY.begin(), contY.end() };
PlotXY(piX, piY);
}
/*!
@brief 2次元要素をプロットする(配列)
@param[in] contX プロット対称配列(x)
@param[in] contY プロット対称配列(y)
*/
template <class T, int N, int M>
void Plot(T (&contX)[N], T (&contY)[M])
{
PlotInfo<T*>
piX = { &contX[0], &contX[N] },
piY = { &contY[0], &contY[M] };
PlotXY(piX, piY);
}
/*!
@brief 3次元要素をプロットする
@param[in] contX プロット対称コンテナ(x)
@param[in] contY プロット対称コンテナ(y)
@param[in] contZ プロット対称コンテナ(z)
*/
template <class T, template <class A, class Allocator = std::allocator<A> > class Container>
void Plot(Container<T> contX, Container<T> contY, Container<T> contZ)
{
PlotInfo<Container<T>::iterator>
piX = { contX.begin(), contX.end() },
piY = { contY.begin(), contY.end() },
piZ = { contZ.begin(), contZ.end() };
PlotXYZ(piX, piY, piZ);
}
/*!
@brief 3次元要素をプロットする(配列)
@param[in] contX プロット対称配列(x)
@param[in] contY プロット対称配列(y)
@param[in] contZ プロット対称配列(z)
*/
template <class T, int N, int M, int L>
void Plot(T (&contX)[N], T (&contY)[M], T (&contZ)[L])
{
PlotInfo<T*>
piX = { &contX[0], &contX[N] },
piY = { &contY[0], &contY[M] },
piZ = { &contZ[0], &contZ[L] };
PlotXYZ(piX, piY, piZ);
}
/*!
@brief 2次元マルチプロット(STLコンテナ限定)
@param[in] contX プロット対称配列(x)
@param[in] contY プロット対称配列(y)
@param[in] contZ プロット対称配列(z)
*/
template <class T, template <class A, class Allocator = std::allocator<A> > class Container>
void Multiplot(Container<T> x, Container<std::pair<std::string, Container<T> > > ys)
{
// 念のため
No = DefaultNo;
// プロット開始
Command("plot \\");
// ファイルへ書き出し
std::ofstream fout(GetPlotFileName().c_str());
if (fout.fail()) {
std::cout << "Error! (@Multiplot)" << std::endl;
return;
}
// 第2引数の展開
Container<std::pair<std::string, Container<T> > >::iterator itYs = ys.begin();
unsigned int i = 1;
while (itYs != ys.end()) {
// ペアの展開
std::pair<std::string, Container<T> > pair = *itYs;
std::string title = pair.first;
Container<T> y = pair.second;
// イテレータ指定
Container<T>::iterator itX = x.begin(), itY = y.begin();
while (itX != x.end() && itY != y.end()) {
fout << *itX << " " << *itY << std::endl;
itX++; itY++;
}
fout << std::endl << std::endl;
// プロット
Command("'%s' ind %d w %s ls %d ti '%s'\\", GetPlotFileName().c_str(), i-1, GetPlotType().c_str(), i, title.c_str());
if (i < ys.size()) {
Command(",\\");
} else {
Command("");
break;
}
itYs++;
i++;
}
}
/*!
@brief プロットタイプ(線,点,線と点)をセット
*/
void SetPlotType(PLOT_TYPE plotType);
/*!
@brief マルチプロット(複数の図をプロット)の切り替え
@param[in] sw true: マルチプロット false: 解除
*/
void SetMultiplot(bool sw = true);
/*!
@brief ラベルをセット
@param[in] title タイトル
*/
void SetTitle(const char* title);
/*!
@brief ラベルをセット
@param[in] labelX Xラベル名
@param[in] labelY Yラベル名
*/
void SetLabel(const char* labelX, const char* labelY);
/*!
@brief プロット範囲を指定
@param[in] min x軸プロット範囲最小値
@param[in] min y軸プロット範囲最小値
*/
void SetXRange(const double min, const double max);
/*!
@brief プロット範囲を指定
@param[in] min y軸プロット範囲最小値
@param[in] min y軸プロット範囲最小値
*/
void SetYRange(const double min, const double max);
/*!
@brief リプロット
*/
void Replot();
/*!
@brief 設定全リセット
*/
void Reset();
/*!
@brief 片対数プロットに変更
*/
void SetLogPlotY(bool sw = true);
/*!
@brief 現在プロットしているデータをファイルに書き出す
中身はTempFileNameに保存されているデータをコピーしているだけ
@param[in] fileName 書き出し先ファイル名
*/
void DumpToFile(const char* fileName);
/*!
@brief 現在プロットしているデータをEPSで書き出す
@param[in] fileName 書き出し先ファイル名
*/
void DumpToEps(const char* fileName);
/*!
@brief 現在プロットしているデータをPNGで書き出す
@param[in] fileName 書き出し先ファイル名
*/
void DumpToPng(const char* fileName);
/*!
@brief 外部ファイルからコマンドを読み込み実行
@param[in] fileName 読み込み元ファイル名
*/
void CommandFromFile(const char* fileName);
};