「proce55ing-gr01」の編集履歴(バックアップ)一覧に戻る

proce55ing-gr01 - (2009/01/29 (木) 13:19:04) のソース

*Processingでgraph

『ビジュアライジング・データ Processingによる情報視覚化手法』
#amazon(4873113784)

を見ながらグラフを書いてみようと思います。
参考:pp.229-238



&bold(){使うもの:}Processing

----

・はまりやすい?エラー
"PFont"を"Pfont"と書いてるのに気付かなかった…
「cannnot find a class or type named "Pfont"」と出るのです。

あとは、これを書くだけです。↓
#highlight(c){{//*- This program is VisualisingData's p229-238 -*//

int nodeCount;
Node[] nodes = new Node[100];
HashMap nodeTable = new HashMap();

int edgeCount;
Edge[] edges = new Edge[500];

static final color nodeColor = #F0C070; //node box background color
static final color selectColor = #FF3030; //dragging color
static final color fixedColor = #FF8080; //click->固定color
static final color edgeColor = #000000; //line color

PFont font;

void setup(){
  size(600, 600);
  loadData();
//  font = loadFont("SansSerif.plain-12.vlw");
  font = createFont("SansSerif", 10);
  textFont(font);
  smooth();
}

void loadData(){
  addEdge("joe", "food");
  addEdge("joe", "dog");
  addEdge("joe", "tea");
  addEdge("joe", "cat");
  addEdge("joe", "table");
  addEdge("table", "plate");
  addEdge("plate", "food");
  addEdge("food", "mouse");
  addEdge("food", "dog");
  addEdge("mouse", "cat");
  
  addEdge("table", "cup");
  addEdge("cup", "tea");
  addEdge("dog", "cat");
  addEdge("cup", "spoon");
  addEdge("plate", "fork");
  
  addEdge("dog", "flea1");
  addEdge("dog", "flea2");
  addEdge("flea1", "flea2");
  addEdge("plate", "knife");
}

// 名前でノードを見つけ出す。見つからなかったノードは新規に追加
void addEdge(String fromLabel, String toLabel){
  Node from = findNode(fromLabel);
  Node to = findNode(toLabel);
  Edge e = new Edge(from, to);
  if (edgeCount == edges.length){
    edges = (Edge[]) expand(edges);
  }
  edges[edgeCount++] = e;
}

// ラベルからノードを見つける
Node findNode(String label){
  label = label.toLowerCase();
  Node n = (Node) nodeTable.get(label);
  if (n == null){
    return addNode(label);
  }
  return n;
}

// 名前での検索を可能にするためnodeTableへの追加も
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;
}

void draw(){
  background(255);
  
  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++){
    edges[i].draw();
  }
  for (int i = 0 ; i < nodeCount ; i++){
    nodes[i].draw();
  }
}

//*- マウスでノード操作できるように -*//
Node selection;

void mousePressed(){
  // これ以上に離れているノードはすべて無視
  float closest = 20;
  for (int i = 0 ; i < nodeCount; i++){
    Node n = nodes[i];
    float d = dist(mouseX, mouseY, n.x, n.y);
    if (d < closest){
      selection = n;
      closest = d;
    }
  }
  if (selection != null){
    if (mouseButton == LEFT){
      selection.fixed = true;
    } else if (mouseButton == RIGHT){
      selection.fixed = false;
    }
  }
}

void mouseDragged(){
  if (selection != null){
    selection.x = mouseX;
    selection.y = mouseY;
  }
}

void mouseReleased(){
  selection = null;
}

class Edge{
  Node from;
  Node to;
  float len;
  
  Edge(Node from, Node to){
    this.from = from;
    this.to = to;
    this.len = 50;
  }
  
  void relax(){
    float vx = to.x - from.x;
    float vy = to.y - from.y;
    float d = mag(vx, vy);
    if (d > 0){
      float f = (len - d) / (d * 3);
      float dx = f * vx;
      float dy = f * vy;
      to.dx -= dx;
      to.dy -= dy;
    }
  }
  
  void draw(){
    stroke(edgeColor);
    strokeWeight(0.35);
    line(from.x, from.y, to.x, to.y);
  }
}

class Node{
  float x, y;
  float dx, dy;
  boolean fixed;
  String label;
  
  Node(String label){
    this.label = label;
    x = random(width);
    y = random(height);
  }
  
  void relax(){
    float ddx = 0;
    float ddy = 0;
    
    for (int j = 0 ; j < nodeCount; j++){
      Node n = nodes[j];
      if (n != this){
        float vx = x - n.x;
        float vy = y - n.y;
        float lensq = vx * vx + vy * vy;
        if (lensq == 0){
          ddx += random(1);
          ddy += random(1);
        } else if (lensq < 100*100){
        ddx += vx / lensq;
        ddy += vy / lensq;
        }
      }
    }
    float dlen = mag(ddx, ddy) /2;
    if (dlen > 0){
      dx += ddx /dlen;
      dy += ddy /dlen;
    }
  }
  
  void update(){
    if (!fixed){
      x += constrain(dx, -5, 5);
      y += constrain(dy, -5, 5);
      
      x = constrain(x, 0, width);
      y = constrain(y, 0, height);
    }
    dx /= 2;
    dy /= 2;
  }
  
  void draw(){
    if (selection == this){
      fill(selectColor);
    } else if (fixed){
      fill(fixedColor);
    } else {
      fill(nodeColor);
    }
    
    stroke(0);
    strokeWeight(0.5);
    
    rectMode(CORNER);
    float w = textWidth(label) + 10;
    float h = textAscent() + textDescent() + 4;
    rect(x - w/2, y - h/2, w, h);
    
    fill(0);
    textAlign(CENTER, CENTER);
    text(label, x, y);
  }
}
}}

・実行したら、こういうのが見えるはず。
#image(graph01.gif,center)

・これをマウスで適当に置きなおすとこうなります。
#image(graph02.gif,center)

・次は、どうしたらこれを自動できれいに配置できるか、とかやる予定。

----



----
today: &counter(today)
yesterday: &counter(yesterday)