『言語処理 100 本ノック』に PHP で挑む (問題 44)
『言語処理 100 本ノック』に PHP で挑戦しています。今回は第 5 章の問題 44 を解きます。
www.cl.ecei.tohoku.ac.jp
44. 係り受け木の可視化
与えられた文の係り受け木を有向グラフとして可視化せよ.可視化には,係り受け木をDOT言語に変換し,Graphvizを用いるとよい.また,Pythonから有向グラフを直接的に可視化するには,pydotを使うとよい.
問題文では Graphviz や pydot が紹介されていますが、ここでは vis.js というライブラリを利用してウェブブラウザ上にグラフを表示してみます。
vis.js - A dynamic, browser based visualization library.
実装したプログラムは以下のとおりです。何番目の文を表示するかをクエリパラメータ (id) で指定できるようにしました。PHP スクリプト部分でグラフのノードとエッジを JSON 形式の文字列として作成し、後半の JavaScript コード部分に書き出します。各ノードを指定した階層に配置するため、level 属性を追加します。末尾の文節を level = 0 とした後、係り元の level が係り先の level + 1 になるように設定していきます。
<?php require_once __DIR__ . '/read_cabocha_data.php'; $sentences = read_cabocha_data('neko.txt.cabocha'); $sentence = $sentences[(int) $_GET['id']]; $nodes = []; $edges = []; foreach ($sentence->chunks as $i => $chunk) { $nodes[] = [ 'id' => $i, 'label' => $chunk->surface(), 'shape' => 'box' ]; if ($chunk->dst) { $dst = array_search($chunk->dst, $sentence->chunks, true); $edges[] = [ 'from' => $i, 'to' => $dst, 'arrows' => 'to' ]; } } $nodes[count($nodes) - 1]['level'] = 0; for ($i = count($edges) - 1; $i >= 0; --$i) { $nodes[$edges[$i]['from']]['level'] = $nodes[$edges[$i]['to']]['level'] + 1; } $nodes = json_encode($nodes); $edges = json_encode($edges); ?> <html> <head> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.16.1/vis.min.js"></script> </head> <body> <div id="container"></div> <script type="text/javascript"> var container = document.getElementById('container'); var data = { nodes: new vis.DataSet(<?= $nodes ?>), edges: new vis.DataSet(<?= $edges ?>) }; var options = { layout: { hierarchical: { enabled: true, direction: 'RL' } } }; var network = new vis.Network(container, data, options); </script> </body> </html>
HTML 側の実装は vis.js のネットワークグラフのドキュメントを参考にしました。以下のウェブページで "Show the getting started!" を開くと簡単な例が表示されます。
vis.js - Network documentation.
ウェブサーバを起動してブラウザからアクセスすると、グラフが表示されます。id = 11 (下記の文) を指定したときの結果は次のようになります。
ただ彼の掌に載せられてスーと持ち上げられた時何だかフワフワした感じがあったばかりである。