みなさん,こんにちは.
おかしょです.
私のような大学院生や研究職の方は研究の成果が出ると,国内や国外で開催される学会に参加することがあります.
私も大学院生なので,これまでに学会には小さいものも含めると5回研究発表をしたことがあります.
このとき,発表資料としてPowerPointでスライドをいくつも作るのですが
私のような制御工学の研究の場合,グラフをどのように見せるのかが重要になります.
ただのグラフを見せただけでは,ロボットなどの動きがイメージしずらいため聞いてくださっている方々に伝わらない可能性があります.
そのようなときは,ロボットをシミュレーションの通りに動かすアニメーションが欲しくなります.
この記事では,アニメーションと同じように流れるグラフの作り方をビジュアルデザインで有名なProcessingを使って解説します.
この記事を読むと以下のようなことがわかる・できるようになります.
- データをグラフ化する方法
- Processingでグラフを描く方法
この記事を読む前に
この記事ではProcessingに読み込んだcsvファイルなどのデータをグラフ化する方法を解説します.
Processingにcsvファイルのデータを読み込む方法については以下の記事で解説しているので,以下の記事を先に読んでおくことをおすすめします.
グラフ作成の流れ
どんなプログラムを書くにせよ,どのような順序でプログラムを書いていくのかを決める必要があります.
ここでは,その大まかな流れを示します.
- グラフを描く範囲を設定する.
- メモリ線を描く.
- メモリに値を記入する.
- 各軸のラベル名を記入する.
- 折れ線グラフを描く.
大まかにはこのような流れで書いていきます.
グラフを描く範囲を設定する
まずは,グラフを描く範囲を決定します.
これは,どのようなデータをグラフ化するのかによって変わってきます.
例えば,時間を横軸にして縦軸に姿勢角などのデータをグラフにする場合は,横長の長方形にすることが多いです.
ロボットの座標の移り変わりを地図のように書く場合には,座標が横長に変化したり縦長に変化したりするのでそれに合わせて決定する必要があります.
この記事では時系列グラフを描くことを想定したプログラムの書き方を解説します.
他のデータをグラフ化する場合でも基本的には変わらないと思うので,参考にしてみてください.
時系列グラフを描くので,横長の長方形を用意します.
今回は以下のようなプログラムで長方形を描きます.
void setup()
{
background(0); // 背景の色指定 黒に指定
size(displayWidth,displayHeight); // windowのサイズ指定 ディスプレイ全体に表示
stroke(255);
noFill();
rect(width*0.58, height*0.09, width*0.37, height*0.24);
}
void draw()
{
}
3行目にあるように,今回は背景は黒に設定しています.
理由は「なんかその方がかっこいい気がする」からです.
作成している発表資料によっては白が背景の方が良い場合もあるので,好みで設定してください.
4行目で表示するwindowのサイズをディスプレイいっぱいに表示するようにしています.
このプログラムは,時系列データだけでなく,ロボットのアニメーションも同時に表示するプログラムの一部から抜粋しているので画面いっぱいに表示するようにしています.
グラフだけを表示したい場合は,グラフのサイズによってwindowのサイズも調整してください.
5~7行目でグラフの枠線を描いています.
5行目にあるように枠線の色は背景が黒なので,白にしました.
そして,長方形の枠だけが必要なのでnoFill()として塗りつぶしはしないようにしています.
7行目で枠線を描く座標とサイズを設定しています.
上のプログラムを実行するとwindowの右上の方に長方形が描けます.
メモリ線を描く
枠線だけではグラフが見ずらいので,メモリ線を描いていきます.
メモリ線の書き方は,データのとりうる範囲によって異なります.
シミュレーション時間が10秒の時は,メモリ線を5本書いて2秒ごとに区切るのか
もしくは100秒で3本メモリ線を引いて,25秒ごとに区切るなどバラバラです.
さらに,同じ10秒でも先程描いた枠線のサイズが小さい場合は5本ではなく1本だけしか引けない場合があります.
このように,シミュレーションの結果によってメモリ線の書き方はさまざまに変化してしまいます.
このような様々な状況に対応できれば非常に便利なのですが,そのようなプログラムは非常に複雑になってしまいます.
そのため,この記事ではシミュレーション時間や区切り方は決まっているものとして解説していきます.
今回はシミュレーション時間は50秒,メモリ線は4本引いて10秒刻みとします.
縦軸のメモリ線は-1から1までの間を0.5刻みで3本のメモリ線を引くとします.
メモリ線の描画は以下のプログラムで行いました.
stroke(100);
for(int i =1;i<5;i++)
{
line(width*0.58+width*0.37*i/5, height*0.09, width*0.58+width*0.37*i/5, height*0.33);
}
for(int i =0;i<2;i++)
{
line(width*0.58, height*0.21-height*0.12*i/2, width*0.58+width*0.37, height*0.21-height*0.12*i/2);
line(width*0.58, height*0.21+height*0.12*i/2, width*0.58+width*0.37, height*0.21+height*0.12*i/2);
}
このプログラムは先ほどのプログラムの7行目の後に加えてください.
そのようにすると,メモリ線が引けてグラフっぽくなります.
最初に枠線の色をstroke(100)として,灰色で設定します.
最初のfor文では横軸のメモリ線を描いています.
メモリ線は4本あればいいので,for文の中でiという変数が1から4まで変化するようにしています.
枠線を書いたときに設定した,枠線のサイズ(width*0.37: windowの37%)とこのiを使ってメモリ線を描いていきます.
次のfor文では縦軸のメモリ線を描いています.
こちらも先程と同じようにしても書くことはできますが,違う方法として中心のメモリ線から書いています.
線を引く時の始点と終点の座標の設定は同じように,枠線のサイズ(height*0.24: heightの24%)と変数iを使用して書いています.
メモリに値を記入する
これまでで,図02のようにメモリ線が引けたので,メモリ線に値を記入していきます.
void setup()
{
background(0); // 背景の色指定 黒に指定
size(displayWidth,displayHeight); // windowのサイズ指定 ディスプレイ全体に表示
stroke(255);
noFill();
rect(width*0.58, height*0.09, width*0.37, height*0.24);
stroke(100);
fill(255);
textSize(height*0.02);
textAlign(CENTER);
for(int i =1;i<5;i++)
{
line(width*0.58+width*0.37*i/5, height*0.09, width*0.58+width*0.37*i/5, height*0.33);
text(i*10, width*0.58+width*0.37*i/5, height*0.35);
}
for(int i =0;i<2;i++)
{
line(width*0.58, height*0.21-height*0.12*i/2, width*0.58+width*0.37, height*0.21-height*0.12*i/2);
line(width*0.58, height*0.21+height*0.12*i/2, width*0.58+width*0.37, height*0.21+height*0.12*i/2);
}
text("0", width*0.57, height*0.21);
text("0.5", width*0.565, height*0.21-height*0.12*1/2);
text("-0.5", width*0.56, height*0.21-height*0.12*(-1)/2);
text("1.0", width*0.565, height*0.21-height*0.12*2/2);
text("-1.0", width*0.56, height*0.21-height*0.12*(-2)/2);
}
void draw()
{
}
これまでのプログラムをまとめたものが以上のプログラムになります.
メモリの値を記入している部分のみ解説します.
まず,値を表示する文字の設定を行っているのが9~11行目になります.
9行目では文字の色を白色に,10行目では文字のサイズ,11行目では文字を中央揃えに設定しています.
そして,縦軸のメモリ値と横軸のメモリ値を2パターンで書いてみました.
横軸のメモリ値は15行目にあるようにfor文の中で簡単に書いています.
縦軸はfor文で書かずに,一つ一つ書いています.
個人的にはfor文で書いた方が楽ですが,縦軸に書いたように一つ一つ書いた方が理解しやすいという方もいるかと思うので,お好きな方で書いてみてください.
各軸のラベル名を記入する
次に各軸にラベルを記入します.
ラベル名の記入は以下のプログラムを先程のプログラムの27行目に加えるとできます.
text("time [s]", width*0.765, height*0.38);
pushMatrix();
rotate(radians(-90));
text("x [-]", -height*0.21, width*0.54);
popMatrix();
ここで,注意するのはラベルを描く座標と縦軸のラベル名は90度回転させることです.
90度回転させますが,ラベル名の記入が終わった後は元の座標系に戻したいので,その前後でpushMatrix()とpopMatrix()を使用しています.
折れ線グラフを描く
最後に,これまで用意してきたグラフ描画範囲に折れ線グラフを描いていきます.
これから示すプログラムではcsvファイルのデータがProcessingで定義した変数に格納されているとして書いています.
そのため,このプログラムだけでは実行できないことをご了承ください.
stroke(R, G, B);
line(width*0.58+width*0.37*TimeP/LastTime, height*0.21+height*0.12*xP/xMax ,width*0.58+width*0.37*Time/LastTime, height*0.21+height*0.12*x/xMax);
TimeP = Time;
xP = x;
これをdraw関数の中に加えることで,先程のブラフ描画範囲内に折れ線グラフを描くことができます.
このプログラムの1行目では折れ線の色をRGBで指定します.お好きな色に設定してください.
2行目では折れ線を描いています.
このとき,TimePやxPというのは時間と状態量のデータの1ステップ前の値になります.
そのため,3,4行目ではそれらの値を更新しています.
また,2行目で使用しているLastTimeはシミュレーション時間を意味します.
今回は50秒としているので,ここの値は50となります.
xMaxというのは状態量の最大値を意味していて,今回の場合は描画可能な範囲が-1から1までなので,この値は1になります.
上記のプログラムをdraw関数内に書き加えることで,draw関数が繰り返されるたびに折れ線が連結されていき,流れるように折れ線グラフの描画が可能となります.
まとめ
この記事ではcsvファイルのデータからProcessingで時系列グラフを作る方法を解説しました.
上記のような方法でプログラムを書いていけば,折れ線グラフの描画も可能となります.
続けて読む
この記事で紹介した方法を利用して,マス・スプリング・ダンパーの数値シミュレーション結果をグラフ化しました.
以下の記事で紹介しているので,興味のある方は参考にしてください.
Twitterでは記事の更新情報や活動の進捗などをつぶやいているので気が向いたらフォローしてください.
それでは最後まで読んでいただきありがとうございました.
コメント