Vega解説 ~全体グラフと詳細グラフ~


Vega[^1] 解説記事です。今回作成する図はサンプルの以下のグラフ([リンク](https://vega.github.io/vega/examples/overview-plus-detail/)）です。
詳細ビュー（上）と全体ビュー（下）に分かれており、全体ビューをマウスで範囲選択（赤線枠内）すると、詳細ビューに選択された範囲が表示されます。今までのグラフと比べると急に複雑になっていますので、６ステップに分けて説明します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51316/60f0b451-e94f-54b2-74c7-34fbd42d0eb5.png)


他の解説記事は以下になります。

* [Vega解説 〜離散データ〜](https://qiita.com/ihgs/items/87fda0cd39693bae44f3)
* [Vega解説 〜動的なグラフ〜](https://qiita.com/ihgs/items/7715bd7f6d2f7987f73a)
* [Vega 解説 ~時系列データを処理する~](https://qiita.com/ihgs/items/05e10b9f20faa002be18)
* [Vega解説 〜凡例〜](https://qiita.com/ihgs/items/bb222824f42969317b5d)
* [Vega解説 〜基準線をひく〜](https://qiita.com/ihgs/items/e69927315cb801cb63bc)
* [Vega解説 〜複数グラフ〜](https://qiita.com/ihgs/items/8a54c56929bf67327629)


[^1]: Vega はjsonでデータや描画の設定を記述することで、視覚化できるツール。[いろんなグラフ](https://vega.github.io/vega/examples/)を表現できます。

### ステップ１：複数グラフを描画


[Online Editor で開く](https://vega.github.io/editor/#/gist/748dd096e9daaf85763a798cd5f63256/step0.json)

まず、複数グラフを表示する様にします。
`marks` にgroupを２つ定義し、x軸は同じだがy軸の高さがちがう２つのグラフを表示します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51316/40ffe4b4-f523-3e37-b951-fdfa8678df10.png)


上が詳細下が全体グラフとし、それぞれのグラフにmarks, signals を指定できます。
後の工程で上記に定義を加え機能を追加していきます。


なお、データは、vega のgithub上にあるデータ [data/sp500.csv](https://github.com/vega/vega/blob/master/docs/data/sp500.csv) を利用します。これを使うことでオンラインエディタでも確認が可能です。
VSCode のvega pluginで表示する場合は、上記データをダウンロードしてspecファイルで指定しているパスに置いておきます。



### ステップ２：詳細グラフの表示範囲を変えてみる

[差分](https://ihgs.github.io/online-diff/?diff=ihgs/748dd096e9daaf85763a798cd5f63256/raw/step0.json...ihgs/748dd096e9daaf85763a798cd5f63256/raw/step1.json)
[Online Editor で開く](https://vega.github.io/editor/#/gist/748dd096e9daaf85763a798cd5f63256/step1.json)


詳細グラフ(上)のx軸に適用するスケール `xDetail` に `domainRaw` を設定します。
`domainRaw` が設定されている場合、その値がnullでない場合、`domain` より優先されて利用されます。

ここでは、`domainRaw` に signalの `detailDomain` を指定しておきます。値を設定しておかなければ全体が表示されますが、値があればその指定された範囲でグラフが表示されます。

画像は、わかりやすい様に初期値を設定してあります。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51316/af26f2b3-0276-00a2-4190-d9b55f4fc560.png)





### ステップ３：全体グラフのアクションで詳細グラフの表示範囲を変えてみる

[差分](https://ihgs.github.io/online-diff/?diff=ihgs/748dd096e9daaf85763a798cd5f63256/raw/step1.json...ihgs/748dd096e9daaf85763a798cd5f63256/raw/step2.json)
[Online Editor で開く](https://vega.github.io/editor/#/gist/748dd096e9daaf85763a798cd5f63256/step2.json)


全体グラフ(下)に範囲枠を追加します。

まずは、固定した領域を表示し、この領域をクリックすると先ほど追加した `detailDomain` の値を更新し、それにより詳細グラフの表示領域を変更する様にします。

固定した領域のために 全体グラフのsignal に `brush` を定義します。 全体グラフのmarksに `brush` の値に従って、表示する四角を表示する様にします。

また、全体グラフのsignal に `detailDomain` を定義します。ここで、`push` を指定することで、トップで定義した signal の`detailDomain` にもデータを反映できる様にします。さらに、brushの四角のマウスダウンイベントを契機にデータが更新されるようにイベント設定を追加します。 


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51316/98dcf596-e5c6-336b-9f52-c4c52adbdbae.png)



### ステップ４：マウスで範囲を指定できるようにする

[差分](https://ihgs.github.io/online-diff/?diff=ihgs/748dd096e9daaf85763a798cd5f63256/raw/step2.json...ihgs/748dd096e9daaf85763a798cd5f63256/raw/step3.json)

[Online Editor で開く](https://vega.github.io/editor/#/gist/748dd096e9daaf85763a798cd5f63256/step3.json)


全体グラフに、mousedownした地点のデータを設定するイベントと、mousedownしてから、mouseupするまでの動きで `brush`  のデータを設定するイベントを追加します。
また、brushにイベントが発生したときに、`detailDomain` を更新するイベントも追加します。
これにより、全体グラフで発生したイベントを詳細グラフに伝えています。
また、範囲の幅がなくなった時(span(brunsh): brushの最初の要素と最後の要素の差が０）に詳細グラフが消えないように、`detailDomain` を null にします。


![chrome-capture.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51316/3c0d8dbe-82e9-5e2d-e141-0056c7b75af2.gif)




### ステップ５：範囲箱をドラッグして動かせるようにする

[差分](https://ihgs.github.io/online-diff/?diff=ihgs/748dd096e9daaf85763a798cd5f63256/raw/step3.json...ihgs/748dd096e9daaf85763a798cd5f63256/raw/step4.json)
[Online Editor で開く](https://vega.github.io/editor/#/gist/748dd096e9daaf85763a798cd5f63256/step4.json)

全体グラフの灰色の四角（`brush`) にmousedownされたときに、brushのコピー(`anchor`)とmousedownした位置(`xdown`) を記録します。さらに、mousedownしてからmouseupするまで動かした時にその動かした距離(`delta`)を記録します。
`brush` のイベントに、上記の `delta` が更新された時に、brushのデータを更新するイベントも追加します。その際に、brushがグラフの外に出ないようにします(`clampRange([anchor[0] + delta, anchor[1] + delta], 0, width)` 。


![chrome-capture (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51316/e0e035c0-b791-dd0d-6752-25d2b58ccd27.gif)




### ステップ６：範囲箱を目立たせる

[差分](https://ihgs.github.io/online-diff/?diff=ihgs/748dd096e9daaf85763a798cd5f63256/raw/step4.json...ihgs/748dd096e9daaf85763a798cd5f63256/raw/step5.json)
[Online Editor で開く](https://vega.github.io/editor/#/gist/748dd096e9daaf85763a798cd5f63256/step5.json)

全体グラフの灰色の四角の開始と終了の地点に赤い枠をつけ、brushの初期値を0にしておくと完成です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51316/18b38d0d-b6f1-e19b-e59d-f6aefb0fe1a6.png)