2017年9月23日

C++ から Python (Matplotlib) でグラフを描く

Abstract
  C++ から Python の Matplotlib でグラフを生成する場合,lava/matplotlib-cpp 等の Python/C API を利用した手法が知られている.しかしながら,様々な制約のため Python/C API を利用できない場合がある.このような場合,C++ で生成したデータを CSV 等のファイルへ一旦書き出した後,再度 Python でデータを取り込むことで描画できるが,これも,大きな労力を伴う.そこで,本投稿では,system 関数により,Python をコマンドラインからの呼び出しとして実行し,この際に描画データを引数として受け渡すことで,労力の軽減を図る.

※ 現在では C++ から任意の Python 関数を実行する の方が,簡単です. - 2018.0316 追記
Introduction
  C++ からグラフを描画する場合,Gnuplot や Python の matplotlib がよく用いられる.汎用言語である Python を用いる場合,C++ から一度ファイルに出力したデータを,再度 Python から読み込んで描画する方法が考えられる.しかしながら,一度ファイルに出力するといった方法は,ファイルの出力先や,不要となったファイルの削除タイミングを考える必要があり,手間がかかる.そこで,Python の実行ファイルに,データをコマンドライン引数として与えることを考える.コマンドライン引数は,例えば,Windowds7 では,32699 文字未満 [1] に制限されており,受け渡せるデータ量に制限はあるものの,浮動小数点数で 3400 個程度の配列を受け渡せるだけのデータ量である.
  例えば,次のように,コマンドラインから Python コードへ,入力引数を文字列として受け渡すことができる.
例:
./main.py
import sys

def main():
    args = sys.argv
    print("own name: %s" % args[0])    
    print("%s" % args[1])
    print("%d" % int(args[2]))

main()

実行結果
$ python main.py 123 456
own name: main.py
123
456

  今回は,この手法を用いて,C++ からグラフを生成する.
Method
  描画する配列データを受け渡すにあたり,データフォーマットを考える必要がある.難しいデータフォーマットを考える必要はなく,今回は,配列長 (vec.size()) を渡したのち,個数分の配列データ (vec[0] vec[1] ... vec[vec.size()-1]) を受け渡した.

例 (疑似コマンド):
$ python ./main.py vec.size() vec[0] vec[1] ... vec[vec.size()-1]
Implementation
  今回使用したコード全体は,GitHub: c2py へ置いておく.

./main.cpp ./plot.py
Results
  上記コードを実行し,下記のグラフを得た.(002.png のみ示す.)
References



Appendix
  C++ 側,および,Python 側での文字列処理コードを添付しておく.

./c2py.cpp ./c2py.py

0 件のコメント:

コメントを投稿