GDT2DV等のモニタリング・アプリケーションソフトウェアのProcessing開発においては、いろいろなグラフ図を効率よく作成していきたい。
そこで、グラフ作成する関数群をまとめて、SwGraphとしてクラス化した。基本となる関数群は、オライリーの「ビジュアライジング・データ――Processingによる情報視覚化手法Visualizing Data by Ben Fly」を参考にした。Processingの開発者の素晴らしい著書であるので是非、一読いただきたい。
特に同書に収められている浮動小数点をテーブルとしてハンドリングするためのライブラリーFloatTable.pde は大変重宝する。
ーーーーーーーーーーーーーーーーーーーーーーーーーー
【ポイント1】座標軸とmap関数変換
関数map(a,b,c,d,e)
aを範囲b-cから別の範囲d-eへ変換する。
ーーーーーーーーーーーーーーーーーーーーーーーーーー
以下のコンストラクタで、SwGraphクラス・インスタンス作成時に、初期設定(X軸最小値、X軸最大値、Y軸最小値、Y軸最大値、X軸ボリュームインターバル、Y軸ボリュームインターバル、X軸マイナーボリュームインターバル、Y軸ボリュームインターバル、X軸左上角座標値、Y軸左上角座標値、X軸幅、Y軸幅)を宣言する。
SwGraph (float _xdataMin, float _xdataMax, float _ydataMin, float _ydataMax,
float _xvolumeInterval, float _yvolumeInterval, float _xvolumeIntervalMinor, float _yvolumeIntervalMinor,
float _plotX1, float _plotY1, float _plotX_W, float _plotY_W)
一方、グラフはdraw()関数内で以下の6つのクラス内インスタンス・メソッドで描画される。
1) void drawPoints(float _x[], float _y[], int _flag, int _color_code) //データプロットを表示する関数
2) void xdrawVolumeLabels() //X軸ボリュームラベルを表示する関数
3) void ydrawVolumeLabels()//Y軸ボリュームラベルを表示する関数
4) void drawxLabels() //X軸のメジャー罫線を描画する関数
5) void drawxLabels() //Y軸のメジャー罫線を描画する関数
6) void drawAxisLabels(String _ylabel, String _xlabel) //Y軸、X軸のラベルを記載する関数
と
7) void drawDataPoints() //保存した過去のデータプロットをトレンド表示する関数
setup()関数内で、SwGraphのインスタンスを生成し、コンストラクタで初期値を指定する。次にdraw()関数内でグラフを描画するdraw_graphs()関数を呼び出す。draw_graphs()関数内では、上記6つのクラス内インスタンス・メソッドをインスタンスに送ってグラフを描画する。
1 2 3 |
swGraph = new SwGraph(X軸最小値, x軸最大値, y軸最小値, y軸最大値, x軸マイナーメモリ, x軸メジャーメモリ, y軸マイナーメモリ, y軸メジャーメモリ, グラフ左上角x座標値, グラフ左上角y座標値, グラフ幅, グラフ高); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
void setup(){ ............. swGraph = new SwGraph(0, 2, 0, 120, 1, 50, 1, 10, 80, 150, 300, 300); ............. } void draw(){ ............. draw_graphs(); ............. } void draw_graphs() { swGraph.drawAxisLabels("SVV", "SVI"); swGraph.xdrawVolumeLabels(); swGraph.ydrawVolumeLabels(); swGraph.drawxLabels(); swGraph.drawyLabels(); swGraph.drawx_range_Labels(13, 4); swGraph.drawy_range_Labels(7, 3); swGraph.draw_range_box(7, 3, 13, 4); swGraph.drawDataPoints_log(); swGraph.drawPoints_log(SVV, SVI); } |
——————————————————————–
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
class SwGraph { float xdataMin = 0; float xdataMax = 0; float ydataMax = 0; float ydataMin = 0; float xvolumeInterval = 0; float yvolumeInterval = 0; float xvolumeIntervalMinor = 0; float yvolumeIntervalMinor = 0; float plotX1 = 0; float plotY1 = 0; float plotX2 = 0; float plotY2 = 0; float plotX_W = 0; float plotY_W = 0; float labelX; float labelY; String xlabel = "x"; String ylabel = "y"; // Constructor SwGraph (float _xdataMin, float _xdataMax, float _ydataMin, float _ydataMax, float _xvolumeInterval, float _yvolumeInterval, float _xvolumeIntervalMinor, float _yvolumeIntervalMinor, float _plotX1, float _plotY1, float _plotX_W, float _plotY_W) { xdataMin = _xdataMin; xdataMax = _xdataMax; ydataMax = _ydataMax; ydataMin = _ydataMin; xvolumeInterval = _xvolumeInterval; yvolumeInterval = _yvolumeInterval; xvolumeIntervalMinor = _xvolumeIntervalMinor; yvolumeIntervalMinor = _yvolumeIntervalMinor; plotX1 = _plotX1; plotY1 = _plotY1; plotX2 = _plotX1+_plotX_W; plotY2 = _plotY1+_plotY_W; plotX_W = _plotX_W; plotY_W = _plotX_W; } void drawPoints(float _x[], float _y[], int _flag, int _color_code){ float[] xvalue = _x; float[] yvalue = _y; float x_mapped = 0; float y_mapped = 0; float x_mapped_pre = 0; float y_mapped_pre = 0; int flag = _flag; int color_code = _color_code; for(int i= 0; i<xvalue.length-1;i++) { if (xvalue[i] <= xdataMax){ x_mapped = map(xvalue[i], xdataMin, xdataMax, plotX1, plotX2); y_mapped = map(yvalue[i], ydataMin, ydataMax, plotY2, plotY1); if (xvalue[i] >= -50 && xvalue[i] <= 50 && yvalue[i] >= -50 && yvalue[i] <= 50){ strokeWeight(1.0); switch (color_code){ case 0: stroke(#00ff00); break; case 1: stroke(#FF00FF); break; case 2: stroke(#00FFFF); break; case 3: stroke(#FFA500); break; case 4: stroke(#FFFF00); break; case 5: stroke(#FF0800); break; } if(i > 0){ if(flag == 0){ point(x_mapped, y_mapped); } else { line (x_mapped_pre, y_mapped_pre, x_mapped, y_mapped); } } x_mapped_pre = x_mapped; y_mapped_pre = y_mapped; } } } } void xdrawVolumeLabels() { fill(0); textSize(10); textAlign(RIGHT); stroke(128); strokeWeight(1.0); //rect(plotX1, plotY1, plotX2, plotY2); for (float v = xdataMin; v <= xdataMax; v += xvolumeIntervalMinor) { if (v % xvolumeIntervalMinor == 0) { float x = map(v, xdataMax, xdataMin, plotX2, plotX1); if (v % xvolumeInterval == 0) { float textOffset = textAscent()/2; if (v == xdataMin) { textOffset = 0; } else if (v == xdataMax) { textOffset = textAscent(); } text(floor(v), x + textOffset, plotY2 + 15); line(x, plotY2 + 4, x, plotY2); } else { line(x, plotY2 + 2, x, plotY2); } } } } void ydrawVolumeLabels() { fill(0); textSize(10); textAlign(RIGHT); stroke(128); strokeWeight(1.0); rect(plotX1, plotY1, plotX2, plotY2); for (float v = ydataMin; v <= ydataMax; v += yvolumeIntervalMinor) { if (v % yvolumeIntervalMinor == 0) { float y = map(v, ydataMin, ydataMax, plotY2, plotY1); if (v % yvolumeInterval == 0) { float textOffset = textAscent()/2; if (v == ydataMin) { textOffset = 0; } else if (v == ydataMax) { textOffset = textAscent(); } text(floor(v), plotX1 - 10, y + textOffset); line(plotX1 - 4, y, plotX1, y); } else { line(plotX1 - 2, y, plotX1, y); } } } } void drawxLabels() { fill(0); stroke(224); strokeWeight(0.5); for (float v = xdataMin; v <= xdataMax; v += xvolumeIntervalMinor) { if (v % xvolumeIntervalMinor == 0) { float x = map(v, xdataMax, xdataMin, plotX2, plotX1); if (v % xvolumeInterval == 0) { float textOffset = textAscent()/2; if (v == xdataMin) { textOffset = 0; } else if (v == xdataMax) { textOffset = textAscent(); } line(x, plotY1, x, plotY2); } } } } void drawyLabels() { fill(0); stroke(224); strokeWeight(0.5); for (float v = ydataMin; v <= ydataMax; v += yvolumeIntervalMinor) { if (v % yvolumeIntervalMinor == 0) { float y = map(v, ydataMin, ydataMax, plotY2, plotY1); if (v % yvolumeInterval == 0) { float textOffset = textAscent()/2; if (v == ydataMin) { textOffset = 0; } else if (v == ydataMax) { textOffset = textAscent(); } //text(floor(v), plotX1 - 10, y + textOffset); line(plotX1, y, plotX2, y); } } } } void drawAxisLabels(String _ylabel, String _xlabel) { fill(0); noStroke(); rect(plotX1, plotY1, plotX2, plotY2); String xlabel = _xlabel; String ylabel = _ylabel; labelX = plotX1-30; labelY = plotY2+25; fill(0); textSize(14); textLeading(15); textAlign(CENTER, CENTER); text(xlabel, labelX, (plotY1+plotY2)/2); textAlign(CENTER); text(ylabel, (plotX1+plotX2)/2, labelY); } } |
今回は、実際には、X軸にプロットするSVVをlog表示とするために、drawDataPoints()関数にて、リアルタイムに保存したtsvデータファイルから読み込んだ過去のデータについてもトレンドも表示できるように、以下のようにインスタンスメソッドを2つ追加した。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
void drawPoints_log(float _x, float _y) { float x_mapped = 0; float y_mapped = 0; float x_mapped_pre = 0; float y_mapped_pre = 0; float xvalue = 0; float yvalue = 0; float x = 0; float y = 0; xvalue = SVV; yvalue = SVI; float xvalue_log = log(xvalue)/log(10); if (xvalue_log > xdataMin & xvalue_log <= xdataMax & yvalue > ydataMin & yvalue <= ydataMax ) { x_mapped = map(xvalue_log, xdataMin, xdataMax, plotX1, plotX2); y_mapped = map(yvalue, ydataMin, ydataMax, plotY2, plotY1); if (xvalue > 0) { stroke(#FF0000); strokeWeight(8); point(x_mapped, y_mapped); } if (yvalue >0 & xvalue >0) { if (yvalue < 70 & yvalue >= 30 & xvalue >= 4 & xvalue < 13) { score= score + 1; } data_count = data_count + 1; } score_calculated = score/data_count; } } void drawDataPoints_log() { float xvalue = 0; float yvalue = 0; float x = 0; float y = 0; float xvalue_post = 0; float yvalue_post = 0; float x_post = 0; float y_post = 0; int col=0; data = new FloatTable("user_data/" + global_id + "/data_vigileo.tsv"); int rowCount = data.getRowCount(); println("rowCounSwt=:", rowCount); for (row = 0; row < rowCount; row++) { if (data.isValid(row, col)) { xvalue = data.getFloat(row, col); yvalue = data.getFloat(row, col+1); float xvalue_log = log(xvalue)/log(10); color_value = data.getFloat(row, col+11); color_int = int(color_value); x = map(xvalue_log, xdataMin, xdataMax, plotX1, plotX2); y = map(yvalue, ydataMin, ydataMax, plotY2, plotY1); if (xvalue_log > xdataMin & xvalue_log <= xdataMax & yvalue >ydataMin & yvalue <= ydataMax) { switch(color_int) { case 0: stroke(#FFFFFF); strokeWeight(4); point(x, y); break; case 1: stroke(#00b200); strokeWeight(4); point(x, y); break; case 2: stroke(#9932CC); strokeWeight(4); point(x, y); break; case 3: stroke(#0000FF); strokeWeight(4); point(x, y); break; case 4: stroke(#FFA500); strokeWeight(4); point(x, y); break; case 5: stroke(#FF0040); strokeWeight(4); point(x, y); stroke(#4B0082); strokeWeight(1); if (row >1) { xvalue_post = data.getFloat(row-1, col); yvalue_post = data.getFloat(row-1, col+1); float xvalue_post_log = log(xvalue_post)/log(10); if (xvalue_post_log > xdataMin & xvalue_post_log <= xdataMax & yvalue_post > ydataMin & yvalue_post <= ydataMax) { x_post = map(xvalue_post_log, xdataMin, xdataMax, plotX1, plotX2); y_post = map(yvalue_post, ydataMin, ydataMax, plotY2, plotY1); line(x, y, x_post, y_post); } } break; } } } } } |