【QuickSight】Highchartsを使って複数の面グラフと折れ線グラフを出してみる。
先日、QuickSightでHighchartsが使用できるアップデートがありました。
こういうの欲しいなとずっと思っていた、面グラフと折れ線グラフをいっぺんに出してみるようなものを作成しながら触ってみました。一個の方法だと思ってみていただければと。
最終的にはこんなビジュアルです。
パラメータを切り替えるとこんな感じ。
使用したテストデータ
時間 | 気温 | 週 | 行動 |
---|---|---|---|
12:00 | 16.8 | 1 | |
12:01 | 17.8 | 1 | スマホ |
・・・ | ・・・ | ・・・ | ・・・ |
12:59 | 12.8 | 3 | 資料作成 |
という形で、どの時間にどのような行動をしたのかを面グラフで表し、その時の気温を折れ線グラフで表示して、表示する行動の面グラフは週のコントロールで指定する。みたいな感じです。
作成したHighchartsのJSON
{
"chart": {
"type": "area"
},
"xAxis": {
"type": "datetime",
"categories": ["unique", ["getColumn", 0]],
"tickInterval":5
},
"yAxis": {
"title": {
"text": "気温"
},
"min":10
},
"tooltip": {
"shared": true,
"pointFormat": "<span style=\"color:{series.color}\">\u25CF</span> {series.name}: <b>{point.y:,.1f}°</b><br/>"
},
"series": [
"+",
[
"map",
["unique", ["getColumn", 1]],
{
"name": ["item"],
"data": [
"map",
[
"filter",
["getColumn", 1, 2, 3, 4],
["==", ["get", ["item"], 2], ["get", ["item"], 3]]
],
[
"case",
["!=", ["get", ["item"], 0], ["item", 2]],
null,
["==", ["get", ["item"], 0], ["item", 2]],
["get", ["item"], 1]
]
]
}
],
[
"map",
["unique", ["getColumn", 3]],
{
"type": "line",
"name": ["item"],
"data": [
"map",
[
"filter",
["getColumn", 3, 5],
["==", ["get", ["item"], 0], ["item", 2]]
],
["get", ["item"], 1]
],
"color": [
"case",
["==", ["item"], 1],
"#ff6347",
["==", ["item"], 2],
"#4169e1",
["==", ["item"], 3],
"#3cb371"
],
"dataLabels": {
"enabled": true,
"format": "{point.y}°",
"style": {
"color": "rgba(0, 0, 0, 0.7)",
"fontSize": "11px",
"fontWeight": "bold"
},
"align": "center",
"verticalAlign": "middle"
}
}
]
]
}
使用したパラメータと計算フィールド
・パラメータは、week
という数値のデータで、週を変更するために使用しています。
・計算フィールドは3つ
- params-week
→現在のパラメータの数値を格納するだけ
- params-何もしていない
→パラメータで指定している週の行動
のカラムが空白の時に0にして、何か文字列が入っている場合、気温
の値を入れる
- params-行動
→パラメータで指定している週の行動
を表示するようにする
${week}
ifelse(
週=${week}, ifelse(行動="",0,気温),NULL
)
ifelse(
週=${week},行動,NULL
)
ディメンションはこの順番で追加しています。
作成したJSONの解釈
x軸とかy軸とかの話
"chart": {
"type": "area"
},
"xAxis": {
"type": "datetime",
"categories": ["unique", ["getColumn", 0]],
"tickInterval":5
},
"yAxis": {
"title": {
"text": "気温"
},
"min":10
},
"tooltip": {
"shared": true,
"pointFormat": "<span style=\"color:{series.color}\">\u25CF</span> {series.name}: <b>{point.y:,.1f}°</b><br/>"
}
・xAxis
は、X軸をコントロールしている部分で、どのデータをX軸として指定しているかは、
"categories": ["unique", ["getColumn", 0]]
の箇所でやっています。["unique", ["getColumn", 0]]
この書き方で、["getColumn", 0]]
の値の個別の値を表示するというような感じですかね。
tickInterval
はステップカウントのようなものです。
・yAxis
は、y軸をコントロールしている部分で、タイトルを気温にして、最小の値を10に設定しています。
・tooltip
は、ツールチップに何を表示するのか。をやっており、shared
にすることにより、関連するデータをすべて表示するようにしています。
データの表示方法を指定する部分
"series": [
"+",
[
"map",
["unique", ["getColumn", 1]],
{
"name": ["item"],
"data": [
"map",
[
"filter",
["getColumn", 1, 2, 3, 4],
["==", ["get", ["item"], 2], ["get", ["item"], 3]]
],
[
"case",
["!=", ["get", ["item"], 0], ["item", 2]],
null,
["==", ["get", ["item"], 0], ["item", 2]],
["get", ["item"], 1]
]
]
}
],
[
"map",
["unique", ["getColumn", 3]],
{
"type": "line",
"name": ["item"],
"data": [
"map",
[
"filter",
["getColumn", 3, 5],
["==", ["get", ["item"], 0], ["item", 2]]
],
["get", ["item"], 1]
],
"color": [
"case",
["==", ["item"], 1],
"#ff6347",
["==", ["item"], 2],
"#4169e1",
["==", ["item"], 3],
"#3cb371"
],
"dataLabels": {
"enabled": true,
"format": "{point.y}°",
"style": {
"color": "rgba(0, 0, 0, 0.7)",
"fontSize": "11px",
"fontWeight": "bold"
},
"align": "center",
"verticalAlign": "middle"
}
}
]
]
getCloumnの整理
・["getColumn", 0] → 時間
・["getColumn", 1] → params-行動
・["getColumn", 2] → params-何もしていない
・["getColumn", 3] → 週
・["getColumn", 4] → params-week
・["getColumn", 5] → 気温
面グラフの部分
[
"map",
["unique", ["getColumn", 1]],
{
"name": ["item"],
"data": [
"map",
[
"filter",
["getColumn", 1, 2, 3, 4],
["==", ["get", ["item"], 2], ["get", ["item"], 3]]
],
[
"case",
["!=", ["get", ["item"], 0], ["item", 2]],
null,
["==", ["get", ["item"], 0], ["item", 2]],
["get", ["item"], 1]
]
]
}
]
上から読んでいくと、まずmap
で「行動」の文字列のユニークの数だけ回します。name
は「行動」の文字列から取得して、data
に関しては、filter
を使用してパラメータで指定しているweekの値と「週」のカラムが同じものだけフィルタリングして、さらに、case
で、上位の["unique", ["getColumn", 1]]
で選択されている、「行動」の文字列と同じ場合は「気温」のデータにしてそのほかをNULLにするといった形です。
["get", ["item"], 2]
とかで指定している配列の番号は、["getColumn", 1, 2, 3, 4]
の時の配列と対比しています。なので、["get", ["item"], 2]
でいうと["getColumn", 3]
みたいな感じです。
例えばではありますが、「行動」が"仕事"になっているときのmap
で書かれる、面グラフはこんな感じです。
これを「行動」のユニーク分回して表示しているような感じです。
折れ線グラフの部分
[
"map",
["unique", ["getColumn", 3]],
{
"type": "line",
"name": ["item"],
"data": [
"map",
[
"filter",
["getColumn", 3, 5],
["==", ["get", ["item"], 0], ["item", 2]]
],
["get", ["item"], 1]
],
"color": [
"case",
["==", ["item"], 1],
"#ff6347",
["==", ["item"], 2],
"#4169e1",
["==", ["item"], 3],
"#3cb371"
],
"dataLabels": {
"enabled": true,
"format": "{point.y}°",
"style": {
"color": "rgba(0, 0, 0, 0.7)",
"fontSize": "11px",
"fontWeight": "bold"
},
"align": "center",
"verticalAlign": "middle"
}
}
]
上から読んでいくと、まずmap
で「週」のユニークの数だけ回します(今回は3回)。type
でline
を指定して折れ線グラフを描きます。name
を「週」の数にして、data
に関しては、
map
で回している「週」のデータをfilter
でフィルタリングしています。それぞれの折れ線グラフを色をcolor
で指定していて、case
でそれぞれ分岐させます。dataLabels
で折れ線グラフにデータラベルを貼り付けます。
それぞれを合体
この面グラフと折れ線グラフを、series
の中に、+
でつなぎます。
"series": [
"+",
//面グラフのJSONコード
,
//折れ線グラフJSONコード
]
さいごに
このアップデート自由度は跳ね上がった感じがしますが、なれるまで一個のビジュアルを作るのに結構時間かかっちゃう。
私の解釈が間違ってたらすみません。あくまでpreview中の一例としてみてください。
Discussion