jQuery: Cytoscape.js お試せた

graphviz ちっくなので飛び付く、のうち一つ。

jQuery: Cytoscape.js お試せた

前置き(1)

一つ前の投稿でこんなこと書いた:

科学技術系や金融系に最も良く使われるチャートの類はまぁ plotly.js 等々概ねいい感じのものは見つけてみたが、チャートてのはもっと色々あるわけであろう。

その「その他」をいくつか試してみたいと思っていて、今一番興味があるのが、graphviz と同じノリの Cytoscape.js なんだけれど、これは一つには「本格的に遊びたい」、もう一つには「ドキュメントの出来がかなりよろしくない」の2つの理由から、ちょっとだけ後回し気分になってる。

これに少し補足しておくと、既に目星をつけているものの中で「graphviz っぽい」のは Cytoscape.js のほかに Sigma.js も多分そうなんじゃないかと思っている。

前置き(2)

「graphviz ちっく」とワタシが言っているニュアンスは実は「機能が似てる」ということ以上のことを含んでいる。これをちょっとだけ説明しとく。graphviz を少しも知らない人はあまりこの感覚がわからないと思うから。

基本的に graphviz やこれに似たものがターゲットとするのは、「手描き出来ないような複雑なグラフ」である。より具体的には、Graph theory (グラフ理論)が扱うようなものたちである。Gallery を見てもらうのがいい。

もちろんワタシが今考えてるようなニーズ、つまり「ちょっとお手軽にも少し単純なもの」を描くのにも使えるけれど、それを本来のユースケースだと理解すると、大抵の場合はストレスばっかりたまって仕方ないはず。すなわち「大量のノードを扱う」ことに主眼が置かれているので、大抵「言うことを聞いてくれない」のだ。無論可能な限り自動で賢くやろうとするから。なので、カチっとしてキッチリとしたあなたによる完全制御可能なグラフ、を目指しちゃダメ。そんなこと出来ない。多少のおかしな配置くらいは目をつぶれるような目的に使うこと。

そしてそういう相手に使うものなので、ということは、graphviz であれば DOT 言語を、Cytoscape.js であれば javascript を「手書きする」のは普通はかなり無理がある、ということ。ほとんどの場合は他の何か(ワタシなら Python など)の助けを借りて生成することになるし、そうしないで「なんだよ使いににくい」と思うなら、やはり使うべき相手を間違っているか、もしくは Cytoscape.js や graphviz を選んでいることのどちらかが間違いである。

てわけで、はじめの一歩

さて。「とりあえず手始めたい」と思ったはいいが、「ドキュメントの出来がかなりよろしくない」はやってみたら想像以上だった。わかってしまえば大した話ではないが、「手始める」のは結構ややこしい。

とりあえず出来た一つはこれ:


「フレームのソースを表示」してくれ、と言いたかったが、右クリックが使えないようなので:

  1 <html>
  2 <head jang="ja">
  3 <meta charset="UTF-8">
  4 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  5 <script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.2.7/cytoscape.min.js"></script>
  6 
  7 <!-- for 'layout: "dagre"' -->
  8 <script src="https://cdn.rawgit.com/cpettitt/dagre/v0.7.4/dist/dagre.min.js"></script>
  9 <script src="https://cdn.rawgit.com/cytoscape/cytoscape.js-dagre/1.5.0/cytoscape-dagre.js"></script>
 10 <style>
 11 #cy {
 12   width: 100%;  /* MUST */
 13   height: 100%;  /* MUST */
 14 
 15   /**
 16   position: absolute;
 17   left: 0;
 18   top: 0;
 19   z-index: 999;
 20   */
 21 }
 22 </style>
 23 </head>
 24 <body>
 25 <div id="cy"></div>
 26 <script>
 27 var cy = window.cy = cytoscape({
 28   container: document.getElementById('cy'),
 29 
 30   boxSelectionEnabled: false,
 31   autounselectify: true,
 32 
 33   layout: {
 34     name: 'dagre'
 35   },
 36   style: [
 37     {
 38       selector: 'node',
 39       style: {
 40         'content': 'data(id)',  /* must be specified if you want to display the node text */
 41         /**
 42         'text-opacity': 0.5,
 43         'text-valign': 'center',
 44         'text-halign': 'right',
 45         */
 46         'background-color': '#11479e'
 47       }
 48     },
 49     {
 50       selector: 'edge',
 51       style: {
 52         'target-arrow-shape': 'triangle',
 53         'curve-style': 'bezier',
 54         'target-arrow-color': '#9dbaea',
 55         'width': 4,
 56         'line-color': '#9dbaea',
 57       }
 58     }
 59   ],
 60 
 61   elements: {
 62     "nodes": [
 63       { "data": { "id": "5th Edition" } }, 
 64       { "data": { "id": "6th Edition" } }, 
 65       { "data": { "id": "PWB 1.0" } }, 
 66       { "data": { "id": "LSX" } }, 
 67       { "data": { "id": "1 BSD" } }, 
 68       { "data": { "id": "Mini Unix" } }, 
 69       { "data": { "id": "Wollongong" } }, 
 70       { "data": { "id": "Interdata" } }, 
 71       { "data": { "id": "Unix/TS 3.0" } }, 
 72       { "data": { "id": "PWB 2.0" } }, 
 73       { "data": { "id": "7th Edition" } }, 
 74       { "data": { "id": "8th Edition" } }, 
 75       { "data": { "id": "32V" } }, 
 76       { "data": { "id": "V7M" } }, 
 77       { "data": { "id": "Ultrix-11" } }, 
 78       { "data": { "id": "Xenix" } }, 
 79       { "data": { "id": "UniPlus+" } }, 
 80       { "data": { "id": "9th Edition" } }, 
 81       { "data": { "id": "2 BSD" } }, 
 82       { "data": { "id": "2.8 BSD" } }, 
 83       { "data": { "id": "2.9 BSD" } }, 
 84       { "data": { "id": "3 BSD" } }, 
 85       { "data": { "id": "4 BSD" } }, 
 86       { "data": { "id": "4.1 BSD" } }, 
 87       { "data": { "id": "4.2 BSD" } }, 
 88       { "data": { "id": "4.3 BSD" } }, 
 89       { "data": { "id": "Ultrix-32" } }, 
 90       { "data": { "id": "PWB 1.2" } }, 
 91       { "data": { "id": "USG 1.0" } }, 
 92       { "data": { "id": "CB Unix 1" } }, 
 93       { "data": { "id": "USG 2.0" } }, 
 94       { "data": { "id": "CB Unix 2" } }, 
 95       { "data": { "id": "CB Unix 3" } }, 
 96       { "data": { "id": "Unix/TS++" } }, 
 97       { "data": { "id": "PDP-11 Sys V" } }, 
 98       { "data": { "id": "USG 3.0" } }, 
 99       { "data": { "id": "Unix/TS 1.0" } }, 
100       { "data": { "id": "TS 4.0" } }, 
101       { "data": { "id": "System V.0" } }, 
102       { "data": { "id": "System V.2" } }, 
103       { "data": { "id": "System V.3" } }
104     ], 
105     "edges": [
106       { "data": { "source": "5th Edition", "target": "6th Edition" } }, 
107       { "data": { "source": "5th Edition", "target": "PWB 1.0" } }, 
108       { "data": { "source": "6th Edition", "target": "LSX" } }, 
109       { "data": { "source": "6th Edition", "target": "1 BSD" } }, 
110       { "data": { "source": "6th Edition", "target": "Mini Unix" } }, 
111       { "data": { "source": "6th Edition", "target": "Wollongong" } }, 
112       { "data": { "source": "6th Edition", "target": "Interdata" } }, 
113       { "data": { "source": "Interdata", "target": "Unix/TS 3.0" } }, 
114       { "data": { "source": "Interdata", "target": "PWB 2.0" } }, 
115       { "data": { "source": "Interdata", "target": "7th Edition" } }, 
116       { "data": { "source": "7th Edition", "target": "8th Edition" } }, 
117       { "data": { "source": "7th Edition", "target": "32V" } }, 
118       { "data": { "source": "7th Edition", "target": "V7M" } }, 
119       { "data": { "source": "7th Edition", "target": "Ultrix-11" } }, 
120       { "data": { "source": "7th Edition", "target": "Xenix" } }, 
121       { "data": { "source": "7th Edition", "target": "UniPlus+" } }, 
122       { "data": { "source": "V7M", "target": "Ultrix-11" } }, 
123       { "data": { "source": "8th Edition", "target": "9th Edition" } }, 
124       { "data": { "source": "1 BSD", "target": "2 BSD" } }, 
125       { "data": { "source": "2 BSD", "target": "2.8 BSD" } }, 
126       { "data": { "source": "2.8 BSD", "target": "Ultrix-11" } }, 
127       { "data": { "source": "2.8 BSD", "target": "2.9 BSD" } }, 
128       { "data": { "source": "32V", "target": "3 BSD" } }, 
129       { "data": { "source": "3 BSD", "target": "4 BSD" } }, 
130       { "data": { "source": "4 BSD", "target": "4.1 BSD" } }, 
131       { "data": { "source": "4.1 BSD", "target": "4.2 BSD" } }, 
132       { "data": { "source": "4.1 BSD", "target": "2.8 BSD" } }, 
133       { "data": { "source": "4.1 BSD", "target": "8th Edition" } }, 
134       { "data": { "source": "4.2 BSD", "target": "4.3 BSD" } }, 
135       { "data": { "source": "4.2 BSD", "target": "Ultrix-32" } }, 
136       { "data": { "source": "PWB 1.0", "target": "PWB 1.2" } }, 
137       { "data": { "source": "PWB 1.0", "target": "USG 1.0" } }, 
138       { "data": { "source": "PWB 1.2", "target": "PWB 2.0" } }, 
139       { "data": { "source": "USG 1.0", "target": "CB Unix 1" } }, 
140       { "data": { "source": "USG 1.0", "target": "USG 2.0" } }, 
141       { "data": { "source": "CB Unix 1", "target": "CB Unix 2" } }, 
142       { "data": { "source": "CB Unix 2", "target": "CB Unix 3" } }, 
143       { "data": { "source": "CB Unix 3", "target": "Unix/TS++" } }, 
144       { "data": { "source": "CB Unix 3", "target": "PDP-11 Sys V" } }, 
145       { "data": { "source": "USG 2.0", "target": "USG 3.0" } }, 
146       { "data": { "source": "USG 3.0", "target": "Unix/TS 3.0" } }, 
147       { "data": { "source": "PWB 2.0", "target": "Unix/TS 3.0" } }, 
148       { "data": { "source": "Unix/TS 1.0", "target": "Unix/TS 3.0" } }, 
149       { "data": { "source": "Unix/TS 3.0", "target": "TS 4.0" } }, 
150       { "data": { "source": "Unix/TS++", "target": "TS 4.0" } }, 
151       { "data": { "source": "CB Unix 3", "target": "TS 4.0" } }, 
152       { "data": { "source": "TS 4.0", "target": "System V.0" } }, 
153       { "data": { "source": "System V.0", "target": "System V.2" } }, 
154       { "data": { "source": "System V.2", "target": "System V.3" } }
155     ]
156   },
157 
158 });
159 </script>
160 </body>
161 </html>

elements の部分は graphviz がわかる人ならお馴染み(だけれど DOT よりダルい)とわかるだろう。

「手始める」にあたって個人的にうわぁと思ったポイントは以下:

  • layout の種類ごとに追加ライブラリが必要 (今回の例の場合は dagre.jscytoscape-dagre.js)
  • スタイルなし、から始められない。不可欠なものがいくつかある。
    • つまり「ださくてもいいからミニマルから始めたい」という学習スタイルの人にキツい。
    • コンテナ(今回の例では cy)の width, height がないとダメ。
    • cytoscapeに渡しているコンフィギュレーションに指定してる style も、全くなしで始めると意味わからんものになるので、へろわるどでも付けて手始めた方がよろしい。

まぁこうやって誰か人柱がいれば、後追いの人はなんてことはないと思うんだろうけどね。

さて、「ドキュメントがヒドい」だけどね、上の「出来てみた」に辿りついた手順はこんななのよ:

  1. Demos からやりたいのに近いものの下にくっついてる GitHub へ Go! ボタン
  2. そのデモの html を読んで、必要なライブラリを学ぶ。
  3. そのデモの js を読んで、書き方を学ぶ。

これ以外の手段はないと思う。少なくとも Getting startedLayout extensionsにはそんなこと一言も書いてないんだから。

第一印象

「ドキュメントはヒドい」は重々わかった上で飛びついてるのでもとからハードルが低いんだけれど、という点は差し引いてワタシの話をきいてね。

印象は、「良い」。非常に。(異論を持たれるのを覚悟の上で)「滅茶苦茶簡単だ」し、Demos をざっと眺める限り、Graphviz に期待することの大抵のことは出来そうだし。

なので問題はワタシにとってはただ一つ。

前置きで書いたように『ほとんどの場合は他の何か(ワタシなら Python など)の助けを借りて生成することになるし』、ということはだ、「サーバサイドで自動生成」あるいは「PC で(Python などで)生成」ということをどうせするんだから、となれば、「別に Graphviz でよくね?」てことになるのね、「そこで Graphviz が使える限りは」。Graphviz は svg も吐き出せるからね。

なので「サーバで生成したいが Graphviz がインストールされてない」なら嬉しいてことになるわけだけれど、もし両方使えるとしたならば。個人的には Graphviz のフォント周りのダサさでいい思い出がないので、Graphviz 以外の選択肢が増えたことはとっても嬉しい。

こんな感じかな、第一印象は。



Related Posts