Cytoscape / cyRESTとpy2cytoscapeを用いたIPython Notebook上でのグラフ解析と可視化 Part 1

# はじめに

![blue_web.png](https://qiita-image-store.s3.amazonaws.com/0/20688/563a78d6-83af-66f2-70ab-8a890552ed27.png)
(酵母菌のタンパク質間相互ネットワークをCytoscapeとcyRESTにて可視化）

[IPython Notebook](http://ipython.org/notebook.html)[^1]を用いてグラフデータの可視化を行う場合、以下のようなグラフ解析ライブラリに付属する可視化モジュールを用いて行うのが一般的です:

* [igraph](http://igraph.org/python/)
* [NetworkX](https://networkx.github.io/)
* [graph-tool](http://graph-tool.skewed.de/)

しかし最近のウェブベースの可視化ツールや、デスクトップの可視化ツールに比べると機能的な部分やインタラクティブ性の面で少々物足りなさがあるのもまた事実です。そこでこれらのライブラリの解析機能と、[Cytoscape](http://www.cytoscape.org/)のインタラクティブな描画機能などを同時に利用できるようにするために作ったのが、今回紹介する__cyREST__と__py2cytoscape__ライブラリです。基本的な考え方はとてもシンプルで、PythonやRといったデータ解析のための標準的な環境からCytoscapeの描画機能などにアクセスできるようにしようというものです。

## cyRESTとは？

![](https://raw.githubusercontent.com/idekerlab/cyREST/master/docs/images/logo300.png)

[cyREST](http://apps.cytoscape.org/apps/cyrest)はCytoscape用の拡張機能[^2]で、Cytoscapeの各種データや機能に、RESTfulなAPIからアクセスできるようにしたものです。簡単な例として「今Cytoscape内にある全てのネットワークのID」にアクセスしたい場合、

```
http://localhost:1234/v1/networks
```

と言うURLに対してGETリクエストを行うことで可能です。同じように、Cytoscape内にあるリソースには

```
# NETWORK_IDに対応するネットワークをJSONとして取得する
http://localhost:1234/v1/networks/NETWORK_ID

# NETWORK_IDに対応するネットワーク内の全てのノードを取得する
http://localhost:1234/v1/networks/NETWORK_ID/nodes

# 同エッジ
http://localhost:1234/v1/networks/NETWORK_ID/edges

# ネットワーク内の特定のノードを取得する
http://localhost:1234/v1/networks/NETWORK_ID/nodes/NODE_ID

# ネットワークのノードに関する全プロパティ（テーブル）を取得する
http://localhost:1234/v1/networks/NETWORK_ID/tables/defaultnode

# スタイルのリストを取得する
http://localhost:1234/v1/styles

# 特定のネットワークに指定された自動レイアウトアルゴリズムを適用する
http://localhost:1234/v1/apply/layouts/LAYOUT_NAME/TARGET_NETWORK_ID

```
基本的なAPI設計は[CRUDオペレーション](https://ja.wikipedia.org/wiki/CRUD)に各種リソースをマッピングするというリソース志向のデザインになっていますので、各種Web APIを利用したことのある方には比較的わかりやすいと思います。つまり、これは言語非依存のAPIであり、HTTPクライアントさえあればどの言語からでもアクセスできます。

## py2cytoscapeとは？
このように一般的なHTTPクライアントを用いれば、どの言語からもCytoscape内のリソースにアクセスできるのですが、生のWeb APIをコールするコードがどうしても冗長になってしまいます。特に、___PUT/POST___を行う場合、どのような形でデータを送れば良いのかというフォーマットに関してはその都度ドキュメントを参照するしかありません。これをできる限り解消するために作られたPython用ラッパー兼ユーティリティー集が[py2cytoscape](https://github.com/idekerlab/py2cytoscape)です。

具体的に、ラッパーを使う場合と使わない場合では以下のような差が出ます。これはCytoscape側にからのネットワークを生成するためのコードです:

```py
# Popular HTTP client for Python
import requests

# Built-in JSON library
import json

# Basic Setup
PORT_NUMBER = 1234
BASE = 'http://localhost:' + str(PORT_NUMBER) + '/v1/'

# Header for posting data to the server as JSON
HEADERS = {'Content-Type': 'application/json'}

# Define dictionary of empty network
empty_network = {
        'data': {
            'name': 'I\'m empty!'
        },
        'elements': {
            'nodes':[],
            'edges':[]
        }
}

res = requests.post(BASE + 'networks?collection=My%20Collection', data=json.dumps(empty_network), headers=HEADERS)
new_network_id = res.json()['networkSUID']
print('Empty network created: SUID = ' + str(new_network_id))
```

一方で、py2cytoscapeを用いると以下のようになります:

```py
from py2cytoscape.data.cyrest_client import CyRestClient

cy = CyRestClient()
network = cy.network.create(name='My Network', collection='My network collection')
print('Empty network created: SUID = ' + str(network.get_id()))
```

このように、冗長性を減らすのと、IDEなどの文法サポートなどが得られやすいようにするのがこのライブラリの目的です。このほかにも、

* Canvasを使った描画ウィジェットの埋め込み（後述）
* NetworkX/igraphなどのオブジェクトからCytoscapeスタイルのJSONへの相互変換

などの機能が含まれます。

現在はPython用のラッパーしかありませんが、R用も順次公開予定です。


# 実際の作業
ここからは実際の利用例を紹介します。Cytoscapeがどのようなものかご存じでない方には、こちらの記事が参考になると思います。

* [ネットワーク可視化プラットフォームCytoscapeの現状まとめ](http://qiita.com/keiono/items/0db6495c4d8bc215de67)


## 動作環境
以下の環境にて動作確認を行いました。

* Mac OS X 10.10.3
* Java SE 8 u45
* Cytoscape 3.2.1
* cyREST 1.1.0
* Python 3.4.3 (Anaconda distributionを利用)
* py2cytoscape 0.4.4

### Python側の準備
IPython Notebookなどのインストールはあらかじめ行ってあるという前提で話を進めます。一応3.4/2.7系でテストしていますが、問題があれば連絡ください。

実行に必要なのはpy2cytoscapeのみで、これは以下のコマンドでインストール可能です

```
pip install py2cytoscape
```

__DockerやEC2などでNotebookサーバー走らせる場合、ノートブックのサーバーとCytoscapeを実行しているマシンが異なることに注意してください。Cytoscapeを実行しているマシンのIPアドレスとポートを適切に設定しない場合、これらのサンプルは動きません。__

### Cytoscape側の準備
こちらの準備はシンプルで、App ManagerからcyRESTをインストールするのみです。メニューの___Apps→App Manager___からApp Managerダイアログを呼び出し、cyRESTを選択してInstallボタンをクリックするだけです。

__デフォルトのポートは1234です。__変更は、___Edit-Preferences-Properties...___からプロパティ設定画面を呼び出し、___rest.port___に数値を与えることで変更できます。


## 実行の手順
準備が整ったら、ちゃんと動いているのかを確認します。

1. Cytoscapeをスタートする
2. ブラウザを開いて以下のURLを開く
    3. ```http://localhost:1234/v1```
4. 以下のような結果が返ってくればcyRESTが作動しています。

![スクリーンショット 2015-07-04 12.17.31.png](https://qiita-image-store.s3.amazonaws.com/0/20688/5e8d782d-db01-ca2f-5893-6c98d249d3e4.png)

次にノートブックを作成します

1. IPython Notebookを実行する
2. ブラウザを開いて新しいノートブックを作成する
3. 以下のコードを実行する

```py3
import json
from py2cytoscape.data.cyrest_client import CyRestClient

cy = CyRestClient()
print(json.dumps(cy.status(), indent=4))
```

```json
{
    "apiVersion": "v1",
    "numberOfCores": 8,
    "memoryStatus": {
        "maxMemory": 28217,
        "usedMemory": 513,
        "freeMemory": 2645,
        "totalMemory": 3159
    }
}
```

### IPアドレスとポート
実際にデータ解析をする場合、IPython NotebookはAWSなどのクラウドで、Cytoscapeとブラウザはローカルで、という場合も多いと思います。この場合、CyRestClientにアドレスとポートを渡すことで、Cytoscapeが走っているマシンの場所を指定することが可能です

```py3
cy = CyRestClient(ip='127.0.0.1', port=1234)
```

これで全ての準備が整いました。ここからは実際にCytoscapeをIPython Notebookの外部描画エンジンとして利用するごく簡単な例を紹介したいと思います。

# Hello (Graph) World
ここではごく簡単な例を紹介します。できれば環境を整えて、実際にノートブックを実行してみてください。

* [実際のノートブック](http://nbviewer.ipython.org/gist/keiono/6b34f951ba91efc6c70b)

## NetworkXによるランダムネットワーク作成
使うグラフデータはなんでも構わないのですが、ここではNetworkXを利用してスケールフリーネットワークを生成します。

```py3
import networkx as nx
g = nx.scale_free_graph(500) # 500ノードのネットワーク
```

## 各種統計量計算
このグラフのDegreeとBetweennessを計算します。

```py3
deg = nx.degree(g)
btw = nx.betweenness_centrality(g)
nx.set_node_attributes(g, 'degree', deg)
nx.set_node_attributes(g, 'betweenness', btw)
```

## Cytoscapeに送信
一つのコマンドで、直接NetworkXのグラフオブジェクトをCytoscape側に送ることが可能です。この際、ノートやエッジ、ネットワークのプロパティ(attributes)も同時に送信できます。

```py3
g_cy = cy.network.create_from_networkx(g)
```

## 自動レイアウトアルゴリズムを適用
ここではKamada-Kawaiアルゴリズムを用いて、Cytoscape側でレイアウトを計算させて描画します。

```py3
cy.layout.apply(name='kamada-kawai', network=g_cy)
```

この時点である程度の描画が行われているのが確認できると思います。


![スクリーンショット 2015-07-04 22.53.38.png](https://qiita-image-store.s3.amazonaws.com/0/20688/bff9d429-2ad5-2e42-d707-a75fd7b1cc1c.png)

## 別のVisual Styleを適用する
Cytoscapeでは、プロパティから視覚要素への各種マッピングを定義したものを___Visual Style___と呼びます。ここではプリセットの中から、___Directed___というものに切り替えます。

```py3
directed = cy.style.create('Directed')
cy.style.apply(directed, network=g_cy)
```

少々分かりにくいですが、Styleを_create_で呼び出すことにより、そのStyleへのリファレンスを作る形になっています。

## エッジを束ねて見やすくする
これは[スケールフリー・ネットワーク](https://ja.wikipedia.org/wiki/%E8%A4%87%E9%9B%91%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF#.E3.82.B9.E3.82.B1.E3.83.BC.E3.83.AB.E3.83.95.E3.83.AA.E3.83.BC.E6.80.A7)なので、一部のノードに接続が集中しています。これを見やすくするために、力学シミュレーションを使ってエッジを束ねます(Edge Bundling)

```py3
cy.edgebundling.apply(g_cy)
```

## 画像としてノートブックに埋め込む
Cytoscapeに内蔵された画像出力機能を使って、画像ファイルとしてネットワークを埋め込んだりファイルに出力したりすることが可能です。現在のバージョンでは、PNG, SVG, PDFをサポートしています。

```py3
# PNG
network_png = g_cy.get_png()
from IPython.display import Image
Image(network_png)

# SVG
network_svg = g_cy.get_svg()
from IPython.display import SVG
SVG(network_svg)

# PDFをファイルに保存
network_pdf = g_cy.get_pdf()
f = open('scale_free_500.pdf', 'wb')
f.write(network_pdf)
f.close()
```


![スクリーンショット 2015-07-04 23.53.20.png](https://qiita-image-store.s3.amazonaws.com/0/20688/be16f302-c5aa-2cd9-aa03-8e942b52daa3.png)


## JavaScriptのインタラクティブなオブジェクトとして埋め込む
py2cytoscapeライブラリには[Cytoscape.js](http://js.cytoscape.org/)[^3]を利用したHTMLウィジェットが内蔵されているので、これを利用すれば簡単なコードでJavaScriptによるCanvasを用いたネットワーク描画が可能です。

![スクリーンショット 2015-07-05 0.20.05.png](https://qiita-image-store.s3.amazonaws.com/0/20688/8db67c66-95a5-7762-a8f2-e0a73f991c7a.png)

```py3
import py2cytoscape.cytoscapejs as renderer

view = g_cy.get_first_view()
# style_for_widget = cy.style.get(my_yeast_style.get_name(), data_format='cytoscapejs')
renderer.render(view, 'Directed', background='radial-gradient(#FFFFFF 15%, #DDDDDD 105%)')
```


現在、Edge Bundlingを含む一部の機能がまだ実装されていませんので、完全に再現されるわけではありませんが、それらも徐々にサポートする予定です。


## 手動でこの結果をさらに編集する
ここまではコードにより描画してきましたが、その結果をGUIからインタラクティブに眺めたり修正したりするのも容易です。これは静止画像を生成するだけのライブラリでは困難な部分です。例えば、ノードの位置の微妙な調整や、細部へのズームインなどがそれにあたります。

![net2.png](https://qiita-image-store.s3.amazonaws.com/0/20688/8fecb654-8f79-3fbe-15df-e5ec5d2b58fb.png)

上の例は、バックグラウンドの色を変えたり、Betweennessをノードの大きさにマッピングしただけの簡単なエディットですが、コードを書いて再現性のある可視化を行うことと、GUIからの直感的なエディットで直接見ながら可視化結果をいじるという双方のメリットが享受できます。

# まとめ
今回は駆け足で基本的な機能を紹介しただけですが、実際のデータ解析を行うには、スタイルのコードを使った生成や、各種グラフ解析ライブラリの結果の利用などが便利です。次回以降にこれらCytoscape + Pythonならではの使い方を紹介したいと思います。


----

[^1]: 現在は[Jupyter Notebook](https://jupyter.org/)としてリブランディング中
[^2]: _App_と呼ばれます。[Cytoscape App Store](http://apps.cytoscape.org/)から入手可能。
[^3]: ネットワーク描画と解析に特化したJavaScriptライブラリ。Cytoscapeの開発チームが開発とメンテナンスを行っている。