「蓄積されたデータおよび随時更新されるデータをグラフとして可視化する」アプリケーション(続き)
Webアプリケーション本体の作成
では、Webアプリケーション本体を作成していきます。Node-REDフローエディターで、画面29に示すフローを作成してください。本記事の添付ファイル(codezine_iotdemo_nodered_app2-b.json)からインポートすることもできます。
各ノードの設定を確認・編集していきます。最初に、「Cloudantからデータ取得処理」フローを修正します。
① input >「http」ノード
Injectノードと差し替えて、functionノード(「search param」)につなげます。
-
Method: GET
-
URL: /data
-
Name: 任意(画面29では「[get] /data」)
ここで指定したURLは、Ajaxによるデータ取得処理の呼び出しで使います。
② functionノード(「search param」)
Function欄に入力するコード
msg.payload = {
"query": "timestamp: 2016*",
"sort" : "-timestamp<string>",
"limit": msg.payload.num
};
return msg;
HTTPリクエストのパラメーターとして"num"
を設定することで、取得する件数を動的に指定できるようにしています。
上述したhttpノードで設定したURLと合わせて、例えば10件データを取得するためには次のURLをAjaxで発行すればよいことになります。
③ output >「http response」ノード
画面側へレスポンスを返すために新規に追加して、Cloudantノードの出力側へつなげます。http responseノードは特に設定する項目はありません。
また、以前の手順でつなげてあったdebugノードはそのまま残しておいて構いません。
次に、「Webアプリケーション」フローを追加します。
④ input >「http」ノード
-
Method: GET
-
URL: /
-
Name: 任意(画面29では「[get]/」)
グラフ表示するページのURLをここで設定します。上記設定の場合は作成したアプリケーションのルートとなります(例 http://codezineiotdemo.mybluemix.net/)。例えば、ここで「/chart」を設定すると、「http://codezineiotdemo.mybluemix.net/chart」がページのURLとなります。
⑤ function >「template」ノード
-
Name: 任意(画面29では「index.html」。.htmlはなくても構いません)
-
set property: msg.payload(デフォルトのまま)
-
Template: 後に示すコードを入力(サンプルファイル「index_app2-b.html」)
-
Format: Mustache template(デフォルトのまま)
Template欄に入力するコード(▼クリックするとプルダウンしてコードが表示されます)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!-- jQuery -->
<script src="http://code.jquery.com/jquery-1.12.0.min.js"></script>
<!-- d3.js -->
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<title>IoT demo chart</title>
<style>
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.line {
fill: none;
stroke: royalblue;
stroke-width: 1.5px;
}
.line2 {
fill: none;
stroke: orangered;
stroke-width: 1.5px;
}
.line3 {
fill: none;
stroke: forestgreen;
stroke-width: 1.5px;
}
</style>
<script type="text/javascript">
//グラフ用のデータ配列
var data = [];
window.addEventListener('load', function () {
//Cloudant APIのURL
var recordnum = 10;
var dataurl = "./data?num=" + recordnum;
//Cloudantからデータ取得して初期表示
d3.json(dataurl, function(datas){
//console.log("===== d3.json ========");
//console.log(datas);
//JSONで取得する項目はそのまま使えるのでグラフ用配列にセット
data = datas;
//配列の順序を入れ替えてセット→D3.jsがよしなにしてくれるので不要
// for (var i in datas){
// data.unshift(datas[i]);
// }
//console.log("==== data object =====");
//console.log(data);
//グラフ描画処理
drawInitialChart();
//最新データを表示
var dispdata = {
timestamp : formatDateTime(new Date(datas[0].timestamp)),
temp : datas[0].temp,
humidity : datas[0].humidity,
objectTemp : datas[0].objectTemp
};
disp_info(dispdata);
});
});
</script>
</head>
<body>
<div style="margin:30px;">
<h1>IoTセンサーデータ可視化デモ</h1>
<div>
<p>最新データ :
<span id="latestts">timestamp</span>
, <span style="color:royalblue;">気温:<span id="latesttemp">xx</span></span>
, <span style="color:forestgreen;">湿度:<span id="latesthum">xx</span></span>
, <span style="color:orangered;">機械温度:<span id="latestot">xx</span></span>
</p>
</div>
<div id="chartarea"></div>
<p></p>
</div>
<script>
//D3.js 初期処理
//表示サイズを設定
var areasize = {width: 960, height: 500};
var margin = {top: 40, right: 40, bottom: 40, left: 40};
//グラフ表示用の高さと幅
var chartwidth = areasize.width - margin.left - margin.right;
var chartheight = areasize.height - margin.top - margin.bottom;
var formatDateTime = d3.time.format("%Y-%m-%d_%H:%M:%S");
var parseDate = d3.time.format("%Y-%m-%d_%H:%M:%S").parse;
//SVG領域の設定
var svg = d3.select("#chartarea").append("svg")
.attr("width", areasize.width)
.attr("height", areasize.height)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.time.scale()
.range([0, chartwidth]);
var y = d3.scale.linear()
.range([chartheight, 0]);
var y2 = d3.scale.linear()
.range([chartheight, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
//.orient("bottom")
//.tickFormat(d3.time.format("%m/%d_%H:%M"));
//温度のY軸(左側)
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
//湿度のY軸(右側)
var yAxis2 = d3.svg.axis()
.scale(y2)
.orient("right");
//ライン・気温
var line = d3.svg.line()
.x(function(d){ return x(d.timestamp); })
.y(function(d){ return y(d.temp); });
//ライン・機器温度
var line2 = d3.svg.line()
.x(function(d){ return x(d.timestamp); })
.y(function(d){ return y(d.objectTemp); });
//ライン・湿度
var line3 = d3.svg.line()
.x(function(d){ return x(d.timestamp); })
.y(function(d){ return y2(d.humidity); });
//グラフの初期描画処理 データ取得後にコールされる
function drawInitialChart(){
//console.log("===== drawInitialChart ======");
data.forEach(function(d){
d.timestamp = parseDate(d.timestamp);
d.temp = +d.temp;
d.objectTemp = +d.objectTemp;
d.humidity = +d.humidity;
});
//X軸のドメイン=Timestampの最小値と最大値
x.domain(d3.extent(data, function(d){ return d.timestamp; }));
//Y軸のドメイン=0から、気温Maxと機器温度Maxの大きい方
var maxtemp = d3.max(data, function(d){ return d.temp; });
var maxobjtemp = d3.max(data, function(d){ return d.objectTemp; });
var max_y = maxtemp > maxobjtemp ? maxtemp : maxobjtemp;
y.domain([0, max_y]);
//Y軸(湿度)は0-100固定
y2.domain([0, 100]);
//X軸 描画
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0, " + chartheight + ")")
.call(xAxis);
//Y軸(左) 描画
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "translate(60,-20) rotate(0)")
.attr("y", 6)
.attr("dy", ".7em")
.style("text-anchor", "end")
.text("温度(℃)");
//Y軸(右) 描画
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + chartwidth + " ,0)")
.call(yAxis2)
.append("text")
.attr("transform", "translate(0,-20) rotate(0)")
.attr("y", 6)
.attr("dy", ".7em")
.style("text-anchor", "end")
.text("湿度(%)");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
svg.append("path")
.datum(data)
.attr("class", "line2")
.attr("d", line2);
svg.append("path")
.datum(data)
.attr("class", "line3")
.attr("d", line3);
}
//最新データ表示
function disp_info(wsdata){
$("#latestts").text(wsdata.timestamp);
$("#latesttemp").text(wsdata.temp);
$("#latesthum").text(wsdata.humidity);
$("#latestot").text(wsdata.objectTemp);
}
</script>
</body>
</html>
以下、コードの説明です。
12~41行目:D3.jsのグラフ用CSSの設定です。.lineが気温、.line2が機器温度、.line3が湿度の線となり、分かりやすくするためにそれぞれ色を変えています。
49~77行目:Cloudantのデータを取得するためのAjax発行処理です。D3.jsでは、54行目の「d3.json(dataurl, function(datas){・・・}という一行の表記だけでdataurlのAjaxを発行してJSON形式の戻り値dataを得て、「・・・」の処理を行う、ということが指定できます。取得したデータを使ってグラフ描画の処理を行いますので、グラフ描画処理はこのd3.jsonのfunctionブロック内に記述します。
103~155行目:D3.jsの初期処理(共通設定)です。今回は、1つのエリアに3つ線があり、かつ温度(気温、機器温度)と湿度という2軸(Y軸が2つ)というグラフになっているので、その分、設定項目は増えています。
159~221行目:グラフの描画処理です。Ajax発行ブロック内からコールされます。170~178行目で設定しているドメインというのは、グラフのX軸・Y軸の値の範囲です。180~205行目でX軸・Y軸を描画して、207~220行目でラインを描画しています。
⑥ output >「http response」ノード
設定する項目はありません。
ここまで確認・編集できたら動作確認します。Webブラウザで、本アプリケーションのルートURL(例 http://codezineiotdemo.mybluemix.net/)にアクセスし、画面34のようなグラフが表示されれば成功です。
IoT成功のカギを握る:データ管理・分析クラウドサービスのご紹介
現象をデータ化するセンサーやデバイスに注目が集まりがちなIoTですが、価値を生むのはデータ化したその後の処理です。
「多数のセンサー、デバイスからインターネット経由で送信されてくるJSONデータを効率よく保管する」
「保管した大量のデータから未知のパターンを割り出し、ビジネスを成長させる知見を提供する」
こうしたIoTが価値を生むためのサービス・製品がIBMにあります。ぜひ、下記の資料をご覧ください。(編集部)