目次
- 目次
- はじめに
- C++からmatplotlibのグラフ描画機能を使うヘッダライブラリ: matplotlib-cpp
- コンパイル方法
- matplotlib-cppの使い方
- 最後に
- 参考資料
- MyEnigma Supporters
はじめに
C++で複雑なアルゴリズムのコードを書いていると、
MATLABやpythonのmatplotlibのように
お手軽にグラフ作成をしたくなります。
これまでは、いちいちC++からcsvファイルを生成し、
そのファイルをpythonで読み込んで、
matplotlibでグラフを生成していましたが
非常に面倒でした。
そこで、どうにかしてC++コードから
matplotlibを呼べないか色々調べていた所、
非常に良い方法を見つけたので紹介したいと思います。
C++からmatplotlibのグラフ描画機能を使うヘッダライブラリ: matplotlib-cpp
下記のmatplotlib-cppというヘッダライブラリを使うと、
簡単にc++コードからmatplotlibのグラフ描画機能を利用することができます。
ヘッダライブラリなので、
インクルードし、コンパイル時にpython2.7にリンクを通すだけで使用できます。
上記のmatplot-cppをより使いやすくするために、
下記のパッケージを作成し、公開しました。
上記のリポジトリをクローンし、
$ git clone https://github.com/AtsushiSakai/matplotlib-cpp-starter.git
下記のスクリプトを起動すると、
ソフトがコンパイルされ、実行されます。
$ ./build_and_run.sh
すると、下記のようなグラフが表示されるはずです。
コンパイル方法
下記のようにPythonをリンクすればコンパイルできます。
Makefile
g++ main.cpp -lstdc++ -lpython2.7 -std=c++11
CMake
find_package(PythonLibs REQUIRED) include_directories(${PYTHON_INCLUDE_DIRS}) target_link_libraries(hoge ${PYTHON_LIBRARIES})
matplotlib-cppの使い方
matplotlib-cppの使い方をサンプルコードと共に
説明したいと思います。
標準的なPlot関数の使い方
下記のようにmatplotlibcpp.hをインクルードし、
namespaceを読み込むと、
matplotlibと同じように使うことができます。
#include<iostream> #include"matplotlibcpp.h" using namespace std; namespace plt = matplotlibcpp; int main(){ cout<<"matplotlib-cpp sample start"<<endl; int n = 5000; vector<double> x(n), y(n); for(int i=0; i<n; ++i) { x.at(i) = i; y.at(i) = sin(2*M_PI*i/360.0); } plt::plot(x, y, "--r"); plt::show(); return 0; }
すると、下記のようなグラフが表示されます。
ちなみに、入力のデータ列はvectorでなくても、
下記のようにlistなどのSTLのコンテナであればOKです。
int n = 5000; list<double> x(n), y(n); for(int i=0; i<n; ++i) { x.push_back(i); y.push_back(sin(2*M_PI*i/360.0)); } plt::plot(x, y, "--r"); plt::show();
またグラフの色や線種などは、
matplotlibと同じフォーマットで指定できます。
複数のプロットをする
plot関数を複数回呼んで、
show関数を呼べば、
matplotlibと同じように複数のプロットを一つのグラフに表示できます。
int n = 5000; list<double> x(n), y(n), z(n); for(int i=0; i<n; ++i) { x.push_back(i); y.push_back(sin(2*M_PI*i/360.0)); z.push_back(cos(2*M_PI*i/360.0)); } plt::plot(x, y, "--r"); plt::plot(x, z, ".-b"); plt::show();
グラフの凡例の表示
下記のようにnamed_plot関数を呼ぶ時に名前を指定すれば、
グラフに凡例を表示させることも簡単です。
plt::named_plot("log(x)", x, y);
plt::legend();
グラフの表示範囲を設定する
下記のように,xlimとylim関数を使えば、
グラフの表示範囲も簡単に設定することができます。
plt::plot(x, y, "--r"); plt::xlim(0, 1000);//一つ目と二つ目の引数の型は一致している必要があります。 plt::ylim(0.0, 0.5); plt::show();
一つ注意点として、xlimとylimの一つ目の引数と、二つ目の引数は
数値の型が同じである必要があります。(int, int) or (float, float)
片方がintで、もう片方がfloatだとコンパイル時に型のエラーが発生するので注意です。
軸のタイトルやグラフの名前を設定する
下記のようにxlabelやylabal, title関数を使うと、
グラフの名前や軸のタイトルを表示できます。
またgrid関数にtrueを渡すと、破線を表示できます。
plt::title("log"); plt::xlabel("x"); plt::ylabel("y"); plt::grid(true);
グラフを保存する
下記のようにplt::show()に代わりに
save関数を呼ぶことで、グラフを画像データとして保存できます。
(自分の環境では、plt::show()を呼ぶとなぜかグラフが表示されませんでした。)
plt::plot(x, y, "--r"); plt::save("./basic.png");
アニメーションを表示する方法
下記のように、matplotと同様に
plt::pause関数を使う所で、
cppのコードで
簡単にアニメーションを表示させることもできます。
vector<double> x(1), y(1); for(int i=0; i<n; ++i) { x[0]=i; y[0]=sin(2*M_PI*i/360.0); plt::plot(x, y, "xr"); plt::pause(0.1);//0.1秒間隔でSinカーブ点を描画 }
上記のコードを実行すると
下記のようにsinカーブの線が
どんどん伸びていくアニメーションが表示されます。
最後に
非常に便利ですね。
まだすべてのmatplotlibの機能が使えるわけではないので、
機能追加してプルリクエストを出してみたいと思います。
参考資料
MyEnigma Supporters
もしこの記事が参考になり、
ブログをサポートしたいと思われた方は、
こちらからよろしくお願いします。