MyEnigma

とある自律移動システムエンジニアのブログです。#Robotics #Programing #C++ #Python #MATLAB #Vim #Mathematics #Book #Movie #Traveling #Mac #iPhone

C++のコードから簡単にmatplotlibを使ってグラフを作成する方法

 

目次

 

はじめに

C++で複雑なアルゴリズムのコードを書いていると、

MATLABやpythonのmatplotlibのように

お手軽にグラフ作成をしたくなります。

myenigma.hatenablog.com

myenigma.hatenablog.com

 

これまでは、いちいちC++からcsvファイルを生成し、

そのファイルをpythonで読み込んで、

matplotlibでグラフを生成していましたが

非常に面倒でした。

 

そこで、どうにかしてC++コードから

matplotlibを呼べないか色々調べていた所、

非常に良い方法を見つけたので紹介したいと思います。

  

C++からmatplotlibのグラフ描画機能を使うヘッダライブラリ: matplotlib-cpp

下記のmatplotlib-cppというヘッダライブラリを使うと、

簡単にc++コードからmatplotlibのグラフ描画機能を利用することができます。

github.com

 

ヘッダライブラリなので、

インクルードし、コンパイル時にpython2.7にリンクを通すだけで使用できます。

 

上記のmatplot-cppをより使いやすくするために、

下記のパッケージを作成し、公開しました。

github.com

上記のリポジトリをクローンし、

$ git clone https://github.com/AtsushiSakai/matplotlib-cpp-starter.git

下記のスクリプトを起動すると、

ソフトがコンパイルされ、実行されます。

$ ./build_and_run.sh

すると、下記のようなグラフが表示されるはずです。

f:id:meison_amsl:20160116081515p:plain

 

コンパイル方法

下記のように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;
}

すると、下記のようなグラフが表示されます。

f:id:meison_amsl:20160116083606p:plain

 

ちなみに、入力のデータ列は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();

f:id:meison_amsl:20160116092738p:plain

 

グラフの凡例の表示

下記のようにnamed_plot関数を呼ぶ時に名前を指定すれば、

グラフに凡例を表示させることも簡単です。

plt::named_plot("log(x)", x, y);
plt::legend(); 

f:id:meison_amsl:20160116085157p:plain

 

グラフの表示範囲を設定する

下記のように,xlimとylim関数を使えば、

グラフの表示範囲も簡単に設定することができます。

plt::plot(x, y, "--r");
plt::xlim(0, 1000);//一つ目と二つ目の引数の型は一致している必要があります。
plt::ylim(0.0, 0.5);  
plt::show();

f:id:meison_amsl:20160116090543p:plain

 

一つ注意点として、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); 

f:id:meison_amsl:20160116221537p:plain

 

グラフを保存する

下記のように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カーブの線が

どんどん伸びていくアニメーションが表示されます。

f:id:meison_amsl:20160116222545p:plain

 

最後に

非常に便利ですね。

まだすべてのmatplotlibの機能が使えるわけではないので、

機能追加してプルリクエストを出してみたいと思います。

 

参考資料

myenigma.hatenablog.com

myenigma.hatenablog.com

myenigma.hatenablog.com

 

MyEnigma Supporters

もしこの記事が参考になり、

ブログをサポートしたいと思われた方は、

こちらからよろしくお願いします。

myenigma.hatenablog.com