Cytoscape.jsを試してみた

Cytoscape.jsとは

もともとはクライアントアプリとして欧米の研究機関によって開発されているオープンソースのネットワーク可視化ソフトウェアプラットフォームであるCytoscapeが10年ほど前に作られ現在も継続して開発が行われています。Cytoscapeはデータの読み込み、分析、可視化といった一連の処理を行うことができますが、分析は別のソフト例えばRなどを使い、それから分析結果をエクスポートしてCytoscapeで可視化と言った使われ方もあるようです。クライアントアプリでは分析結果の共有に不便であるためカナダのトロント大学Cytoscape.jsのを開発を始めたようです。
以下のデモを見るのが一番わかりやすいと思います。 js.cytoscape.org

Cytoscapeでの処理フローについて

下記URLのCytoscapeの開発者の記事によりますと以下のような処理フローになるようです。
http://qiita.com/keiono/items/0db6495c4d8bc215de67

    ネットワークデータを読み込む
    アトリビュート(データテーブル)を読み込む
        ソーシャルネットワークの例で言えば
            人の名前、年齢、職業、性別などがノードアトリビュート
            婚姻関係、友人関係、メールの交換された数などといった関係性に関する情報がエッジアトリビュート
    統合されたデータを使って、統計的な解析やフィルタリングなどを行い分析する
    自動レイアウト機能を使って、ノードを見やすく配置する
    ノード、エッジに付随する各種データに基づきマッピングを設定し、描画を行う
    PDFやJavaScriptウィジェットに出力する

Cytoscape.jsを試してみる

では実際にCytoscape.jsを試しに動かしてみたいと思います。
ここのチュートリアルを試してます。

1.ソース取得
ソースををgithubからダウンロードしておきます。
https://github.com/cytoscape/cytoscape.js

2.html作成
以下のhtmlを記述します。srcのパスはダウンロードしたCytoscape.jsのdist/cytoscape.min.jsを参照するように修正しておいてください。

<!doctype html>

<html>

<head>
    <title>Tutorial 1: Getting Started</title>
    <script src="cytoscape.js"></script>
</head>

<style>
    #cy {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0px;
        left: 0px;
    }
</style>

<body>
    <div id="cy"></div>
</body>
</html>

divタグに対してcanvasを埋め込んでグラフの描画を行いまして、cssで表示領域を設定しています。

3.グラフインスタンスの作成

var cy = cytoscape({
  container: document.getElementById('cy'),
  elements: [
    { data: { id: 'a' } },
    { data: { id: 'b' } },
    {
      data: {
        id: 'ab',
        source: 'a',
        target: 'b'
      }
    }]
});

上記スクリプトで描画するノードとエッジを指定しています。data: { id: ‘a’ } 、data: { id: ‘b’ } とありますので2つのノードが描画されます。それから、data: {id: ‘ab’,source: ‘a’,target: ‘b’}とありますので2つのノードを結んだエッジも表示されます。
先ほど作成したhtmlにスクリプトを記述して開いてみるとグラフが表示されたことが確認できます。cytoscape.jsには自動レイアウト機能がありますのでウィンドウのサイズを変更して開き直すとノードが縦に並んだり、横に並んだりして自動でレイアウトして描画されることが確認できます。

4.グラフの描画設定 3で描画したスクリプトのelementsに続けて以下のstyleを追記してください。

style: [
    {
        selector: 'node',
        style: {
            shape: 'hexagon',
            'background-color': 'red',
            label: 'data(id)'
        }
    }]

それから開き直すとノードが赤色六角形のID付きで表示されることが確認できたかと思います。
styleについて他にどんな設定があるかは以下を見たら良いと思います。
https://github.com/cytoscape/cytoscape.js/blob/master/documentation/md/style.md

5.ノードの配置設定
ノードをどのように配置するかはlayoutで指定できるようになっています。例えばノードを円状に並べて描画したい場合は、以下を追記したら行えます。

cy.layout({
    name: 'circle'
});

円状に並べたのをわかりやすくするためhtmlを編集しノードを増やしてみます。

<!doctype html>

<html>

<head>
    <title>Tutorial 1: Getting Started</title>
    <script src="../cytoscape.js/dist/cytoscape.min.js"></script>
</head>

<style>
    #cy {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0px;
        left: 0px;
    }
</style>

<body>
    <div id="cy"></div>
    <script>
      var cy = cytoscape({
        container: document.getElementById('cy'),
        elements: [
          { data: { id: 'a' } },
          { data: { id: 'b' } },
          {
            data: {
              id: 'ab',
              source: 'a',
              target: 'b'
            }
          }],
        style: [
        {
            selector: 'node',
            style: {
                shape: 'hexagon',
                'background-color': 'red',
                label: 'data(id)'
            }
        }]
      });
      for (var i = 0; i < 10; i++) {
          cy.add({
              data: { id: 'node' + i }
              }
          );
          var source = 'node' + i;
          cy.add({
              data: {
                  id: 'edge' + i,
                  source: source,
                  target: (i % 2 == 0 ? 'a' : 'b')
              }
          });
      }
      cy.layout({
        name: 'circle'
      });
    </script>
</body>
</html>

これで開きなおしてみると以下のように円状に並んで表示されることが確認できます。 f:id:steavevaivai:20170325065549p:plain

レイアウトの描画設定は自分で行うこともできここにまとめられているのですがcircleに配置するのであれば、以下の設定でも同様となっております。

var options = {
  name: 'circle',

  fit: true, // whether to fit the viewport to the graph
  padding: 30, // the padding on fit
  boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
  avoidOverlap: true, // prevents node overlap, may overflow boundingBox and radius if not enough space
  radius: undefined, // the radius of the circle
  startAngle: 3 / 2 * Math.PI, // where nodes start in radians
  sweep: undefined, // how many radians should be between the first and last node (defaults to full circle)
  clockwise: true, // whether the layout should go clockwise (true) or counterclockwise/anticlockwise (false)
  sort: undefined, // a sorting function to order the nodes; e.g. function(a, b){ return a.data('weight') - b.data('weight') }
  animate: false, // whether to transition the node positions
  animationDuration: 500, // duration of animation in ms if enabled
  animationEasing: undefined, // easing of animation if enabled
  ready: undefined, // callback on layoutready
  stop: undefined // callback on layoutstop
};

cy.layout( options );

6.ノードごとでスタイルを変えてみる
ノードごとでスタイルを変更したい場合があると思うのですが、その場合はノードに付与したIDを指定してstyle属性に設定を追加してあげれば行えます。
例えばID=node1に対してスタイルを設定したい場合は以下のようになります。

{
    selector: '#node1',
    style: {
        'background-image': 'https://farm8.staticflickr.com/7272/7633179468_3e19e45a0c_b.jpg',
        'height': 80,
        'width': 80,
        'background-fit': 'cover',
        'border-color': '#000',
        'border-width': 3,
        'border-opacity': 0.5
}

結果、このようになりスタイルが適用されているのが確認できます。 f:id:steavevaivai:20170325065606p:plain

触ってみた感想として表示するデータに合わせて柔軟にレイアウトを調整するというよりかは、事前に表示するデータを想定した上でそれに合わせてレイアウトをどう調整するのかが重要そうな気がしました。他の分析ソフトからエッジとノードあとアトリビュートをエクスポートできたら分析結果の共有に便利そうです。