はじめに
先日投稿した記事は、データ可視化系のソフトウェアを使うワークショップをいかに効率的に進めるかということに主眼をおいて書きましたが、その中で少しだけ紹介した実際のワークショップの内容、すなわちインタラクティブにネットワークを可視化する手順の部分を、せっかくなので日本語でも少し紹介したいと思います。
問題の背景
ネットワーク解析にかかわらず、データ解析と可視化に使えるツールがどんどん増えている一方、それらを組み合わせて実際に使うノウハウはまだまだ情報量が少ないと思います。最近では、データ解析や可視化の分野ではPythonとRがスタンダードの地位を占めていますが、ここではPythonを使った例をいくつかあげてみます。私達が開発しているCytoscapeと言うネットワーク可視化ソフトウェアを使って、NetworkXなどの豊富な解析機能と、Cytoscapeの柔軟な可視化機能の「いいとこ取り」をしようというものです。英語版での記事はこちらになりますが、日本の皆様にもこういったツールの組み合わせがもっと普及して欲しいと思い、簡単ですが紹介してみます。
環境設定
Dockerを使って進めるのが一番簡単です。この文章を読まれている方はプログラマの方が多いと思われますので詳細は省きますが、以下の手順で完全に私が使ったのと同じ環境が再現されます。当然自前で環境をローカルに構築しても構いませんが、余計な手間がかかると思います。
必要なソフトウェア
- Git
- Docker (1.5でテストしました)
ノートの基本部分を試すだけならこれで大丈夫なのですが、Cytoscapeを使ってネットワークの可視化をする場合は、当然そのインストールも必要です。その場合の必要なソフトウェアは、
- Java 8最新版
- Cytoscape 3.2.1
- cyREST App - CytoscapeにREST APIを付加するアドオン(___App___と呼ばれます)です。Cytoscapeを実行している状態でこのページを開くことにより、Installボタンから直接インストールできます。最新版(0.9.13以降)が必要です。
ノートブック環境の構築
基本的に以下のコマンドで全て自動的に終わります:
git clone https://github.com/idekerlab/vizbi-2015
cd vizbi-2015
docker run -d -p 80:8888 -v $PWD:/notebooks -e "PASSWORD=(ノートブックにアクセスするためのPW)" -e "USE_HTTP=1" idekerlab/vizbi-2015
実行されていれば、あとはブラウザからアクセスするだけです。boot2dockerを利用している場合は、以下の様なアドレスのはずです:
http://192.168.59.103/
これで_tutorials_内にあるノートブックに直ぐアクセスできます
全くIPython Notebookに触れたことのない方は、Lesson 0でノートの基本操作と_magic_と呼ばれる特殊コマンドの使い方を幾つか習得しておくと今後役立つと思います。
残念ながらこれらのノートブックは全部英語ですので、少し日本語で解説を加えます。
cyRESTとは何か?
Cytoscapeは、生物学界隈では広く使われているネットワーク解析と可視化のためのオープンソースソフトウェアです。GUIベースの操作なので、比較的取っ付き易いのですが、ハードに使う方々にとっては、自動化の手段などがないので使いづらいと思われる方も居ます。この問題を解決するために、広く使われているRESTfulなAPIを、最近の標準的な手法であるリソース指向なデザイン手法で作成し、Appとして実装したものです。
Boot2docker上のDockerコンテナ内からアクセスする場合
全てをローカルマシンに直接インストール場合は問題ないのですが、boot2docker上のコンテナからは_localhost_でアクセスできませんので、Cytoscapeが走っているマシンのIPアドレスを指定する必要があり、ノートブックの最初はこのようなコードが必要になります:
# cyREST サーバーのIPアドレス(Cytoscapeを実行しているマシンのアドレス)。必ず設定が必要です!
IP = '10.0.1.6'
# cyRESTサーバーの情報。デフォルトのポートは1234
PORT_NUMBER = 1234
# 定数としてベースとなるURLを保存
BASE = 'http://' + IP + ':' + str(PORT_NUMBER) + '/v1/'
実際の流れ
今回はごく基本的な機能を利用するサンプルをノートブックとしてアップしておきます。
ネットワークの生成とPOST
cyRESTの機能は、Cytoscape内で使われている基本的なデータ構造に対してCRUDオペレーションを行えるようにしただけと言うシンプルなものです。ここでは詳細を割愛しますが、以下のデータに関して基本的なCRUDをサポートします。
- CyNetwork
- Group
- CyTable
- Visual Style
詳しくはCytoscapeの公式ドキュメントをご覧ください。現在v1.0.0リリースに向けて、機能追加やバグ修正を行っていますので、最終版にはいくつかの機能が追加されます。
基本的な機能を使うには実際にコードを見たほうが早いと思いますので、以下に例をあげます。下のコードは、NetworkXで生成したデータをCytoscapeが受け付ける形式のJSONに変形してPOSTするものです。
# 生成されるネットワークに含まれるノード数
NUM_NODES = 100
# 小規模なスケールフリーネットワークを作成
scale_free_graph = nx.scale_free_graph(NUM_NODES)
# ネットワークのアトリビュートとして名前をつける
scale_free_graph.graph['name'] = 'スケールフリーネットワーク (ノード数: ' + str(NUM_NODES) + ')'
# ユーティリティーを使ってそれをCytoscape.js 形式のJSONに変換可能なディクショナリオブジェクトを得る
cy_netwiork1 = cy.from_networkx(scale_free_graph)
# CytoscapeにネットワークをPOSTする (Create)
res = requests.post(BASE + 'networks', data=json.dumps(cy_netwiork1), headers=HEADERS)
# 生成されたネットワークのSUID (Session-Unique ID)を得る
suid = res.json()['networkSUID']
# そのSUIDを利用して、自動レイアウトアルゴリズム(ここではばねモデル)を走らせる
requests.get(BASE + 'apply/layouts/force-directed/' + str(suid))
# プリセットのVisual Style (後述)を適用する
requests.get(BASE + 'apply/styles/Directed/' + str(suid))
# 画像APIを利用して、可視化結果をこのノートに埋め込む
Image(url=BASE+'networks/' + str(suid) + '/views/first.png', embed=True)
これを実行すると、ノート側にはこのような画像(ランダムネットワークを生成しているので、実行のたびにトポロジは変わります)が埋め込まれます:
そして、Cytoscape側にも同様なものが表示されます。
この組み合わせが便利なのは、__(ネットワーク)データ解析と可視化の作業の中で、どこまでを自動化し、どこをインタラクティブな探索にするのかというのを自分で選択的に使い分けられる__という点です。つまり、データの容易と解析はノートブック内に記述したPythonのコードで自動的に行い、必要に応じてインタラクティブなCytoscapeのGUIから操作を行うという使い分けができるからです。
ちなみに同じデータをNetworkXの基本機能を使ってそのまま可視化すると以下のようになります:
NetworkXのみで行う場合、ここから様々なパラメーターをコードとして書き下すのですが、一部の作業(細かいレイアウトの修正等)はやはり手で行ってしまったほうが楽な場合も多いです。
この手法を用いる場合2つのウィンドウをよく行き来しますので、デュアルモニタ環境で作業することをお薦めします。
基本的な可視化機能(Visual Style)を利用する
可視化はCytoscapeの中核となる機能なのですが、行っていることはとてもシンプルです。それは、
データを視覚変数にマッピングする関数を指定し、それを用いて可視化をする。その関数がない場合は、予め指定されたデフォルトの値を利用する
と言うものです。前者を___Visual Mapping Functions___、後者を___defaults___と呼び、それらの集合を___Visual Style___と呼びます。今回はごく一部だけを紹介するのに留めますが、様々な値を調整したり、__Cytoscape側で手動でエディットしたVisual StyleをGETメソッドでJSONとして取得し、それを元に新しいスタイルをコードとして作成する__と言った作業をするのが、基本的な概念を学ぶ近道だと思います。
defaultsの値をPUT(アップデート)する
この部分はとてもシンプルです。マッピングが存在しない場合に使われる色や形を、リストとして作成してPUTするのみです。
defaults = [
{
'visualProperty':'NODE_FILL_COLOR',
'value': '#FFFFFF'
},
{
'visualProperty':'NODE_BORDER_WIDTH',
'value': 0
},
{
'visualProperty':'NODE_LABEL_FONT_SIZE',
'value': 18
},
{
'visualProperty':'NODE_LABEL_COLOR',
'value': '#555555'
},
{
'visualProperty':'NODE_SIZE',
'value': 30
},
{
'visualProperty': 'EDGE_WIDTH',
'value': 1
},
{
'visualProperty': 'NODE_TRANSPARENCY',
'value': 200
},
{
'visualProperty': 'EDGE_TRANSPARENCY',
'value': 80
}
]
res = requests.put(BASE + 'styles/Directed/defaults', data=json.dumps(defaults), headers=HEADERS)
Mappingを生成する
NetworkXは多くのグラフ解析アルゴリズムを持っていますので、それを利用して各種指標を計算することが出来ます。そういった数値をCytoscapeの柔軟なVisual Mapping Functionを使って、視覚変数(Visual Properties)にマッピングすることが可能です。
# ノードの次数を大きさにマッピングする
node_size_mapping = {
'mappingType': 'continuous',
'mappingColumn': 'degree',
'mappingColumnType': 'Double',
'visualProperty': 'NODE_SIZE',
'points':[
{
'value': 1,
'lesser': '15',
'equal': '15',
'greater': '15'
},
{
'value': max(degree.values()),
'lesser': '100',
'equal': '100',
'greater': '100'
}
]
}
# Betweennessをノードの色にマッピングする
node_color_mapping = {
'mappingType': 'continuous',
'mappingColumn': 'betweenness',
'mappingColumnType': 'Double',
'visualProperty': 'NODE_FILL_COLOR',
'points':[
{
'value': 0,
'lesser': '#C6E2FF',
'equal': '#C6E2FF',
'greater': '#C6E2FF'
},
{
'value': max(bc.values()),
'lesser': '#009ACD',
'equal': '#009ACD',
'greater': '#009ACD'
}
]
}
res = requests.post(BASE + 'styles/Directed/mappings', data=json.dumps([node_size_mapping, node_color_mapping]), headers=HEADERS)
このノートブックの例では、最終的にこのようなデスクトップが構成されます
ここから更に可視化を手動で微調整することも出来ますし、ノートブック側のコードを変更して他のデータに対して同じワークフローを適用することも出来ます。
おわりに
この記事は、先日行われたワークショップのダイジェスト版のような形になっていますので、詳細に興味のある方は、英語版ですがこちらからたどってみてください。
さらなる複雑なサンプルも後日投稿したいと思います。