フューチャー技術ブログ

Vis Networkで階層グラフを可視化する

はじめに

はじめまして、TIG コアテクノロジーユニットの山田です。

だいぶ前のことですが業務で階層グラフを可視化する機会があったので、階層グラフの可視化方法 について共有させていただこうと思います。

グラフとは関係を抽象化したもので、線グラフや棒グラフなどのチャートとは異なる概念です。グラフはノードとエッジで表現され、例えばSNSでのつながりを表すソーシャルグラフや関数の呼び出し関係を表すコールグラフなど様々な関係をグラフで表現できます。
(詳細はグラフ (データ構造) - Wikipediaを御覧ください)

グラフの可視化ツールと言えばGraphvizが有名ですが、サーバ側にバイナリ入れてプロセス起動する形になってしまうのでWebアプリでの利用には少し不向きです。

Webアプリで利用しやすい、JavaScript製のライブラリの代表的なプロダクトは例えば以下があります。

vis-network mxGraph D3.js mermaid
描画方式 canvas SVG canvas / SVG SVG
特徴 高性能 diagrams.net (旧 draw.io) で使われている 多機能 GitLabで標準利用可
ライセンス Apache License 2.0 / MIT License Apache License 2.0 修正BSDライセンス MIT License

この中で、本記事でははVis Networkを用いて階層グラフを表示する方法をご紹介します。

mxGraphについて次の記事で紹介する予定ですのでお楽しみに。

Vis Networkとは

vis.jsという可視化ライブラリに含まれるグラフ可視化ライブラリです。その中でもVis Networkはグラフの可視化に特化したライブラリで、Vis Network Examplesにあるように様々なグラフを描画できます。Vis Networkはcanvasに描画するため描画が高速で、パフォーマンスが要求される場面に有用です。 1

Vis Networkの使い方

Vis Networkでは表示するグラフの元となるノード、エッジ、オプションを定義する必要があります。

ノード定義

下記のようにノードを定義できます。

const nodes = new vis.DataSet([
{ id: 1, label: '1' },
{ id: 2, label: '2' },
{ id: 3, label: '3' },
{ id: 4, label: '4' },
{ id: 5, label: '5' },
{ id: 6, label: '6' },
{ id: 7, label: '7' },
{ id: 8, label: '8' },
{ id: 9, label: '9' },
{ id: 10, label: '10' },
{ id: 11, label: '11' },
{ id: 12, label: '12' },
]);

ノードに設定可能な属性一覧はvis.js - Nodes documentation.をご参照ください。

エッジ定義

from, toで指定したノードIDをつなぐエッジを作成します。

const edges = new vis.DataSet([
{ from: 1, to: 3 },
{ from: 1, to: 2 },
{ from: 2, to: 4 },
{ from: 2, to: 5 },
{ from: 3, to: 6 },
{ from: 3, to: 8 },
{ from: 6, to: 7 },
{ from: 6, to: 9 },
{ from: 4, to: 10 },
{ from: 4, to: 11 },
{ from: 5, to: 12 },
]);

エッジに設定可能な属性一覧はvis.js - Edges documentation.をご参照ください。

オプション定義

階層グラフを表示する場合、layoutオプションを指定する必要があります。その際、下記のようにsortMethod: 'directed'を指定することでグラフの形状から各ノードのレベルを自動計算してくれるので、ライトに可視化したい場合にはこのオプションを使用することをおすすめします。

const options = {
layout: {
hierarchical: {
sortMethod: 'directed'
}
}
};

オプションに設定可能な属性一覧はvis.js - Network documentation.をご参照ください。

可視化

上記のノード定義、エッジ定義、オプション定義を元に可視化できます。実際に可視化した例です。

ソースコードは [Edit fiddle \- JSFiddle \- Code Playground](https://jsfiddle.net/0bxLo6wt/) にて確認できます。

これだけでは寂しいので、少しグラフを加工していきましょう。

ノードの形状

ノード定義にshape属性を追加することで、ノードにラベルを表示することが出来ます。なお、ここでは紹介しませんでしたがshape: imageを指定することで任意の画像を表示することもできます。

const nodes = new vis.DataSet([
{ id: 1, label: '1' },
{ id: 2, label: '2', shape: 'database' },
{ id: 3, label: '3', shape: 'box' },
{ id: 4, label: '4', shape: 'text' },
{ id: 5, label: '5', shape: 'triangle' },
{ id: 6, label: '6', shape: 'diamond' },
{ id: 7, label: '7', shape: 'dot' },
{ id: 8, label: '8', shape: 'star' },
{ id: 9, label: '9', shape: 'triangle' },
{ id: 10, label: '10', shape: 'triangleDown' },
{ id: 11, label: '11', shape: 'hexagon' },
{ id: 12, label: '12', shape: 'square' },
]);
ソースコードは [Edit fiddle \- JSFiddle \- Code Playground](https://jsfiddle.net/3nkac917/) にて確認できます。

tooltip

tooltip(ツールチップ)とは、マウスオーバーした際に表示される枠内の補足説明などのことです。詳細はこちらの記事などを参考ください。

ノード定義にtitle属性を追加することでtooltipを表示することが出来ます。ドキュメントによるとHTMLを含む文字列を直接セット出来ると書かれていますが、XSS対策 2のため9.0.0からできなくなっています。

tooltipでHTMLを表示したい場合はVis Network | Other | Popupsのように HTML Element を直接セットする必要があります。

const nodes = new vis.DataSet([
{ id: 1, label: '1', title: 'tooltip\ntest' },
{ id: 2, label: '2', shape: 'database' },
{ id: 3, label: '3', shape: 'box' },
{ id: 4, label: '4', shape: 'text' },
{ id: 5, label: '5', shape: 'triangle' },
{ id: 6, label: '6', shape: 'diamond' },
{ id: 7, label: '7', shape: 'dot' },
{ id: 8, label: '8', shape: 'star' },
{ id: 9, label: '9', shape: 'triangle' },
{ id: 10, label: '10', shape: 'triangleDown' },
{ id: 11, label: '11', shape: 'hexagon' },
{ id: 12, label: '12', shape: 'square' },
]);
ソースコードは [Edit fiddle \- JSFiddle \- Code Playground](https://jsfiddle.net/rg50c2jh/) にて確認できます。

イベント

onメソッドで指定したイベントを処理するCallbackを登録することが出来ます。
下記のサンプルではクリックしたノードのcolor属性を変更します。

ソースコードは [Edit fiddle \- JSFiddle \- Code Playground](https://jsfiddle.net/hu2kts5y/) にて確認できます。

イベント一覧は vis.js - Network documentation. に記載されています。
イベント発生時に渡されるパラメータの中身を確認したり、実際にイベント発生させて試したい場合は Vis Network | Events | Interaction events がおすすめです。

dot言語からのインポート

Vis NetworkではGephiからエクスポートしたデータやdot言語をインポートできます。今回は私が先日Graphvizを用いて可視化したグラフ 3をVis Networkで表示してみます。

ソースコードは Edit fiddle - JSFiddle - Code Playground にて確認できます。

Graphvizほど洗練されたレイアウトにはなりませんが、非常に簡単にdot言語をインポートできました。

※ 上記画像ではVis Networkのノードやエッジのラベルが読み取れない状態になっていますが、Canvas上で拡大することでラベルを読み取ることが出来ます

注意

開発中にバージョンアップしたときに何も表示されなくなる不具合 4に遭遇したことがありました。このようなわかりやすい不具合ならまだいいですが、細かいところで挙動が変わってしまっている可能性もあるのでバージョンアップの際には十分な検証が必要かなと思います(どのソフトウェアにも言えることではありますが…)

課題

当初Vis Networkを使用していましたが、大きめの階層グラフを表示するとエッジの交差が非常に多くなってしまうことがわかりました。例えば下図はこれまでサンプルとして表示していたグラフにオレンジのエッジを一本追加しただけなのですが、エッジの交差が必要以上に多くなってしまっています。

ソースコードは Edit fiddle - JSFiddle - Code Playground にて確認できます。

私の所属しているプロジェクトでは比較的大きな階層グラフを表示する必要があり、この課題を解消するためmxGraphに乗り換えました。mxGraphではこのようにエッジの交差を減らすことができます。

次回の記事ではmxGraphをご紹介いたします。

  • 続きの記事もこちらに公開されました。併せて確認してもらえると嬉しいです!

階層グラフのレイアウト問題そのものに興味がある方は 階層グラフの可視化 などを見ると楽しめるかなと思います。

まとめ

vis.jsを使い、ライトに階層グラフを表示・加工出来ることがわかりました。残念ながら私達の用途には合いませんでしたが、適切なシーンで使用すればとても有用なライブラリだと思います。

コアテクノロジーユニットでは、現在チームメンバーを募集しています。興味がある方はお気軽に技術ブログTwitterや会社採用HPへ、連絡をお待ちしております。

https://www.future.co.jp/recruit/