鉄道路線データをグラフとしてCytoscapeで可視化する 4: 東京メトロのデータを例に

# はじめに

このシリーズは、[Cytoscape](http://www.cytoscape.org/)を使ってや[IPython Notebook](http://ipython.org/notebook.html)、[Pandas](http://pandas.pydata.org/)などのオープンソースツールを利用し、公開データを元に実際のグラフ可視化を行う過程を紹介する、可視化の実践者向けの記事です。

* [第一回](http://qiita.com/keiono/items/29286f49b15a5b13c987)
* [第二回](http://qiita.com/keiono/items/5e43bc93f17eb22250ab)
* [第三回](http://qiita.com/keiono/items/85cbb721467709113e2f)
* [第四回](http://qiita.com/keiono/items/c9d31ddb0beeea9af840)


![](http://cl.ly/X4z8/metro3.png)


最終回は、グラフ可視化で重要なレイアウトとスタイル設定、そしてCytoscapeで作成したデータの他のアプリケーションでの利用について紹介します。


## 東京メトロのアプリコンテスト
このシリーズでは、どなたにも馴染みのあるデータとして[鉄道路線図のグラフデータ](http://www.ekidata.jp/)を例として利用しました。全くの偶然ですが、まもなく[東京メトロ](http://www.tokyometro.jp/index.html)が運行状況などの各種情報を[JSON-LD](http://json-ld.org/)として公開し、アプリケーションコンテストを行うと発表しました:

* [オープンデータ活用コンテスト](http://tokyometro10th.jp/future/opendata/index.html)

これは[コンテスト参加者しか利用できないデータなので、真の意味でのオープンデータではない](http://itpro.nikkeibp.co.jp/atcl/watcher/14/334361/090200044/)のですが、それはまあ今後に期待ということで。せっかくなので、先日作成した東京メトロのデータセットを例に、レイアウトやスタイリングでどのように見え方が変わるのかを紹介したいと思います。ここで作成した基本的なグラフ可視化結果にAPIから取得した各種データを各種視覚変数にマッピングすることで、最終的なアプリケーション作成の前に、基本的なデザインやレイアウトを確認するのにも使えると思います。まだデータの詳細が発表になっていないので、コンテストで利用できる実際のデータを使用することは出来ませんが、可視化の方針が路線図データを元に、そこへ各種情報、すなわち電車の位置、遅延、時刻表等をマッピングするというものでしたら、ここで解説してある基本的なここで解説してある基本的なテクニックは、実際のデータでも問題なく利用できると思います。

また最後に触れますが、私達のプロジェクトで作成しているネットワーク可視化JavaScriptライブラリのCytoscape.jsや、D3.jsのForceレイアウトで利用できるJSON形式でデータを書き出すことも可能ですから、最終的に作成するウェブアプリで利用するデータの作成ツールとしても使えます。


# レイアウトとスタイルを使いこなす
グラフ可視化において、各種アルゴリズムを利用した自動__レイアウト__とデータを視覚変数にマッピングする__スタイル__の作成は重要なステップです。今回はこれをCytoscapeでどのように行うかを見ていきます。

### 利用するデータセット
手元で実際に試せるように、前回までに作成したデータを元にしたCytoscape用のセッションファイルを用意しましたので、これを使います。統合した全国版のデータを、東京メトロの部分だけ切り出したものです:

* [東京メトロ路線+乗降客数データ](http://cl.ly/XQ3Q/tokyo_metro_start.cys)　（Cytoscape3.1用セッションファイル）


## スタイル作成

### Review: スタイルとは？
Cytoscapeでは、可視化に使われるマッピングの集合を__*Visual Style*__と呼んでいます。これは2つの要素に分解できます:

* デフォルト値 - 何のマッピングも存在しない時に使われる値
* マッピング - データから視覚変数（Cytoscapeでは__*Visual Property*__と呼ばれます）への変換

この2つを上手く調節して行くことにより最終的な可視化を作成します。

### 実際のスタイル作成
今回の可視化のテーマは、ビギナー用の簡単な例として__「銀座線、丸ノ内線、東西線の各駅の2012年度の一日あたりの平均乗降客数を見やすく提示する」__とします。このゴールに向かってレイアウトとスタイルを決定していきます。

まず上のリンクからダウンロードしたセッションファイルを開くと、必要最小限のマッピングが設定されたデータが表示されます:


![minimal_style1.png](https://qiita-image-store.s3.amazonaws.com/0/20688/034c321d-6ba2-4eea-8069-ae3a14e0c112.png)

この状態では何のデータかよくわかりませんね。ここでは、ほとんど何のマッピングも設定されていません。ここから必要な値を設定することにより、より分かりやすい見た目に加工していきます。まずは「過剰な装飾を避けるため、本当に必要のある視覚要素以外は極力削ぎ落とす」と言う方針に則り、ノードの境界線（Nord Border）を削除したいと思います。これは、_Node Border Width_のデフォルト値をゼロに設定するだけです（Def.以下にある四角いエリアをクリックすることで値を入力できます）:


![border1.png](https://qiita-image-store.s3.amazonaws.com/0/20688/6dd2c182-e473-3328-8e36-e0841eb1900e.png)

すると見た目は以下のように変化します:


![minimal_style.png](https://qiita-image-store.s3.amazonaws.com/0/20688/e0e7b4f9-fe17-7d01-29cd-0590f6de9cba.png)


この「白地図」に各種データをマッピングしましょう。


### Passthrough Mapping
このサンプルでは、予め一つだけマッピングが設定されています。それは、駅名（__*station_name*__）と言うデータからノードラベル（__*Node Label*__）と言う視覚変数へのPassthroughマッピングです。前回も触れたように、Passthroughは単純にデータの値を視覚変数にそのまま渡すだけです。つまりこの場合は、「__station_nameと言うカラムに存在する値を、そのままノードのラベルとして描け__」と言う意味です。

ではここで実際にこのタイプのマッピングを設定しましょう。今回のデータは、前々回に収集した路線ごとの色データ（_line_color_と言う名前のカラム）も含みますので、それを使ったPassthroughマッピングを設定します。

* __line_color__から__Node Fill Color__へ
* __line_color__から__Edge Stroke Color (Unselected)__へ


![colorpt1.png](https://qiita-image-store.s3.amazonaws.com/0/20688/e8f351ca-37b7-7722-3f8f-361c6284eccd.png)  ![colorpt2.png](https://qiita-image-store.s3.amazonaws.com/0/20688/7f14fc0c-dd2b-7e7c-7220-2f06e12ae6c0.png)

すると、16進数で指定された色がそのままノードとエッジの色に反映されます:

![minimal_style2.png](https://qiita-image-store.s3.amazonaws.com/0/20688/5b6e988a-0cac-1ae4-a2f1-69f24199e7a9.png)


### デフォルト値の変更
次はマッピングの必要のない要素の初期値を調整することにより、全体をより見やすく調整します。

* ノードの形を円形に変更　- Node Shapeを_Ellipse_（楕円）に。
* 路線図らしく、各路線を太い線で表現 - Edge Widthを20へ。

これで見た目は以下のように変化します:

![minimal_style3.png](https://qiita-image-store.s3.amazonaws.com/0/20688/64d6ddf7-1541-0772-7128-eb9f4f8fbc15.png)

ではここで一度自動レイアウトを適用して繋がりを見やすくしましょう。ここでは、yFiles社の開発したプロプライエタリな自動レイアウトアルゴリズムであるOrganicレイアウトを使ってみます:

![organic.png](https://qiita-image-store.s3.amazonaws.com/0/20688/57832007-7877-8492-7411-deb8b59b1e54.png)


![metro_layout1.png](https://qiita-image-store.s3.amazonaws.com/0/20688/6b773069-e2a0-9482-1262-261b5580bbfe.png)

ここでは駅の配置は純粋にグラフとしてのつながりを元に計算されていますので、地理的な位置などは一切考慮されていません。


### Discrete Mappingによる乗り換え可能を示すエッジの区別
[第二回](http://qiita.com/keiono/items/5e43bc93f17eb22250ab)で、元となったデータ内に含まれている駅グループの情報を用いて、乗り換え可能を表すエッジを追加しました。これを他のエッジと区別するマッピングを作成します。これには__*Discrete Mapping*__を使用します。__*Interaction*__と呼ばれるエッジのタイプを示すカラムを使い、ここに含まれる__0__と言う乗り換え可能を表す値に細い点線を表示するようにマップします。すなわち、

* Interactionの値が０ならば:
    * Edge Line Typeを点線に
    * Edge Widthを２に

と言う簡単な命令をDiscreteマッピングで作ります:


![スクリーンショット 2014-09-07 20.31.43.png](https://qiita-image-store.s3.amazonaws.com/0/20688/ea7b7def-18e5-9ebd-bcb0-325542bd9199.png) ![スクリーンショット 2014-09-07 20.31.58.png](https://qiita-image-store.s3.amazonaws.com/0/20688/9f341528-a75a-85dc-a9e6-a5ca5e80890f.png)


これにより、他のエッジに比べて、徒歩での乗り換え可能を意味する特殊なエッジが細い点線で表示されます:


![minimal_style4.png](https://qiita-image-store.s3.amazonaws.com/0/20688/33579de1-b7d8-492a-bc97-3200ed69af05.png)


## レイアウト
ここでは、自動レイアウトがどのようなものかを試してみましょう。以下は、Layoutメニュー以下から選択できる各種自動レイアウトアルゴリズムをこの東京メトロのネットワークに適用したものです:

#### Circular
円形にノードを配置するレイアウト。とても単純なアルゴリズムなので、大規模なネットワークにも利用できます。
![circular.png](https://qiita-image-store.s3.amazonaws.com/0/20688/fdfd3f9e-3f68-b11c-ae1a-08db7f120520.png)


#### Force-Directed
いわゆる[力学モデル](http://ja.wikipedia.org/wiki/%E5%8A%9B%E5%AD%A6%E3%83%A2%E3%83%87%E3%83%AB_(%E3%82%B0%E3%83%A9%E3%83%95%E6%8F%8F%E7%94%BB%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0))を利用したアルゴリズムで、ネットで見られるグラフ描画のサンプルの多くはこれでレイアウトしてあります。多くの場合うまく行くのですが、大変重い計算なので、大規模グラフには非常に長い時間を要します。
![force-directed.png](https://qiita-image-store.s3.amazonaws.com/0/20688/625494ee-2d95-dcbd-796c-5af5680f6757.png)


#### Hierarchical
階層的な構造を持ったデータに適しますが、そうでないものも強引にツリー状に並べることも可能です。
![hir.png](https://qiita-image-store.s3.amazonaws.com/0/20688/3f0f39a6-8370-db66-58f4-31f58b2b35ef.png)


### レイアウトアルゴリズムの選択
どのレイアウトアルゴリズムを選択するかは純粋に最終的な可視化をどのようなものにしたいかというゴールによります。一般的に、このような地理データに対して自動レイアウトを行えば、地図上での位置関係は失われます。しかし、抽象化された接続図と言う物を可視化し、そこに各種データをマッピングするのならば、実際の位置関係よりも、以下の様な抽象化されたモノのほうが都合のいい場合が多いです。

![](http://www.tokyometro.jp/news/2009/img/2009-59_2.jpg)
(東京メトロの作成した丸ノ内線の手書き路線図)

その場合、__選択した部分ごとに各種レイアウトを利用し、データマッピングに適した形に仕上げる__のがベストです。



### マニュアルレイアウト
この他にも、手動で微調整を行うときに利用するマニュアルレイアウトと言う機能もあります。Illustratorをお使いの方ならお馴染みの、指定したオブジェクトを整列させたり、拡大、回転などを行う機能です。後ほど例の中で使用します。


## 数値を視覚変数にマッピングする: Continuous Mapping
ここでは、今回のメインである乗降客数を利用するマッピングを作成します。安直ですが、2011年度の乗降客数を以下のVisual Propertyにマッピングします。

* ノードの大きさ
* ラベルの文字の大きさ

ここでは乗降客数という数値を大きさに変換するので、Continuous Mappingを使用します。以下のように、最大値と最小値に対してマッピング先の値を指定することにより、シンプルな線形のマッピングを作成できます:

![cont1.png](https://qiita-image-store.s3.amazonaws.com/0/20688/390b9680-44c4-306f-a479-0568543851eb.png)


![cont2.png](https://qiita-image-store.s3.amazonaws.com/0/20688/680bcdb4-e365-eea0-7f8d-c9bea8b96aa8.png)


結果、乗降客数が多いほど大きなノード、大きなラベルで表示される図が作成されます:

![cont_final.png](https://qiita-image-store.s3.amazonaws.com/0/20688/76bc1c4e-de89-34f9-2a1d-d904b4b5e7be.png)


## サブグラフ切り出しと加工
ここで、最終的に必要な三路線を切り出します。検索窓に以下のクエリを打ち込んでエンターを押すと、目的のノードが選択されます:

```
銀座線 OR 丸ノ内線 OR 東西線
```
と入力して、CTR+N （Macの場合はCommand+N）で切り出せます。これにyFiles&rarr;hierarchicレイアウトを適用すると以下のようになります:


![comparison1.png](https://qiita-image-store.s3.amazonaws.com/0/20688/9e39f13d-0f3e-b190-4494-383ffeb9ac5a.png)


ここからの仕上げは手動で作業を行います。プルダウンメニューから__Copy Style__を選んで、新しいスタイルをこのサブグラフ向けに作成しましょう:


![copy.png](https://qiita-image-store.s3.amazonaws.com/0/20688/711244b6-4722-d105-9d23-12d2864abc8c.png)


#### スケーリング
横軸が詰まりすぎているので、幅を広げて見やすくします。__Layout &rarr; Scaling__で表示されるパネルを利用します。X軸方向のスケーリングを選択し、見やすくなるように8倍程度まで広げます。ちなみに、Reset scale barをクリックすれば、そこからまた拡大できるので、いくらでも大きく出来ます。

![scaling.png](https://qiita-image-store.s3.amazonaws.com/0/20688/dfad0b4a-f28d-c70e-0594-d57f2a7ad359.png)

#### ラベル位置の変更
ラベルを見やすい位置に移動します。これは__Node Label Position__というVisual Propertyのデフォルト値を変更することで行います。デフォルトの状態では表示されていないと思うので、まず__Properties__の一覧から選んで表示させます:

![prop.png](https://qiita-image-store.s3.amazonaws.com/0/20688/0ef8998c-3459-6068-3a70-5a5beb59369a.png)

そして位置をドラッグ＆ドロップで決めたあとに、X方向のオフセット値で微調整します:

![labelpos.png](https://qiita-image-store.s3.amazonaws.com/0/20688/f81f2e38-1e26-1ada-71bb-eaf2df46826e.png)



#### 整列
拡大することにより各路線がずれてしまっていると思うので、これを修正します。路線ごとにドラッグで選択して、__Aligh & Distribute__のパネルから縦方向の串刺しアイコンを選べば自動整列します:


![aligh.png](https://qiita-image-store.s3.amazonaws.com/0/20688/d6cbd1e2-efa8-b5bc-fc95-adfad488747d.png)

必要に応じて細部を調整して、最終的には以下の様なものに仕上げます:

![](http://cl.ly/XQLM/comparison_final.png)
（ハイレゾ版は[こちら](http://cl.ly/XQLM/comparison_final.png)）

簡単な描画ですが、とりあえずどの駅が乗降客が多いか、をざっと把握することは出来ると思います。なお、データの無い駅については小さく表示して混乱を招かないようにしてあります。

* [マッピング作成済みのセッションファイル](http://cl.ly/XPD7/tokyo_metro_final.cys)
* PDFに出力したものは[こちら](http://cl.ly/XQIW/comparison_final.pdf)


これはマッピング機能（Visual Style）を学ぶための単純な可視化の一例に過ぎませんので、上のリンクからダウンロードしたセッションを色々といじってみて、マッピングをどう変更するとそれがどう可視化に反映されるのかを調べてみてください。以下は同じセッションから作った別のサンプルです:

![](http://cl.ly/XQ2m/mod1.png)

([full res](http://cl.ly/XQ2m/mod1.png))


![](http://cl.ly/XPM6/mod2.png)

([full res](http://cl.ly/XPM6/mod2.png))



# Webアプリケーションとの連携

![spa.png](https://qiita-image-store.s3.amazonaws.com/0/20688/fceff361-5385-0ef1-4a58-39c1d1ed55c0.png)


Cytoscapeでこういったスケッチを作成した場合、何も画像としてのスケッチだけで終わらせる必要はありません。私達の長期的なビジョンとして、今存在する様々な著名ツール（D3.js、Pandas、igraph等の可視化や解析のためのツール群）との連携は重要な項目の一つで、できるだけ一般的な形式でのデータ書き出しをサポートしています。

## Cytoscape.js用JSON形式への書き出し
[Cytoscape.js形式のJSONとしてネットワークとスタイルを書き出すことが出来ます](http://wiki.cytoscape.org/Cytoscape_3/UserManual/CytoscapeJs)。これらは直接Cytoscape.jsでレンダリング可能です。また、これらはシンプルなJSONファイルに過ぎませんので、ちょっとした処理を加えれば、他の様々なアプリケーションで利用できると思います。

### どうやってJavaオブジェクトをCytoscape.js用のJSON形式にしているのか？
CytoscapeはJavaで書かれたデスクトップアプリケーションで、ネットワーク、テーブル、そしてスタイルも全部Javaオブジェクトです。これらをそのままJackson等のデータマッパを使ってもCytoscape.js形式には上手く変換できませんので、書き出しはカスタムシリアライザを作成してJSONを作っています。特にスタイルは、[Cytoscape.jsのCSSのセレクタ](http://cytoscape.github.io/cytoscape.js/#selectors/data)形式に各マッピングを変換するため、マッピングの設定によってはとても効率の悪いセレクタが生成されます。__JSON形式へのスタイル書き出しを行う場合、Passthrough形式で指定したものが最も効率のいいセレクタを生成します__。これはCytoscapeで可視化を作成するときのベストプラクティスではないのですが、最終的にはCytoscape.jsでの利用を考えている場合、これは頭の隅に置いておくと良いでしょう。

## D3.jsのForce形式での書き出し
[このApp](http://apps.cytoscape.org/apps/d3jsexporter)を使うことにより、D3.jsのForceレイアウトで直接使えるデータ形式に書き出すことも可能です。

### D3.jsとグラフデータ
[D3.js](http://d3js.org/)には「元になるデータのフォーマットに関する制約は最小限にする」と言う思想があるようです。基本的にはCSVなどのテーブル形式でデータを用意すればほとんどの場合はそのまま読み込めます。そんな中グラフ形式のデータに関しては、並び順(ordinal)をIDとみなすという、冗長性は少なくなる一方、若干可読性に欠ける方式となっています。もちろんそれでもシンプルなので、ちょっとしたスクリプトを書いてしまえば済む作業ですが、目で見ながらグラフィカルにグラフ構造をエディットし、それを自動的に書き出せたらそれも便利です。[D3.js Exporter](http://apps.cytoscape.org/apps/d3jsexporter)は、Cytoscape上で動くプラグイン(App)で、読み込まれたグラフのトポロジと属性データをそのままD3.jsで読み込める形式に書き出すものです。

### D3.jsで簡単に読める形式への書き出し
Appをインストールしたあとは、__*File &rarr; Export &rarr; Network*__で、ファイル名を指定してD3.js形式のフォーマットを選択するだけです。書き出しの結果は[こんな感じになります](https://gist.github.com/25c9ef2cf0bb99efaa5d)。

### D3.js側の基本的なコード
D3.js上で、このJSONに含まれるデータを使ったマッピングを作るのは簡単です。例えば、2012年度の乗降客数データをそのままノードの大きさにマッピングする場合、返り値を半径にマップするだけです:

```js
node.append("circle")
    .attr("class", "node")
    .attr("r", function(data) {
        return data.passengers2012;
    });
```

この辺りは大量にサンプルが出回っているので、D3.jsとForce Layoutで検索してみてください。D3.jsで可視化を作成する場合、D3.jsでデータを準備したり加工するのはナンセンスですから、IPython Notebook, Pandas, Cytoscape辺りを組み合わせてデータの下準備をしておくと便利だと思います。D3.js側でのコードは上記のようなマッピングや、トランジションといった部分に集中できますので。

#### D3.jsの使いどころ
リンクした下の例を見ていただければお分かりになると思いますが、__JavaScriptでグラフ（ネットワーク）を描画する、と言うだけでしたら、Cytoscape.jsなどを使う方がはるかにコード量も少ないですし、APIの抽象度も高レベルで簡単です__。しかし、単なるnode-link diagramを超えた新しい可視化を試したいような場合は、D3.jsのローレベルさが逆に便利です。例えば、D3.jsのTransitionを上手く使って、node-link図とTreemapを切り替え可能にしたりといった場合です。また、D3.jsはデフォルトではSVGで描画する場合がほとんどでしょうから、最終的な出力が紙などの場合もこれは便利な点です（Cytoscape.jsを含むグラフ可視化ライブラリのほとんどがCanvasを利用していますので）。


## Single Page Applicationとしての書き出し
これはまもなくリリースされるCytoscape 3.2.0の新機能なのですが、バラバラにJSONファイルを書き出す代わりに、プリセットのWebアプリケーションとして書き出す機能があります。要するに、サーバにそのフォルダごとアップロードすれば、Cytoscapeで作った可視化をそのままウェブアプリケーションとして共有できるという機能です。要するに、既存のCytoscape.js向けJSONシリアライザの出力を一つのzipファイルにまとめて、更にその中にCytoscape.js、AngularJSなどを使ったJSコードとCSS、HTMLをまとめて書き出す機能です。解凍してそのディレクトリに入り、

```bash
python -m SimpleHTTPServer 8000
```

とでもタイプすれば、そのままSPAとしてCytoscape側で作業していた結果をブラウザで再現できます。

* [Tokyo Metro Session as Single-Page Web Application (zipped)]()
* [これをwebサーバーにアップロードしたもの](http://chianti.ucsd.edu/~kono/tokyometro/#/)。ネットワークを「比較2012」に、スタイルを「metro2012」に切り替えることにより上のものが再現されます。

もちろん、レンダリングの詳細部分でCytoscapeとCytoscape.jsは異なる部分もあるのでまだ100%の再現性とは行かないですが、これは今後も順次アップデートしていき、再現性をあげます。Webアプリケーションとの連携機能はまだまだ今後増えると思いますが、今の段階でも、Cytoscapeでスケッチしたグラフ可視化をWebアプリケーションで再利用する道は用意されています。


----

# おわりに
これは様々な可視化が可能なCytoscapeの機能のほんの一部です。また機会があったら書いてみようと思うのですが、現在、[CytoscapeをREST API経由で操作できるようにするモジュールも開発中](https://github.com/keiono/cy-rest/wiki)で、これが完成すれば、日常的にIPython NotebookやRStudioを利用されている方が、それらのコマンドラインから離れることなく可視化を作成できるようになると思います。

また、可視化一般の知識は別の連載にまとめましたので、こちらも合わせて読んでいただくことにより、理論と実践の関係（とギャップ）を理解していただけると思います:

* [プログラマーが効果的な可視化を作成する](http://qiita.com/keiono/items/9042bf58224ca54bdb45)　（全四回シリーズで完結済みです）


今後もできるだけ日本語での情報提供を続けたいと思いますが、最新の情報はどうしても英語になってしまいますので、ご興味のある方はぜひ我々の公式ツイッターアカウントや、メーリングリストをチェックしてみてください:

* [Cytoscape公式Twitterアカウント](https://twitter.com/cytoscape)
* [cytoscape-discuss](https://groups.google.com/forum/#!forum/cytoscape-discuss)
* [cytoscape-help](https://groups.google.com/forum/#!forum/cytoscape-helpdesk)

また簡単な質問なら、[私に日本語でTweet](https://twitter.com/c_z)してもらっても構いません。皆様が様々なプロジェクトでCytoscapeを活用してくだされば幸いです。

Keiichiro Ono