はじめに †
とある授業で使うかもしれないのと、自分で前から作ってみたかったのでぱぱっと実装。
基本はビジュアライジング・データ のサンプルコードを拡張して作りました。
ある映画監督のキャストをネットワークグラフで表示するものです。
サンプルプログラムの実行 †
右のメニューの「Download」をクリックします。 †
No Donationを選択して(もちろんDonationしてもOKです)Downloadをクリック †
Downloadをクリック †
自分のPCの環境に合わせて選択。この例ではWindows 64 bit †
ダウンロードファイルの保存場所の指定。この例ではデスクトップ。 †
ダウンロードしたファイルをデスクトップで解凍して中のprocessing.exeをダブルクリック。 †
Processingメニューの「File」をクリック。
一番最初にダウンロードしたサンプルプログラムの中のnetwork_visualization.pdeをクリック。 †
再生ボタンをクリック。 †
ネットワークグラフが表示される。 †
ソースコード解説 †
processingのコアとなるのは
起動時に一度だけ実行されるsetup関数
画面描写の度に実行されるdraw関数
の2つです。
setup関数 †
int nodeCount;
Node[] nodes = new Node[100];
HashMap nodeTable = new HashMap();
int edgeCount;
Edge[] edges = new Edge[500];
static final color selectColor = #FF3030;
static final color fixedColor = #FF8080;
static final color edgeColor = #000000;
static final int minimum_size = 2;
PFont font;
void setup() {
size(1000, 700);
loadData();
font = createFont("Meiryo UI", 10);
textFont(font);
smooth();
}
起動時に一度だけ実行される関数です。
主に初期化処理を実行しています。
sizeはウィンドウのサイズ、loadDataはデータの読み込み、createFont、textFont、smoothはフォントを設定して表示を滑らかにしています。
loadData関数 †
void loadData() {
String[] lines = loadStrings("sample.txt");
String[] data;
for(int i = 0; i < lines.length; i++){
data = split(lines[i], ',');
addEdge(data[0], data[1]);
}
}
起動時にsetup関数経由で実行される関数です。
CSVファイルを配列に変換してグラフを生成しています。
sample.txtから一行ずつ取ってきてsplitで分割しています。
addEdgeはデータ列の一番目と二番目をつなぐグラフを生成ます。
例えば、sample.txtにCSV形式で
天空の蜂,江口洋介
天空の蜂,本木雅弘
天空の蜂,仲間由紀恵
と書かれていた場合には
天空の蜂⇔江口洋介
天空の蜂⇔本木雅弘
天空の蜂⇔仲間由紀恵
をそれぞれ接続したグラフが生成されます。
addEdge関数 †
void addEdge(String fromLabel, String toLabel) {
Node from = findNode(fromLabel);
Node to = findNode(toLabel);
from.increment();
from.nodeColor = #FFFFFF;
to.nodeColor = #FF0000;
to.increment();
for (int i = 0; i < edgeCount; i++) {
if (edges[i].from == from && edges[i].to == to) {
edges[i].increment();
return;
}
}
Edge e = new Edge(from, to);
e.increment();
if(edgeCount == edges.length){
edges = (Edge[]) expand(edges);
}
edges[edgeCount++] = e;
}
起動時にsetup関数→loadData関数経由で実行される関数です。
以下の処理を実行します。
fromLabelとtoLabelに指定されたノードを読み込み
それぞれの接続数をincrementで追加
既に同じ接続(edge)が存在するか確認
存在する場合にはそこで関数は終了
存在しない場合には接続をedgeとして新たに作成
edgeは元々「Edge[] edges = new Edge[500]」で500個の配列で作成されているが、配列が足りなくなったらexpandで2倍のサイズに拡張。
findNode関数 †
Node findNode(String label) {
label = label.toLowerCase();
Node n = (Node) nodeTable.get(label);
if (n == null) {
return addNode(label);
}
return n;
}
addEdge関数から実行される関数です。
既にそのラベルのノードが作られているかどうかを調べます。
もしそのラベルのノードが存在する場合には該当ノードを返します。
もしそのラベルのノードが存在しない場合にはaddNode関数で新たなノードを作成して、作成したノードを返します。
addNode関数 †
Node addNode(String label){
Node n = new Node(label);
if(nodeCount == nodes.length){
nodes = (Node[]) expand(nodes);
}
nodeTable.put(label, n);
nodes[nodeCount++] = n;
return n;
}
findNode関数から実行される関数です。
新しいノードを作成して、配列nodesのサイズが足りなくなったら配列をexpand関数で2倍に増やします。
draw関数 †
void draw() {
if (record) {
beginRecord(PDF, "output.pdf");
}
background(#FFFFFF);
for(int i = 0; i < edgeCount; i++){
edges[i].relax();
}
for(int i = 0; i < nodeCount; i++){
nodes[i].relax();
}
for(int i = 0; i < nodeCount; i++){
nodes[i].update();
}
for (int i = 0; i < edgeCount ; i++){
if(edges[i].from.count >= 1 &&
edges[i].to.count >= 1){
edges[i].draw();
}
}
for(int i = 0; i < nodeCount; i++){
if(nodes[i].count >= 1){
nodes[i].draw();
}
}
if(record){
endRecord();
record = false;
}
}
描画の度に実行される関数です。
まず一番外側のrecordに関係する部分はpdfにグラフを出力する際に使用します。
rキーを押すとrecordがtrueになって中が実行されます。
おわりに †
データの取得に関しては別で解説します。