<?xml version="1.0" encoding="UTF-8" ?>
<entry
	xmlns="http://www.w3.org/2005/Atom"
	xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"
	xml:lang="ja-JP"
>
	<title>Jungで相関行列のグラフ化</title>
	<id>tag:txqz.net,2008-10-25:blog/2008/10/25/1155</id>
	<link rel="self" href="http://txqz.net/blog/2008/10/25/1155.atom"/>
	<link rel="alternate" type="application/rss+xml" href="http://txqz.net/blog/2008/10/25/1155.rdf"/>
	<link rel="alternate" type="application/xhtml+xml" href="http://txqz.net/blog/2008/10/25/1155.xhtml"/>
	<link rel="alternate" type="text/html" href="http://txqz.net/blog/2008/10/25/1155.html"/>
	<link rel="contents" href="http://txqz.net/blog/2008/10/25/.atom" title="2008年10月25日"/>
	<link rel="first" href="http://txqz.net/blog/2001/08/04/0001.atom" title="地球空冷化"/>
	<link rel="prev" href="http://txqz.net/blog/2008/10/21/2206.atom" title="たのしいSQL教室 「CASE式でクロス集計をしよう」編"/>
	<link rel="next" href="http://txqz.net/blog/2008/10/25/2244.atom" title="ノートパソコン上のOperaでldRのピンを立てすぎるとブラウザが不安定になるのでbを多用するようにした"/>
	<link rel="last" href="http://txqz.net/blog/2010/02/14/1221.atom" title="VIASO/K-power追悼"/>
	<author>
		<name>陽坂智佐</name>
		<email>spambasket@txqz.net</email>
	</author>
	<content type="xhtml">
		<div xmlns="http://www.w3.org/1999/xhtml">
<h2>ファイルからデータを読み込んでグラフを表示する</h2>
<p><a href="http://jung.sourceforge.net/" title="JUNG - Java Universal Network/Graph Framework">JUNG</a>はPageRankや中心性の計算やクラスタリングとかにも使えるJavaのグラフ構造ライブラリなのだが、日本語のまとまった解説文書が<a href="http://www.techscore.com/tech/Others/Jung/index.html" title="Jung-TECHSCORE-">TECHSCORE</a>くらいにしか見当たらない。でもTECHSCOREの解説を見れば大体使えたりする。使い方が変更されているメソッドや非推奨になったクラスもたまにあるが、<a href="http://jung.sourceforge.net/doc/api/index.html" title="Overview (JUNG 1.7.6 API)">JavaDoc</a>を見ればだいたい解決する。</p>
<p>ということで、相関行列を読み込んで、有意な関係をグラフ化するものをJUNGを使って作ってみようと思う。そのために、<a href="http://sourceforge.net/projects/jung/" title="SourceForge.net: Java Universal Network/Graph Framework">SourceForge</a>からJUNGのJARファイルをダウンロードし、依存ライブラリである<a href="http://larvalabs.com/collections/" title="larvalabs">Commons Collection</a>と<a href="http://acs.lbl.gov/~hoschek/colt/" title="Colt - Welcome">Cern Colt</a>(行列計算ライブラリ)をビルドパスに含める。</p>
<p>まず相関行列のデータが必要なので、<a href="http://kogolab.jp/elearn/icecream/chap7/sec6.html" title="7.6 通過テスト">アイスクリーム統計学</a>のデータから作成した。ExcelファイルをダウンロードしてPEARSON関数を20回コピペするだけの簡単なお仕事。終わったら表頭とデータ部分をコピーしてicecream.txtを作成する。1行目は「バニラ」や「ストロベリー」といった表頭変数がタブ区切りで並び、2行目から相関行列の各行ベクトルがタブ区切りで並ぶことになる。それらを読み込んでVertexを作り、閾値以上のVertexにEdgeを張ってJFrameに表示させる。ソースはこんな感じ:</p>
<pre><code class="java">package net.txqz.neta;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;

import javax.swing.JFrame;

import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.Vertex;
import edu.uci.ics.jung.graph.impl.UndirectedSparseEdge;
import edu.uci.ics.jung.graph.impl.UndirectedSparseGraph;
import edu.uci.ics.jung.graph.impl.UndirectedSparseVertex;
import edu.uci.ics.jung.visualization.FRLayout;
import edu.uci.ics.jung.visualization.Layout;
import edu.uci.ics.jung.visualization.PluggableRenderer;
import edu.uci.ics.jung.visualization.VisualizationViewer;

public class RelationGraph {
  public static void main(String[] args) throws NumberFormatException, IOException {
    JFrame window = new JFrame("RelationGraph");
    final Graph graph = new UndirectedSparseGraph();
    double threshold = 0.2;
    // 表頭変数の配列
    String[] names = null;
    // 相関行列
    double[][] correlation = null;
    LineNumberReader in = new LineNumberReader(
        new InputStreamReader(new FileInputStream("D:\\data\\icecream.txt"), "MS932")
    );
    String line;
    while((line = in.readLine()) != null) {
      // 1行目は表頭変数。ついでに列の数も数えて配列を作成する。
      if(in.getLineNumber() == 1) {
        names = line.split("\t");
        correlation = new double[names.length][names.length];
      }
      // 2行目以降はn行目のデータを配列の[n-2]番目に入れる。
      else {
        String[] t = line.split("\t");
        double[] d = new double[names.length];
        for(int i = in.getLineNumber() - 1; i &lt; t.length; i++) {
          d[i] = Double.parseDouble(t[i]);
        }
        correlation[in.getLineNumber() - 2] = d;
      }
    }
    
    // Vertexの配列を作ってそれぞれに参照を代入
    Vertex[] vertices = new Vertex[names.length];
    for(int i = 0; i &lt; names.length; i++) {
      vertices[i] = graph.addVertex(new UndirectedSparseVertex());
    }
    
    // 閾値以上の相関係数を持っているVertex同士にEdgeを結ぶ
    for(int i = 0; i &lt; correlation.length - 1; i++) {
      for(int j = i + 1; j &lt; correlation[i].length; j++) {
        double current = correlation[i][j];
        if(current &gt;= threshold || current &lt;= -threshold) {
          graph.addEdge(new UndirectedSparseEdge(vertices[i], vertices[j]));
        }
      }
    }
    
    Layout layout = new FRLayout(graph);
    PluggableRenderer renderer = new PluggableRenderer();

    VisualizationViewer viewer = new VisualizationViewer(layout, renderer);
    
    window.add(viewer);
    window.setSize(600, 600);
    window.setLocationRelativeTo(null);
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    window.setVisible(true);
  }
}</code></pre>
<table id="item4056_fig1">
<caption>図1: まず表示させてみた</caption>
<tbody>
<tr><td><img src="/figure/2008/10/25/a" alt="" /></td></tr>
</tbody>
</table>
<h2>ノードの名前を表示させる</h2>
<p>丸と線しかないので何がなんだかわからない。どのアイスがどの頂点に対応しているのかがわからないと解釈のしようがない。そのために<a href="http://jung.sourceforge.net/doc/api/edu/uci/ics/jung/graph/decorators/StringLabeller.html" title="StringLabeller (JUNG 1.7.6 API)">StringLabeller</a>を使う。あと、頂点と頂点を結ぶ線に相関係数のデータを含ませるために<a href="http://jung.sourceforge.net/doc/api/edu/uci/ics/jung/graph/decorators/EdgeWeightLabeller.html" title="EdgeWeightLabeller (JUNG 1.7.6 API)">EdgeWeightLabeller</a>が使える。該当部分を書き直してみると:</p>
<pre><code class="java">    // Vertexの配列を作ってそれぞれに参照を代入
    Vertex[] vertices = new Vertex[names.length];
    final StringLabeller stringLabeller = StringLabeller.getLabeller(graph);
    final EdgeWeightLabeller weightLabeller = EdgeWeightLabeller.getLabeller(graph);
    
    for(int i = 0; i &lt; names.length; i++) {
      vertices[i] = graph.addVertex(new UndirectedSparseVertex());
      try {
        stringLabeller.setLabel(vertices[i], names[i]);
      } catch (UniqueLabelException e1) {
        e1.printStackTrace();
      }
    }
    
    // 閾値以上の相関係数を持っているVertex同士にEdgeを結ぶ
    for(int i = 0; i &lt; correlation.length - 1; i++) {
      for(int j = i + 1; j &lt; correlation[i].length; j++) {
        double current = correlation[i][j];
        if(current &gt;= threshold || current &lt;= -threshold) {
          Edge e = graph.addEdge(new UndirectedSparseEdge(vertices[i], vertices[j]));
          weightLabeller.setNumber(e, current);
        }
      }
    }</code></pre>
<p>そして<a href="http://jung.sourceforge.net/doc/api/edu/uci/ics/jung/visualization/PluggableRenderer.html" title="PluggableRenderer (JUNG 1.7.6 API)">PluggableRenderer</a>に:</p>
<pre><code class="java">    renderer.setVertexStringer(new VertexStringer() {
      public String getLabel(ArchetypeVertex v) {
        return stringLabeller.getLabel(v);
      }
    });</code></pre>
<p>とすると<a href="#item4056_fig2">下図</a>のようにノードに名前が表示されるようになる。グラフがどのように表示されるかは実行のたびに変化するが、トポロジー的には変化していない。<a href="http://www.techscore.com/tech/Others/Jung/04_03.html" title="Jung-TECHSCORE-">TECHSCOREの解説</a>ではUserDataContainerを使っているが、StringLabellerを使うほうが直感的だと思う。執筆時にはなかった機能なのかもしれない。</p>
<table id="item4056_fig2">
<caption>図2: ノードに名前が表示された</caption>
<tbody>
<tr><td><img src="/figure/2008/10/25/b" alt="" /></td></tr>
</tbody>
</table>
<h2>相関がプラスかマイナスかで色を変える</h2>
<p>さきほどEdgeWeightLabellerに相関係数を入れたので、これを使って辺に色をつけてみる。こういうのはPluggableRendererをいじると実現できる。</p>
<pre><code class="java">    renderer.setEdgePaintFunction(new EdgePaintFunction() {
      public Paint getDrawPaint(Edge e) {
        return weightLabeller.getNumber(e).doubleValue() > 0
               ? Color.PINK
               : Color.CYAN;
      }
      public Paint getFillPaint(Edge e) {
        return null;
      }
    });</code></pre>
<table id="item4056_fig3">
<caption>図3: 色をつけた</caption>
<tbody>
<tr><td><img src="/figure/2008/10/25/c" alt="" /></td></tr>
</tbody>
</table>
<h2>相関の強さに応じて線の種類を変える</h2>
<p>同様に、EdgeWeightLabellerを使って辺の種類も変えてみる。</p>
<p>たとえば、相関係数0.4未満を点線、0.4以上を太線にするなら:</p>
<pre><code class="java">    renderer.setEdgeStrokeFunction(new EdgeStrokeFunction() {
      public Stroke getStroke(Edge e) {
        return Math.abs(weightLabeller.getNumber(e).doubleValue()) &lt; 0.4
               ? PluggableRenderer.DOTTED
               : new BasicStroke(2);
      }
    });</code></pre>
<table id="item4056_fig4">
<caption>図4: だいぶ見通しがついてきた</caption>
<tbody>
<tr><td><img src="/figure/2008/10/25/d" alt="" /></td></tr>
</tbody>
</table>
<h2>選択されたノードと、それに隣接しているノードの色を変える</h2>
<p>頂点をクリックすると、選択された頂点と辺で結ばれた隣の頂点の色と選択された頂点から延びる辺の色が変わるようにしたい。</p>
<p>頂点や辺が選択されたことを検知するには<a href="http://jung.sourceforge.net/doc/api/edu/uci/ics/jung/visualization/PickedInfo.html" title="PickedInfo (JUNG 1.7.6 API)">PickedInfo</a>を使う。PluggableRendererはPickedInfoインタフェースを実装しているが、PluggableRenderer#isPicked()はDeprecatedなので、PickedInfoにキャストしてからisPickedメソッドを実行する必要がある。先ほどいじっていたPluggableRenderer#setEdgePaintFunction()とPluggableRenderer#setEdgeStrokeFunction()、あと加えてPluggableRenderer#setVertexPaintFunction()を変更する。非選択ノードをデフォルトの赤から灰色に変えた上で選択されたノードは橙色に、隣接するノードのうち相関係数がプラスなのは赤でマイナスなのは青に、隣接するアークも同様に相関係数によって青か赤に変更し、点線も太くしよう。内部クラスからrendererを呼ぶので、rendererにfinal宣言が必要。</p>
<pre><code class="java">    renderer.setVertexPaintFunction(new VertexPaintFunction() {
      public Paint getDrawPaint(Vertex v) {
        return Color.DARK_GRAY;
      }

      public Paint getFillPaint(Vertex v) {
        if(((PickedInfo)renderer).isPicked(v))
          return Color.ORANGE;
        for(Object n : v.getNeighbors()) {
          if(((PickedInfo)renderer).isPicked((Vertex)n))
            return weightLabeller.getNumber(v.findEdge((Vertex)n)).doubleValue() &lt; 0
                   ? Color.BLUE
                   : Color.RED;
        }
        return Color.LIGHT_GRAY;
      }
    });
    renderer.setEdgePaintFunction(new EdgePaintFunction() {
      public Paint getDrawPaint(Edge e) {
        for(Object v : e.getIncidentVertices()) {
          if(((PickedInfo)renderer).isPicked((Vertex)v)) {
            return weightLabeller.getNumber(e).doubleValue() &lt; 0
                   ? Color.BLUE
                   : Color.RED;
          }
        }
        return weightLabeller.getNumber(e).doubleValue() > 0
               ? Color.PINK
               : Color.CYAN;
      }
      public Paint getFillPaint(Edge e) {
        return null;
      }
    });
    renderer.setEdgeStrokeFunction(new EdgeStrokeFunction() {
      public Stroke getStroke(Edge e) {
        for(Object v : e.getIncidentVertices()) {
          if(((PickedInfo)renderer).isPicked((Vertex)v)) {
            return Math.abs(weightLabeller.getNumber(e).doubleValue()) &lt; 0.4
                   ? new BasicStroke(2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1.0f, new float[]{1.0f, 5.0f}, 0f)
                   : new BasicStroke(2);
          }
        }
        return Math.abs(weightLabeller.getNumber(e).doubleValue()) &lt; 0.4
               ? PluggableRenderer.DOTTED
               : new BasicStroke(2);
      }
    });</code></pre>
<table id="item4056_fig5">
<caption>図5: 選択されたノードとその隣接ノードの表現を変えた</caption>
<tbody>
<tr><td><img src="/figure/2008/10/25/e" alt="" /></td></tr>
</tbody>
</table>
<h2>PluggableGraphMouseで操作性を向上する</h2>
<p>ノードをクリックして自分自身と隣接ノードの色を変えられたのはいいが、左ボタンから指を離すと色が元に戻ってしまう。それが不便なときは<a href="http://jung.sourceforge.net/doc/api/edu/uci/ics/jung/visualization/control/PickingGraphMousePlugin.html" title="PickingGraphMousePlugin (JUNG 1.7.6 API)">PickingGraphMousePlugin</a>を<a href="http://jung.sourceforge.net/doc/api/edu/uci/ics/jung/visualization/control/PluggableGraphMouse.html" title="PluggableGraphMouse (JUNG 1.7.6 API)">PluggableGraphMouse</a>に加えるとよい。</p>
<pre><code class="java">    PluggableGraphMouse gm = new PluggableGraphMouse();
    gm.add(new PickingGraphMousePlugin());
    
    VisualizationViewer viewer = new VisualizationViewer(layout, renderer);
    viewer.setGraphMouse(gm);</code></pre>
<p>その他、<em>グラフを回転させたい</em>なら<a href="http://leda.science.uoit.ca/java-libraries/jung-1.7.6/doc/edu/uci/ics/jung/visualization/control/RotatingGraphMousePlugin.html" title="RotatingGraphMousePlugin (JUNG 1.7.6 API)">RotatingGraphMousePlugin</a> (Shiftを押しながらドラッグするとグラフを回転できる)を、PDFビューワのように<em>ドラッグでグラフ表示領域の移動がしたい</em>なら<a href="http://leda.science.uoit.ca/java-libraries/jung-1.7.6/doc/edu/uci/ics/jung/visualization/control/TranslatingGraphMousePlugin.html" title="TranslatingGraphMousePlugin (JUNG 1.7.6 API)">TranslatingGraphMousePlugin</a>を、<em>ホイール回転で拡大縮小させたい</em>なら<a href="http://jung.sourceforge.net/doc/api/edu/uci/ics/jung/visualization/control/ScalingGraphMousePlugin.html" title="ScalingGraphMousePlugin (JUNG 1.7.6 API)">ScalingGraphMousePlugin</a>をそれぞれPluggableGraphMouseにaddしていくとよい。こういうビジュアルな効果はこだわりだすと果てしないけどやってて面白い。拡大したときとかにスクロールバーがほしければ<a href="http://jung.sourceforge.net/doc/api/edu/uci/ics/jung/visualization/GraphZoomScrollPane.html" title="GraphZoomScrollPane (JUNG 1.7.6 API)">GraphZoomScrollPane</a>をJFrameオブジェクトにaddすれば表示されるようになる。</p>
<table id="item4056_fig6">
<caption>図6: ズームとスクロールバー</caption>
<tbody>
<tr><td><img src="/figure/2008/10/25/f" alt="" /></td></tr>
</tbody>
</table>
<p>最終的にソースは以下のようになった:</p>
<pre><code class="java">package net.txqz.neta;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Paint;
import java.awt.Stroke;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;

import javax.swing.JFrame;

import edu.uci.ics.jung.graph.ArchetypeVertex;
import edu.uci.ics.jung.graph.Edge;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.Vertex;
import edu.uci.ics.jung.graph.decorators.EdgePaintFunction;
import edu.uci.ics.jung.graph.decorators.EdgeStrokeFunction;
import edu.uci.ics.jung.graph.decorators.EdgeWeightLabeller;
import edu.uci.ics.jung.graph.decorators.StringLabeller;
import edu.uci.ics.jung.graph.decorators.VertexPaintFunction;
import edu.uci.ics.jung.graph.decorators.VertexStringer;
import edu.uci.ics.jung.graph.decorators.StringLabeller.UniqueLabelException;
import edu.uci.ics.jung.graph.impl.UndirectedSparseEdge;
import edu.uci.ics.jung.graph.impl.UndirectedSparseGraph;
import edu.uci.ics.jung.graph.impl.UndirectedSparseVertex;
import edu.uci.ics.jung.visualization.FRLayout;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.Layout;
import edu.uci.ics.jung.visualization.PickedInfo;
import edu.uci.ics.jung.visualization.PluggableRenderer;
import edu.uci.ics.jung.visualization.ShapePickSupport;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.LayoutScalingControl;
import edu.uci.ics.jung.visualization.control.PickingGraphMousePlugin;
import edu.uci.ics.jung.visualization.control.PluggableGraphMouse;
import edu.uci.ics.jung.visualization.control.RotatingGraphMousePlugin;
import edu.uci.ics.jung.visualization.control.ScalingGraphMousePlugin;
import edu.uci.ics.jung.visualization.control.TranslatingGraphMousePlugin;

public class RelationGraph {
  public static void main(String[] args) throws NumberFormatException, IOException {
    JFrame window = new JFrame("RelationGraph");
    final Graph graph = new UndirectedSparseGraph();
    double threshold = 0.2;
    // 表頭変数の配列
    String[] names = null;
    // 
    double[][] correlation = null;
    LineNumberReader in = new LineNumberReader(
        new InputStreamReader(new FileInputStream("D:\\data\\icecream.txt"), "MS932")
    );
    String line;
    while((line = in.readLine()) != null) {
      // 1行目は表頭変数。ついでに列の数も数えて配列を作成する。
      if(in.getLineNumber() == 1) {
        names = line.split("\t");
        correlation = new double[names.length][names.length];
      }
      // 2行目以降はn行目のデータを配列の[n-2]番目に入れる
      else {
        String[] t = line.split("\t");
        double[] d = new double[names.length];
        for(int i = in.getLineNumber() - 1; i &lt; t.length; i++) {
          d[i] = Double.parseDouble(t[i]);
        }
        correlation[in.getLineNumber() - 2] = d;
      }
    }
    
    // Vertexの配列を作ってそれぞれに参照を代入
    Vertex[] vertices = new Vertex[names.length];
    final StringLabeller stringLabeller = StringLabeller.getLabeller(graph);
    final EdgeWeightLabeller weightLabeller = EdgeWeightLabeller.getLabeller(graph);
    
    for(int i = 0; i &lt; names.length; i++) {
      vertices[i] = graph.addVertex(new UndirectedSparseVertex());
      try {
        stringLabeller.setLabel(vertices[i], names[i]);
      } catch (UniqueLabelException e1) {
        e1.printStackTrace();
      }
    }
    
    // 閾値以上の相関係数を持っているVertex同士にEdgeを結ぶ
    for(int i = 0; i &lt; correlation.length - 1; i++) {
      for(int j = i + 1; j &lt; correlation[i].length; j++) {
        double current = correlation[i][j];
        if(current >= threshold || current &lt;= -threshold) {
          Edge e = graph.addEdge(new UndirectedSparseEdge(vertices[i], vertices[j]));
          weightLabeller.setNumber(e, current);
        }
      }
    }
    
    Layout layout = new FRLayout(graph);
    final PluggableRenderer renderer = new PluggableRenderer();

    renderer.setVertexStringer(new VertexStringer() {
      public String getLabel(ArchetypeVertex v) {
        return stringLabeller.getLabel(v);
      }
    });

    renderer.setVertexPaintFunction(new VertexPaintFunction() {
      public Paint getDrawPaint(Vertex v) {
        return Color.DARK_GRAY;
      }
      
      public Paint getFillPaint(Vertex v) {
        if(((PickedInfo)renderer).isPicked(v))
          return Color.ORANGE;
        for(Object n : v.getNeighbors()) {
          if(((PickedInfo)renderer).isPicked((Vertex)n))
            return weightLabeller.getNumber(v.findEdge((Vertex)n)).floatValue() &lt; 0
                   ? Color.BLUE
                   : Color.RED;
        }
        return Color.LIGHT_GRAY;
      }
    });
    renderer.setEdgePaintFunction(new EdgePaintFunction() {
      public Paint getDrawPaint(Edge e) {
        for(Object v : e.getIncidentVertices()) {
          if(((PickedInfo)renderer).isPicked((Vertex)v)) {
            return weightLabeller.getNumber(e).floatValue() &lt; 0
                   ? Color.BLUE
                   : Color.RED;
          }
        }
        return weightLabeller.getNumber(e).doubleValue() > 0
               ? Color.PINK
               : Color.CYAN;
      }
      public Paint getFillPaint(Edge e) {
        return null;
      }
    });
    renderer.setEdgeStrokeFunction(new EdgeStrokeFunction() {
      public Stroke getStroke(Edge e) {
        for(Object v : e.getIncidentVertices()) {
          if(((PickedInfo)renderer).isPicked((Vertex)v)) {
            return Math.abs(weightLabeller.getNumber(e).floatValue()) &lt; 0.4
                   ? new BasicStroke(2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1.0f, new float[]{1.0f, 5.0f}, 0f)
                   : new BasicStroke(2);
          }
        }
        return Math.abs(weightLabeller.getNumber(e).floatValue()) &lt; 0.4
               ? PluggableRenderer.DOTTED
               : new BasicStroke(2);
      }
    });

    PluggableGraphMouse gm = new PluggableGraphMouse();
    gm.add(new PickingGraphMousePlugin());
    gm.add(new RotatingGraphMousePlugin());
    gm.add(new TranslatingGraphMousePlugin());
    gm.add(new ScalingGraphMousePlugin(new LayoutScalingControl(), 0));
    
    VisualizationViewer viewer = new VisualizationViewer(layout, renderer);
    viewer.setGraphMouse(gm);
    viewer.setPickSupport(new ShapePickSupport(viewer, viewer, renderer, 2));
    
    window.add(viewer);
    window.setSize(600, 600);
    window.setLocationRelativeTo(null);
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    window.add(new GraphZoomScrollPane(viewer));
    window.setVisible(true);
  }
}</code></pre>
<p>マジックナンバーが多いとか、そもそもこんなの全部mainメソッドの中でやっていいのかとか、まああるけど簡単なサンプルということで。あと、このサーバでJavaが動けばこの下にAppletとか置けてよりそれっぽい紹介ができるのだけど、動かないので残念。まあ、ヘタにAppletなんか置くとページの読み込みが激重になるだろうし、いいか。</p>
		</div>
	</content>
	<category term="Jung"/>
	<category term="Java"/>
	<category term="ライブラリ"/>
	<category term="グラフ"/>
	<category term="相関行列"/>
	<category term="相関係数"/>
	<category term="可視化"/>
	<trackback:ping>http://txqz.net/blog/2008/10/25/1155/tb</trackback:ping>
	<published>2008-10-25T11:55:10+09:00</published>
	<updated>2008-10-25T11:55:10+09:00</updated>
	<rights>Attribution-Noncommercial-Share Alike 3.0 Unported</rights>
</entry>