WSH・JScriptから Graphviz を利用するためのクラス (関係グラフを描画して、複雑な構造のデータを可視化する方法)
JScriptからGraphvizを利用して、関係グラフを手早く描画する。
下記のような使い方ができる。
var dr = new DotRecorder( "my_graph" ); // ノードを登録 dr.node( "1a", "口" ); dr.node( "2a", "日" ); dr.node( "2b", "回" ); dr.node( "3a", "目" ); dr.node( "3b", "品" ); dr.node( "4a", "田" ); // 関係を登録 dr.rel( "1a", "2a" ); dr.rel( "2a", "3a" ); dr.rel( "3a", "4a" ); dr.rel( "1a", "2b" ); dr.rel( "2b", "3b" ); dr.rel( "3b", "4a" ); // グラフ作成 dr.dot( "hoge.dot" ); dr.png( "hoge.png" );
すると、hoge.pngというファイル名で、右上のようなグラフ画像が出力・保存される。
このDotRecorderというオブジェクトのソースコードは下記の通り。
※こちらからダウンロードできます。
http://www.name-of-this-site.org/codi...
/* Graphvizのdotを作成するクラス 説明: ・ノードのラベルに日本語が使えます。 注意: ・事前にGraphvizをインストールし、binにPATHを通しておくこと。 Graphviz http://www.graphviz.org/ ・このjsファイルは、ダブルクリックやbat呼び出しによって実行すること。 (それ以外の起動方法では、カレントディレクトリが変わってしまう場合があります) 更新: 09/01/23 : 初版公開 09/01/28 : 同ランク登録と,エッジのラベル登録を追加 */ var DotRecorder = function( graph_name ){ // 初期化 this.graph_name = graph_name; this.arr_node = new Array(); this.arr_rel = new Array(); this.arr_same_rank = new Array(); }; DotRecorder.prototype = { // グラフ名 graph_name : null, // ファイル名 dot_path : null, // 「ノードのIDと名前の対応」の配列 arr_node : null, // 「ノード同士の関係」の配列 arr_rel : null, // 「等ランクなノード」の配列 arr_same_rank : null, // ノードを登録します node : function( t_id, t_name ){ this.arr_node.push( { node_id : t_id, node_name : t_name } ); }, // 関係を登録します rel : function( t_from, t_to ){ var t_label = ( arguments.length > 2 ) ? arguments[2] : "" ; this.arr_rel.push( { from_id : t_from, to_id : t_to, label : t_label } ); }, // 同ランクに登録します。引数個数は可変長。 same_rank : function(){ var temp_arr = new Array(); for( var i = 0, len = arguments.length; i < len; i ++ ) { // 引数のIDをpush temp_arr.push( arguments[i] ); } // 配列をpush this.arr_same_rank.push( temp_arr ); }, // dotファイルを出力します dot : function( file_path ){ // 新規ファイル作成 // utf-8で書き込み // http://passing.breeze.cc/mt/archives/2008/05/jscript-utf8.html var adTypeText = 2; var adWriteChar = 0; var adWriteLine = 1; var adSaveCreateOverWrite = 2; var stw = new ActiveXObject("ADODB.Stream"); stw.Type = adTypeText; stw.charset = "utf-8"; stw.Open(); // グラフ作成開始 var sp = " "; stw.WriteText( "digraph " + this.graph_name + "{\r\n" + sp + "node [fontname=\"MS GOTHIC\"];\r\n" + "edge [fontname=\"MS GOTHIC\"];" , adWriteLine ); // ノード登録 for( var i = 0, len = this.arr_node.length; i < len; i ++ ) { var node_id = this.arr_node[i].node_id; var node_name = this.arr_node[i].node_name; stw.WriteText( sp + "\"" + node_id + "\" [label=\"" + node_name + "\"];" , adWriteLine ); } // ランク登録 for( var i = 0, len = this.arr_same_rank.length; i < len; i ++ ) { stw.WriteText( sp + "{rank=same;" , adWriteChar ); var arr_temp = this.arr_same_rank[ i ]; for( var j = 0, len2 = arr_temp.length; j < len2; j ++ ) { stw.WriteText( "\"" + arr_temp[j] + "\"" + ((j == len2 - 1) ? "" : " " ) , adWriteChar ); } stw.WriteText( "};", adWriteLine ); } // 関係登録 for( var i = 0, len = this.arr_rel.length; i < len; i ++ ) { var from_id = this.arr_rel[i].from_id; var to_id = this.arr_rel[i].to_id; var label = this.arr_rel[i].label; stw.WriteText( sp + "\"" + from_id + "\" -> \"" + to_id + "\"" + " [label=\"" + label + "\"]" + ";" , adWriteLine ); } // グラフ作成終了 stw.WriteText( "}", adWriteLine ); stw.SaveToFile( file_path, adSaveCreateOverWrite ); stw.Close(); // 無事にファイルが作れたのでファイルパスを登録 this.dot_path = file_path; }, // dotからpngを作ります png : function( png_path ){ // dotは作成済みか if( this.dot_path.length > 0 ) { var cmd = "dot -Tpng -o " + png_path + " " + this.dot_path ; //WScript.Echo( cmd ); var ws = WScript.CreateObject("WScript.Shell"); ws.Run( cmd ); //dot -Tpng -o hoge.png hoge.dot } else { WScript.Echo("dotファイルが未作成です。"); } } }; // クラスのテスト /* var dr = new DotRecorder( "my_graph" ); // ノードを登録 dr.node( "1a", "口" ); dr.node( "2a", "日" ); dr.node( "2b", "回" ); dr.node( "3a", "目" ); dr.node( "3b", "品" ); dr.node( "4a", "田" ); // 関係を登録 dr.rel( "1a", "2a" ); dr.rel( "2a", "3a" ); dr.rel( "3a", "4a" ); dr.rel( "1a", "2b" ); dr.rel( "2b", "3b" ); dr.rel( "3b", "4a" ); // グラフ作成 dr.dot( "hoge.dot" ); dr.png( "hoge.png" ); */
コード中に併記したように、Graphvizのインストールを済ませ、binフォルダをPATHに登録しておくこと。(dotを呼び出すので)
実行の際には、上記を 適当な名前.js で保存してダブルクリック。
中間生成物として、hoge.dotが出力される。
digraph my_graph{ node [fontname="MS GOTHIC"]; "a" [label="口"]; "b" [label="日"]; "c" [label="品"]; "d" [label="田"]; "a" -> "b"; "b" -> "c"; "c" -> "d"; "d" -> "a"; }
複雑な構造のデータを視覚化する際に役立つかもしれない。
バッチ処理と言うと,「大量の物を一括して何かする」という操作である事が多い。
その操作の最中に,上記のクラスの処理をちょっとだけ混ぜてみれば,バッチ処理結果のレポートが簡単に作れる。という具合だ。
補足
日本語で有向グラフを描画する方法については,下記を参照。
http://cassa.at.webry.info/200711/art...
- .dotをUTF8で書く
- 日本語フォントを指定する
このためにはUTF8でファイル入出力を行なう必要があり,下記を参考にさせて頂いた。
jscriptで utf8なファイル出力
http://passing.breeze.cc/mt/archives/...