追記
2018.02.07追記。
Kibana6.2.0より、VegaがプラグインインストールなしでKibana本体だけで使えるようになっています。
Vegaの記法そのものについては、この記事は参考になる部分はありますが、その旨ご承知おきください。
あわせて、こちらもどうぞKibana 6.2.0リリース記念 Vegaで遊ぼう
追記終わり。
概要
Kibanaでは、棒グラフや線グラフ、円グラフを始めとした基本的なグラフがVisualizationとして用意されていますが、
それ以外もプラグインを入れることで実現できたりします。
公式に紹介されているプラグインは、こちらで見ることができます。
https://www.elastic.co/guide/en/kibana/current/known-plugins.html
今回は、ローソク足チャートを出すために、ここにあるVega-based visualizationsを入れてやってみます。
どんなグラフが描けますか
詳しくはこちらのサイト、Examplesから見ることができます。
で、今回はVega Liteの方にある「Candlestick Chart」を使ってみます。
先に結論
こんな画面を作ることができました。
ローソク足
移動平均線を追加
環境構築
kibanaにプラグインのインストール
現時点での最新版の6.1.0では互換性がないと言われたので、kibanaは6.0.1を使用します。
12/19日現在、プラグインは0.5.1が最新でした。
kibana-plugin install \
https://github.com/nyurik/kibana-vega-vis/releases/download/v0.5.1/vega_vis-0.5.1--for-Kibana-6.0.1.zip
環境にもよるのでしょうが、インストールには少し時間がかかりました。
テストデータの用意
今回は日経平均株価でローソク足チャートを書いています。
以前にやった「Elasticsearchを使って日経平均株価データでMachine Learningを体験する」 を使いまわし(再利用し)ます
データとしては、このような形として入ります。
{
"_index": "stock",
"_type": "nikkei225",
"_id": "105",
"_score": 1,
"_source": {
"start_value": 15130.74,
"timestamp": "2014-06-10T00:00:00",
"high_value": 15184.77,
"end_value": 14994.8,
"low_value": 14966.8
}
}
Visualizationの作成
新規作成
Visualizationを選択し、画面下部の「Other」の部分に現れる「Vega」をダブルニープレス(選択)します。
雛形の表示
標準で提供されているVisualizationであれば、選択後にはIndexやSaved Searchを選択する画面に遷移しますが、
Vegaの場合は、indexなどを指定する画面は表示されず、いきなりこのような画面となります。
初期表示時に、Dev Toolsのような画面が現れ、いきなり赤い文字でエラーのように見えると萎えます。
ざっと中身を眺めたあと、上部にある「JSON」ボタンを押すと、コメントがなくなりエラーは消えます。
jsonの記述
ここからは、https://vega.github.io/editor/#/ を開きつつ行うと良いでしょう。
こちらのサイトでは、データを直接渡したり、外部のjsonファイルから取得するようなサンプルとなっています。
このデータを受け渡す部分を、Elasticsearchのクエリと検索結果にする、という作業になります。
メインは、aggs以下なのですが、それ以外の項目もあるので整理します。
全体の構造
大まかな構造はこのようになっています。
{
"$schema": "https://vega.github.io/schema/vega-lite/v2.json",
"title": "日経平均株価の推移",
"width": 1024,
"data": {
"url": {
"index": "stock",
"%context_query%": "timestamp",
"body": {}
},
"size": 0
},
"format": {"property": "aggregations.time_buckets.buckets"}
},
"transform": [],
"layer": []
}
項目 | 説明 |
---|---|
$schema | vega側のスキーマ指定。通常は変更せずそのままで良いと思う |
title | visualizationの上部に表示されるタイトル名 |
width | 横幅。Dashboardに貼り付けた際に領域の大きさに自動でフィットするわけではなかった |
data | 肝心のグラフに描画するデータ設定部分。 |
data.url.index | index名を指定する。logstash-* などのイメージ |
data.url.%context_query% | kibanaの上部にある時間の範囲指定部分のクエリーの対象フィールドを指定する 今回はtimestampにdatetimeがあるので、"timestamp"としている。 |
data.url.body | aggregationの指定をここで行う。 |
transform | データ加工のフェーズ |
layer | グラフ表示部分。ローソク足の場合は、縦の細い棒のグラフと矩形のグラフの2つが重なって表現されている。これをレイヤーで表現している |
data.url.body
aggs以下は、通常のElasticsearchでaggregationを取得する際のクエリと変わりません。
注意が必要なのは、通常kibanaで生成されるリクエストでは aggs以下に1や2といった名前となっていますが、
Vegaの場合、後からlayerの部分で明示的にどの項目をy軸の値とするか、といった指定をします。
そのため、わかりやすい名称にしています。
- date histgramを1日間隔で取得
- 高値、安値、始値、終値を1日ごとに取得
- 終値の25日移動平均を取得
"url": {
"index": "stock",
"%context_query%": "timestamp",
"body": {
"aggs": {
"time_buckets": {
"date_histogram": {
"field": "timestamp",
"interval": "1d",
"extended_bounds": {
"min": {"%timefilter%": "min"},
"max": {"%timefilter%": "max"}
},
"min_doc_count": 0
},
"aggs": {
"high_value": {"avg": {"field": "high_value"}},
"low_value": {"avg": {"field": "low_value"}},
"end_value": {"avg": {"field": "end_value"}},
"start_value": {"avg": {"field": "start_value"}},
"moving": {
"moving_avg": {
"buckets_path": "moving_end",
"model": "simple",
"window": 25,
"settings": {}
}
},
"moving_end": {"avg": {"field": "end_value"}}
}
}
}
}
auto intervalとする場合は、interval指定を、このように書けば良いです。
"interval": {"%autointerval%": true}
layer ローソク足部分
markとしてrule(縦線), bar(矩形部分)の2つがあります。
x軸はdate histgramなので共通ですが、y軸の値の指定が違います。
typeに指定されているtemporalは時系列の時間、quantitativeは数値データということぐらいの認識で良いです。
大事なのは、fieldに指定するところです。
ここに、{aggregation名}.value で値をセットすることができます。
"layer": [
{
"mark": "rule",
"encoding": {
"x": {
"field": "key",
"type": "temporal",
"timeUnit": "yearmonthdate",
"axis": {"format": "%m/%d", "title": "月/日"}
},
"y": {
"field": "low_value.value",
"type": "quantitative",
"scale": {"zero": false},
"axis": {"title": ""}
},
"y2": {
"field": "high_value.value",
"type": "quantitative"
},
"color": {
"field": "isIncrease",
"type": "nominal",
"scale": {"range": ["#ae1325", "#06982d"]},
"legend": null
}
}
},
{
"mark": "bar",
"encoding": {
"x": {
"field": "key",
"type": "temporal",
"timeUnit": "yearmonthdate"
},
"y": {
"field": "start_value.value",
"type": "quantitative"
},
"y2": {
"field": "end_value.value",
"type": "quantitative"
},
"size": {"value": 5},
"color": {
"field": "isIncrease",
"type": "nominal",
"legend": null
}
}
},
graph | item | value | remarks |
---|---|---|---|
rule | y.field | low_value.value | 安値 |
rule | y2.field | high_value.value | 高値 |
bar | y.field | start_value.value | 始値 |
bar | y2.field | end_value.value | 終値 |
移動平均部分
Lineチャートなので、typeをlineとし、なめらかになるように interpolateをcardinalにしています。
先と同じように yのfieldに値をセットします。
{
"mark": {
"type":"line",
"interpolate": "cardinal"
},
"encoding": {
"x": {
"field": "key",
"timeUnit": "yearmonthdate",
"axis": {"format": "%m/%d", "title": "月/日"}
},
"y": {
"field": "moving_end.value",
"type": "quantitative"
}
}
}
おまけ
始値が終値よりも低い場合は、「増えた」とみなす、というようなデータ処理をtransformで行っています。
"transform": [
{
"calculate": "datum.start_value.value < datum.end_value.value",
"as": "isIncrease"
}
],
isIncreaseの内容によって色を変えている例です。
"color": {
"field": "isIncrease",
"type": "nominal",
"scale": {"range": ["#ae1325", "#06982d"]},
"legend": null
}
参考資料
今回試したものの内容は、以下にあげてあります。
まとめと感想
- Vegaの記法、内容は知っておく必要がある。
- 基本はグラフにデータを渡す部分が、ElasticsaerchのAggregaionになっただけと考えれば、さほど構えることはない。
- https://vega.github.io/editor/#/ とにらめっこしながらやれば、何とかなる。
- プラグインがKibanaのメンテナンス速度についていってくれると、使う側はとてもうれしい。
自分の望むVisualizationを、プラグインを書くことで実現することもできるけれど、そこまで技術力高くないマン、Reactとかよく分からない非フロントエンドのエンジニアには、プラグインの拡充はうれしいですね!!!