Elasticsearch
kibana

Kibana でローソク足チャートを出してみる

追記

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を入れてやってみます。

どんなグラフが描けますか

https://vega.github.io/vega/

詳しくはこちらのサイト、Examplesから見ることができます。

A Visualization Grammar   Vega.png

で、今回はVega Liteの方にある「Candlestick Chart」を使ってみます。

Example Gallery   Vega Lite.png

先に結論

こんな画面を作ることができました。

ローソク足

ro soku   Kibana.png

移動平均線を追加

Kibana (2).png

環境構築

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」をダブルニープレス(選択)します。

d1.png

雛形の表示

標準で提供されているVisualizationであれば、選択後にはIndexやSaved Searchを選択する画面に遷移しますが、
Vegaの場合は、indexなどを指定する画面は表示されず、いきなりこのような画面となります。

初期表示時に、Dev Toolsのような画面が現れ、いきなり赤い文字でエラーのように見えると萎えます。
ざっと中身を眺めたあと、上部にある「JSON」ボタンを押すと、コメントがなくなりエラーは消えます。

d2.png

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
        }

参考資料

今回試したものの内容は、以下にあげてあります。

まとめと感想

  1. Vegaの記法、内容は知っておく必要がある。
  2. 基本はグラフにデータを渡す部分が、ElasticsaerchのAggregaionになっただけと考えれば、さほど構えることはない。
  3. https://vega.github.io/editor/#/ とにらめっこしながらやれば、何とかなる。
  4. プラグインがKibanaのメンテナンス速度についていってくれると、使う側はとてもうれしい。

自分の望むVisualizationを、プラグインを書くことで実現することもできるけれど、そこまで技術力高くないマン、Reactとかよく分からない非フロントエンドのエンジニアには、プラグインの拡充はうれしいですね!!!