matplotlibでのオブジェクト指向的な描画
matplotlibには主にpyplotの関数を用いてオブジェクトを明示的に操作せず簡単に描画する方法と、オブジェクトを明示的に操作する方法がある。以下後者の方法について。
matplotlibではグラフは一度FigureCanvasに描画され、それがバックエンドのmatplotlib.backend_bases.FigureCanvasBaseを継承した出力フォーマット依存のクラスによって出力されるという仕組みをとっている(はず、要出典)。
FigureCanvasに描画されるFigureは部品ごとに管理されており、すべての部品はmatplotlib.artist.Artistという抽象基底クラスを継承している。Figure自身もArtistの派生クラス。部品というのは例えば、軸(Axisというクラスで管理される)や目盛り、グリッド線(Tickというクラスに管理される)などのことを指す。また、これらはこちらもまたArtistの派生クラスであるmatplotlin.axes.Axesによってまとめられ、管理されている。
オブジェクト指向でのプロットは以下のようになる(例として2つの行列から2つのカラーマップを描く場合を取り上げる)。
import matplotlib.pyplot as pet import matplotlib.cm as cm #データを用意する arr1 = [[1,0,0],[0,1,0],[0,0,1]] arr2 = [[0,0,1],[0,1,0],[1,0,0]] data = [arr1,arr2] #Figure全体を管理するオブジェクトfigを生成する fig = plt.figure() #Figureの構成要素である2つの図それぞれを管理するAxesオブジェクトax1とax2を生成する ax1 = fig.add_subplot(1,2,1)#1行2列のグラフの1つめを描く ax2 = fig.add_subplot(1,2,2)#1行2列のグラフの2つめを描く ax1.imshow(data[0], cmap = cm.Greys, interpolation = 'nearest')#オブジェクトにカラーマップの情報をもたせるAxesのimshowメソッドを呼び出す ax1.set_axis_off()#軸を表示しない設定にするset_axis_off()メソッドを呼び出す ax2.imshow(data[1], cmap = cm.Greys_r, interpolation = 'nearest') ax2.set_axis_off() #描画する plt.show()
上記コードのうちcm.binaryは色を指定している。指定できる色は(http://matplotlib.org/examples/color/colormaps_reference.html)にある。”Greys_r”の”_r”は、グラデーションを反転させている。ここにない色も指定できたりする(例えば”binary”)。また、interpolationの’nearest’は描画をタイル状にしており、無指定だとグラフはグラデーションになる。
図の詳細な設定をいじる場合は図を管理しているAxesオブジェクトのメソッドを使う、というような事になる。Axes.get_xaxisなどのメソッドを使ってX軸の情報のみを管理するXAxisオブジェクトを生成し、更に細かく設定を行うことも(多分)できる。このようなAxesクラスのメソッドは(http://matplotlib.org/api/axes_api.html#axis-limits)に書いてある。
matplotlib version2.0.0をインストールした作業記録[Ubuntu 16.04]
Ubuntu 16.04に何も考えずaptでmatplotlibを入れたらversionが1.5.1だった。バージョンの確認は
$ python >>> import matplotlib >>> matplotlib.__version__
でできる。
最新版は2.0.0なのでこちらに更新したい。また、今まではpythonで使っていたが折角なのでpython3で使いたい。以下作業ログ。
$ apt search python3-matplotlib
の結果aptで入れられるのは1.5.1までらしい。apt-get updateしても変わらなかった。
少し調べてみるとどうもpythonのパッケージ管理システムpipで入れることができるらしい。そういうわけで、まずはpipを入れる(aptとpipが後々衝突したりしないかとても不安だけれど取り敢えず気にせず入れてみる)。
$ apt search python3-matplotlib
の結果python3-pipがヒットしたのでインストールする。
$ sudo apt-get install python3-pip
pipが入ったので以下でmatplotlibを探そうとしたらpipがまだ入っていないと怒られた。
$ pip search matplotlib
pipという名前では入っていないようなので名前を特定する。/usr/bin内を探したところ、pipというファイルはなかったが代わりにpip3というファイルがあった。おそらくこれだと思われるのでpip3で呼べば良い。
さてmatplotlibのインストールといきたいところだが、念の為以前入れていたmatplotlibを削除しておく必要がある。
$ sudo apt-get purge python-matplotlib
で以前のmatplotlibを削除した。purgeだと設定ファイルごと削除してくれるらしい。
pip3でmatplotlibを検索する。
$ pip3 search matplotlib
matplotlib (2.0.0)がヒットしてくれたのでこれをインストールする。
$ pip3 install matplotlib
ちゃんとpython3のmatplotlib(2.0.0)が入っているかどうか確認する。
$ python3 >>> import matplotlib as mpl >>> mpl.__version__
と打ったら
'2.0.0'
と帰ってきたので無事完了したか?と思ったのだけど、その後
$ python3 (実行ファイル名).py
ImportError: No module named '_tkinter', please install the python3-tk package
と怒られてしまった。python3-tkパッケージがないということなのでpip3でsearchをかけたがそれらしきものがない。
$ apt search python3-tk
としたらヒットしたのでaptで入れることにする。
$ sudo apt-get install python3-tk
こうしたら実行ファイルもちゃんと動くようになった。めでたしめでたし。
C++のconst指定子とポインタのややこしい話
C++でよく変更する予定のない変数の型の前にconstを付けるが、あれは唯の目印のようなものではなく、const ホニャララという新しい型を宣言している感覚に近いっぽい。
このconstの仕様はC言語時代からの負の遺産で大分ややこしいものになっているため、ここに少し整理しておくことにする。
double型を例にとって整理しよう。
double x;//一般的なdouble型の宣言 double* x;//double型のポインタの宣言 const double x;//double型で、xの値を変更することはできない const double* x;//値を変更することのできないdouble型(const double)へのポインタ double const* x;//実はこれは上と同じものを指す。この辺からややこしい。 double* const x;//xはdouble型のポインタで、ポインタの指す先をかえることはできない。ポインタが指しているdouble型の変数に別の値を代入することはできる。 const double* const x;//変更不能なポインタが指しているのはconst double型なので、こちらに別の値を代入することもできない。 double const* const x;//上と同じ const double* const* const* x;//const double型へのポインタも変更不能で、そのポインタへのポインタも変更不能だが、このポインタへのポインタにはconst指定子がついていないので変更できる。 deouble const* const* const* x;//上と同じ
おわかり頂けただろうか?
他に、f(const double x)のような関数にdouble型の変数を代入しても問題ないが、f(double x)のような関数にconst double型の変数を代入するとコンパイルエラーになる。
また、この話には直接関係がないが、関数ポインタへのアドレス参照演算子は無視される、intなどの型とintなどのリストは内部では違う型として扱われているので、int型のポインタのポインタにint型のリストのアドレスを代入しようとしてもエラーを吐くなどの話を今日しったのでメモしておく。
(C++)大きさ不明の2次元配列データを2次元vectorに読み込む方法
3/22 17:10
大きさの分からない2次元配列データを2次元vectorに格納する方法がいくら調べても見つからなかったので、分からないなりに調べつつコードを作成してみた。
下記のコードであれば、データが数値のcsvファイルならなんでも読み込めるはず。
2017/10/20
久しぶりにコードを見返したところ、いくつか気になった点があったので修正。
修正点
任意の数値型のvectorに対してGetdata関数が適用できるようにした。
using namespace std;を削除した。
2018/2/25
コードを見返したところ、いくつか気になった点が出てきたので修正。
修正点
引数で指定したファイルが見つからない場合に例外を返却するよう修正。
引数で受け取ったvectorに副作用でデータを格納するのではなく、関数の返り値として読み込みデータを返却するように変更。
第2引数で空読みしたい行数を指定できるよう変更。
ループ変数名と型(int->std::size_t)の修正。
2018/6/4
頂いたコメントを受けて修正。その他仕様に至らぬ点があったため修正。
修正点
コメントへの返信に記載。
csvファイルの末尾に空行がある際、dataの行数も空行分大きくなってしまう点を修正。
csvファイルの各行末に","が存在する場合、行末のデータを重複して読み込んでしまう点を修正。
//大きさ不明の2次元配列データを2次元vectorに読み込むGetdata関数 #include <iostream> #include <fstream> #include <sstream> #include <vector> #include <string> #include <exception> template<typename Num_type> std::vector<std::vector<Num_type> > Getdata(std::string filename, std::size_t ignore_line_num = 0){ std::ifstream reading_file; reading_file.open(filename, std::ios::in); if(!reading_file) throw std::invalid_argument(filename + std::string("could not be opened.")); std::string reading_line_buffer; //最初のignore_line_num行を空読みする for(std::size_t line = 0; line < ignore_line_num; line++){ getline(reading_file,reading_line_buffer); if(reading_file.eof()) break; } Num_type num; char comma; std::vector<std::vector<Num_type> > data; while(std::getline(reading_file, reading_line_buffer)){ if(reading_line_buffer.size() == 0) break; std::vector<Num_type> temp_data; std::istringstream is(reading_line_buffer); while(is >> num){ temp_data.push_back(num); is >> comma; } data.push_back(temp_data); } return data; } //動作テスト int main(){ //読み込みデータ格納先2次元vectorを用意する、今回の数値型はなんでも良い std::vector<std::vector<double> > data; std::string filename("test.csv"); //Getdata関数を使う //テンプレート引数として読み込みデータの型名を指定(今回はdouble)。 //第1引数に読み込みたいファイルのカレントディレクトリからのパスを指定する std::cout << "reading " << filename << "..." << std::endl; data = Getdata<double>(filename); for(std::size_t line=0 ;line < data.size() ;line++){ for(int column=0 ;column < data[line].size() ;column++){ std::cout << data[line][column] << " "; } std::cout << std::endl; } std::cout << std::endl; //最初のn行を読み飛ばす場合には第2引数にnを入れる std::size_t n = 3; std::cout << "reading " << filename << "..." << std::endl; data = Getdata<double>(filename,n); for(std::size_t line=0 ;line < data.size() ;line++){ for(std::size_t column=0 ;column < data[line].size() ;column++){ std::cout << data[line][column] << " "; } std::cout << std::endl; } std::cout << std::endl; return 0; }
C++でのファイルの入出力
2/25 17:28
C++でのファイルからの入力、ファイルへの出力の仕様がよく分からなくてもやもやする。検索をしてもどうもC仕様のやり方とC++仕様のやり方があるようで、この二つが混ざって出てくる上に痒いところに手が届かないサイトしかない。あまりにイライラするのでとりあえず今欲しい情報をまとめて調べて、後で忘れた時のために書いておくことにする。
ついでにフラフラとサイトを彷徨っていたら何やら良さそうなC++の本が紹介されていたのでメモ代わりに残しておくことにする。
Accelerated C++ - 効率的なプログラミングのための新しい定跡
Exceptional C++ - 47のクイズ形式によるプログラム問題と解法
まず、stdio.hのヘッダファイルを使った入出力の方法をまとめてみる。これはC言語関数辞典(http://www.c-tipsref.com/reference/stdio.html)に載っていたのでC言語様の入出力方法なのだろう。欲をいえば覚えることは減らしたいので文法は全てC++様のものにしたいのだが、面倒なので当分はこちらをまとめてこちらを使うことにする。
fopenでファイルを開いて、入出力関数でごにょごにょし、fcloseでファイルを閉じるのが一連の流れになる。
openの戻り値は事前に宣言したファイルポインタに入れる。これは、fopenが「開いたファイルの情報を持っているオブジェクト」のポインタを返す関数だからみたいだ。
ちなみにファイル型はstdio.hの中でtypedefによって定義されている型なので、stdio.hをincludeすれば宣言できる様になる。
つまり、test.dataを読み込もうとしたら
#include <stdio.h> ... FILE * fp; ... fp = fopen("test.data", "r");
のようなコードを書けば良い。この時、fopenの二つ目の引数の”r”は読出し専用モードで開くことを指定している。
このようなモード指定は他にもある。
(http://www.c-tipsref.com/reference/stdio/fopen.html)
今回僕が知りたいのは開いたファイルの情報を上書きするのではなく、その末尾に追加で情報を加える方法なのだが、”a”で指定できる追加書き込みがどうも欲しい機能を提供してくれそうだ。
write モードではファイルを消してしまう事になるので、ファイル を消さずに書き込みを行うには append モードを用いる。(http://www.wakhok.ac.jp/~kanayama/C/02/node165.html)とあるので、これでできそう。というか全部更新モードでいいじゃないか。まあエラーを吐かせたほうが云々というのはあるのだろうけど。
ちなみにファイルのクローズは
fclose(fp);
のように書くが、プログラム終了時にはオープンしたファイルは必ずクローズされるらしいので途中でモードを変更したい場合以外は特にする必要もないみたい。
ファイルからの情報の読み込みにはfscanfを使う。使う時は下のような感じ。
double one_data; fscanf(fp,"%lf ",&one_data); data[t][i] = one_data;
一つ目の変数で入力に使うオブジェクトのポインタを指定(これをストリーム(プログラム-入出力間のデータの流れ)をしていすると言うらしい)している。
二つ目の引数は書式文字列と言うらしい。
%[代入抑止文字][フィールド幅][長さ修飾子]変換指定子 ※[]内は省略可能
という形式で記述する。代入抑止文字の部分には、もしを書くと指定した文字が読み込まれずに破棄される。例えば、%2cとやると先頭の2文字が破棄されるらしい。
長さ修飾子については以下のような感じで、引数の型を指定している。なんで長さなのかは謎。知っている方いたら是非とも教えていただきたいです。
[f:id:purple-apple:20170205200351p:plain]
(https://ja.wikipedia.org/wiki/Scanf)
変換指定子については以下
[f:id:purple-apple:20170205200406p:plain]
(https://ja.wikipedia.org/wiki/Scanf)
読み取った引数を戻す際に変換を加えることができる。
3つ目の引数には適切な方の変数を入れて、以降この変数に入ったデータを扱う。
for(int t = 0; t < TIME; t++){ for(int i = 0; i< CELL ;i++){ fscanf(fp,"%lf ",&one_data); data[t][i] = one_data; } }
のように使用すると、fpがさすオブジェクトのデータを勝手に順々にスキャンしていってくれる。また、改行は特に意識されないみたい。
とりあえずこの辺まで調べて満足したので終わり。
3/18 C++仕様の入出力についても簡単にメモしておく。
#include <fstream> //入力 std::ifstream ifs(“ファイルパス”); //ifsにファイルの内容が読み込まれる std::getline(ifs,line);//lineにifsの内容を1行ずつ読み込む //出力 std::ofstream ofs(“ファイルパス”); off << “書き込みたい文字列等” << std::endl;
軽いプログラムの時はこっちのほうが楽そう。
OpenCVの環境構築を頑張ってみた(Mac)
TLでOpenCVの環境構築に苦戦している人がいたので、それに刺激されて僕の方も一度放棄したOpenCVの環境構築に再挑戦してみることにした。
とりあえず参考になりそうなサイトとして
http://stackoverflow.com/questions/24985713/opencv-undefined-symbols-for-architecture-x86-64-error
http://www.yasutomo57jp.com/2010/09/01/linuxでopencvを入れて適当なコードをコンパイルするまで/
などを見つけたのでこれらを見つつ進めてみる。
とりあえずテストコードをネットから拾ってきてg++でコンパイルしたが、
Undefined symbols for architecture x86_64:
"_cvCreateImage", referenced from:
_main in testopencv-7eff1a.o
"_cvDestroyAllWindows", referenced from:
_main in testopencv-7eff1a.o
"_cvGetSize", referenced from:
_main in testopencv-7eff1a.o
"_cvLoadImage", referenced from:
_main in testopencv-7eff1a.o
"_cvNamedWindow", referenced from:
_main in testopencv-7eff1a.o
"_cvReleaseImage", referenced from:
_main in testopencv-7eff1a.o
"_cvShowImage", referenced from:
_main in testopencv-7eff1a.o
"_cvSmooth", referenced from:
_main in testopencv-7eff1a.o
"_cvWaitKey", referenced from:
_main in testopencv-7eff1a.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
こんな感じで弾かれてしまった。どうもリンクがうまくいっていないみたい?
「(1)cv.hなどのOpenCVのヘッダファイルが何処にあるのかの指定と,(2)libcvなどのOpenCVのライブラリが何処にあるのかの指定が必要です.」
とのことらしい。
まず,(1)のヘッダファイルについては
pkg-config --cflags opencv
でリストアップ可能で、(2)のライブラリについても同様に
pkg-config --libs opencv
を実行することでリストアップできるらしい。
この結果を
g++ -o main main.cpp -I/usr/include/opencv -L/usr/lib/opencv -lcv -lhighgui(この-o main main.cppというのは実行ファイルをmainという名前で作成するってことだろうか?)
みたいな感じでg++の引数として渡してやれば良いらしい。
また
g++ -o main main.cpp `pkg-config --cflags opencv` `pkg-config --libs opencv`
こう書けば実行時に勝手に後ろにつけたコマンドを実行して、その結果を引数として取ってくれるとか。
試してみるとうまく実行された。ちなみに同じディレクトリにMakefile(今回名前はGNUmakefileにしたがこれでないといけないかはよく分からない)を作成して
(ファイル名): (ファイル名).cpp
g++ (ファイル名).cpp -o (希望の実行ファイル名) `pkg-config --cflags opencv` `pkg-config --libs opencv`
と書き込んでおくと
make
とコマンドを打つだけで実行ファイルを作ってくれる。これでひとまずは安心?か。OpenCV3の方がこれでうまくいくのかはよく分からない。
El Capitanで日本語の入力速度が我慢ならないほど落ちた場合の対処レポ
日記をつけている最中に変換の重さが気になり、直す作業をしながらログがてらにとっていた記録をそのままあげているので乱文、かつ序盤は問題を誤認識しています。
それと、今自分はrtdfファイルをテキストエディットで編集してに気をつけているのだが、これだとどうもある程度テキストファイルが重くなると書き込みに時間がかかるようになってしまうらしい。少し他の方法を模索しないといけない。いっその事全部livedoorブログに移転してしまおうか。
とりあえず緊急避難的に今日の分だけ別ファイルに写してみたのだが、それでも重い。
どうやら今開いているファイルが問題というわけではないらしい。
もしかしたらこのファイルを入れているディスクイメージに割り振っている容量が問題なのだろうか。
少し多めの容量を割り振ってディスクイメージを作り直してみよう。
それよりもデスクトップ保存してそれで変換の速さを見てみた方が良いか。
試してみたところ変換速度は速くならなかったのでおそらく原因はディスクイメージではない。
http://itea40.jp/technic/mac-troubles/remedy-character-input-of-mac-is-slow/
少しこのページに従って直してみる。
まずディスクのアクセス権の修復を試みようとしたのだが、El Capitanではそのようなことはできないらしい。なんでGUI変えちゃうの!!
ひとまず次の項目を試して見る。Font bookの重複をチェックしたところ、それはなさそうだった。
次に、「英字入力中のスペル自動変換やスペルチェックの設定を変更する」を試して見る。
とりあえずスペルの自動変換機能をオフにしてやってみる。しかしこれでも遅い。
とりあえずスペルの自動変換機能をオフにしてやってみる。しかしこれでも遅い。
とりあえずスペルの自動変換機能をオフにしてやってみる。しかしこれでも遅い。
ONとOFFで比べてみたが、大した差はなかったので自動変換が問題でもなさそうだ。
ライブ変換をOFFにして改めて入力を試みたが、やはり遅い。
バックグラウンドのアプリケーションも3つしかないので(Readcubu,canonのプリンターのやつ,iTuneHelper)たいして影響しているとは思えない。
アクティビティモニタから何が容量をくっているのか見てみると、日本語入力プログラムが凄まじい容量の(40~90パーセント)CPUを食いつぶしているのがわかった。
システム環境設定のアクセシビリティからコントラストを上げるを選択すると治るとかいう面白い記事があったので試してみたがこれはもちろんダメだった(http://kiririmode.hatenablog.jp/entry/20150907/1441551600)。
セーフブートで起動とかも面倒だけど試してみるべきか。
それより先に日本語入力システムを切り替えよう。
いや、その前にデスクトップをきれいにしてみよう。
デスクトップに出しっぱなしにしていたファイルを整理用のフォルダに分けてみたが、多少動きが改善されたように思う。ただやっぱり日本語入力プログラムは90%近くCPUをくっているしでどうもおかしい。
変換学習をリセットしたら元の速度に戻らないだろうか。
というわけで変換学習をリセットした状態で今打っているのだが、前よりも多少改善されたような気がする。CPUの方はどうなっているかというとまあ70%とか言ってしまっているので実はあまり変わっていないのかもしれないけど。今90%近くまで上がっていた。
やはり問題はあまり改善されていなさそう。ライブ変換は便利だから使いたいのだけど、こうも遅いとストレスがたまってしまう。
こういうものだと思って我慢して使うしかないのだろうか。Google日本語入力を入れて試してみようと思う。
その前に
https://medium.com/backstage-of-backspace/el-capitan日本語入力やめました-74ba62545d31#.kc5nl15ba
にセーフブートしてみるという手軽な方法が書いてあったのでこれを試してみることにする。
「1. Macをシステム終了します(システム終了できない場合は、電源ボタンを長押しで終了)
2. 電源ボタンを押します
3. 起動音が聞こえたらすぐに「shift」キーを押してそのままにします。
4. 画面に Apple ロゴが表示されたら「shift」キーを放します。 ログインウィンドウが表示されたら、ユーザ名とパスワードの入力をお願いいたします。 「セーフモード」というモードで起動してまいります。」
ということらしい。
というわけでセーフモードで起動してみた。日本語入力プログラムも10%以下のCPU消費と非常に快適に入力ができている。ライブ変換もONにしてみよう。
ONにしてみた。これでどうだろう。変換速度は僕のタイピング速度についてきてくれているので非常に快適だ。日本語入力プログラムは50%近くCPUを食っているが、遅さは気になるほどではない。
同じ文章をライブ変換なしで入力してみる。変換速度は僕のタイピングについてきてくれているので非常に快適だ。日本語入力プログラムは多くても15%程度しかCPUを食っていない。これなら問題はなさそうだ。
ちなみに記事を読んでいるとセーフモードで起動=セーフブートみたいだ。
セーフモードではたまに画面に白い横線のような、昔のテレビでありそうな画面の乱れが生じるのが気になるけど、特に他には問題はなさそう。
これで元の起動方法に戻してみよう。
どうやらセーフモードにしなければ画面の乱れはなくなるみたいだ。変換速度は元に戻っていて非常に快適に入力ができる。
ライブ変換をONにしてみよう。
ライブ変換をONにした状態で今入力しているが、とても快適に入力できている。
アクティビティモニタの方はかなり早めにタイピングをしてみているがそれでも50%を超えないのでどうやらこれでストレスを感じずにタイピングをできそうだ。セーフブートするのがいちばん有効な解決法みたい。