自分用にp50あたりのソースコードを貼っておく。どこかで公開してるはずだけどとりあえず。
sketch
PImage mapImage; Table locationTable; Table nameTable; int rowCount; Table dataTable; float dataMin = -10; float dataMax = 10; Integrator[] interpolators; void setup(){ size(640, 400); mapImage = loadImage("map.png"); locationTable = new Table("locations.tsv"); rowCount = locationTable.getRowCount(); // read the data table. dataTable = new Table("random.tsv"); nameTable = new Table("names.tsv"); // setup: loat initial values into the integrator. interpolators = new Integrator[rowCount]; for(int row = 0; row < rowCount; row++){ float initialValue = dataTable.getFloat(row, 1); interpolators[row] = new Integrator(initialValue, 0.9, 0.1); } } // global variables set in drawdata() and read in draw() float closestDist; String closestText; float closestTextX; float closestTextY; void draw(){ background(255); image(mapImage, 0, 0); // draw: update the integrator with the current values, // which are either those from the setup() function // or those loaded by the target() functin issued in // updateTable(). for(int row = 0; row < rowCount; row++){ interpolators[row].update(); } closestDist = MAX_FLOAT; smooth(); fill(192, 0, 0); noStroke(); for(int row = 0; row < rowCount; row++){ String abbrev = dataTable.getRowName(row); float x = locationTable.getFloat(abbrev, 1); float y = locationTable.getFloat(abbrev, 2); drawData(x, y, abbrev); } if(closestDist != MAX_FLOAT){ fill(0); textAlign(CENTER); text(closestText, closestTextX, closestTextY); } PFont font = loadFont("Universe-Bold-12.vlw"); textFont(font); } void drawData(float x, float y, String abbrev){ // figure out what row this is. int row = dataTable.getRowIndex(abbrev); // get the current value. float value = interpolators[row].value; float radius = 0; if(value >= 0){ radius = map(value, 0, dataMax, 1.5, 15); fill(#4422CC); // blue } else { radius = map(value, 0, dataMin, 1.5, 15); fill(#FF4422); // red } ellipseMode(RADIUS); ellipse(x, y, radius, radius); float d = dist(x, y, mouseX, mouseY); if((d <radius + 2) && (d < closestDist)){ closestDist = d; String name = nameTable.getString(abbrev, 1); // use target (not current) value for showing the data point. String val = nfp(interpolators[row].target, 0, 2); closestText = name + " " + val; closestTextX = x; closestTextY = y-radius-4; } } void keyPressed(){ if(key == ' '){ updateTable(); } } void updateTable(){ for(int row = 0; row < rowCount; row++){ float newValue = random(-10, 10); interpolators[row].target(newValue); } }
Integrator
class Integrator { final float DAMPING = 0.5f; final float ATTRACTION = 0.2f; float value; float vel; float accel; float force; float mass = 1; float damping = DAMPING; float attraction = ATTRACTION; boolean targeting; float target; Integrator() { } Integrator(float value) { this.value = value; } Integrator(float value, float damping, float attraction) { this.value = value; this.damping = damping; this.attraction = attraction; } void set(float v) { value = v; } void update() { if (targeting) { force += attraction * (target - value); } accel = force / mass; vel = (vel + accel) * damping; value += vel; force = 0; } void target(float t) { targeting = true; target = t; } void noTarget() { targeting = false; } }
Table
class Table { String[][] data; int rowCount; Table() { data = new String[10][10]; } Table(String filename) { String[] rows = loadStrings(filename); data = new String[rows.length][]; for (int i = 0; i < rows.length; i++) { if (trim(rows[i]).length() == 0) { continue; // skip empty rows } if (rows[i].startsWith("#")) { continue; // skip comment lines } // split the row on the tabs String[] pieces = split(rows[i], TAB); // copy to the table array data[rowCount] = pieces; rowCount++; // this could be done in one fell swoop via: //data[rowCount++] = split(rows[i], TAB); } // resize the 'data' array as necessary data = (String[][]) subset(data, 0, rowCount); } int getRowCount() { return rowCount; } // find a row by its name, returns -1 if no row found int getRowIndex(String name) { for (int i = 0; i < rowCount; i++) { if (data[i][0].equals(name)) { return i; } } println("No row named '" + name + "' was found"); return -1; } String getRowName(int row) { return getString(row, 0); } String getString(int rowIndex, int column) { return data[rowIndex][column]; } String getString(String rowName, int column) { return getString(getRowIndex(rowName), column); } int getInt(String rowName, int column) { return parseInt(getString(rowName, column)); } int getInt(int rowIndex, int column) { return parseInt(getString(rowIndex, column)); } float getFloat(String rowName, int column) { return parseFloat(getString(rowName, column)); } float getFloat(int rowIndex, int column) { return parseFloat(getString(rowIndex, column)); } void setRowName(int row, String what) { data[row][0] = what; } void setString(int rowIndex, int column, String what) { data[rowIndex][column] = what; } void setString(String rowName, int column, String what) { int rowIndex = getRowIndex(rowName); data[rowIndex][column] = what; } void setInt(int rowIndex, int column, int what) { data[rowIndex][column] = str(what); } void setInt(String rowName, int column, int what) { int rowIndex = getRowIndex(rowName); data[rowIndex][column] = str(what); } void setFloat(int rowIndex, int column, float what) { data[rowIndex][column] = str(what); } void setFloat(String rowName, int column, float what) { int rowIndex = getRowIndex(rowName); data[rowIndex][column] = str(what); } // Write this table as a TSV file void write(PrintWriter writer) { for (int i = 0; i < rowCount; i++) { for (int j = 0; j < data[i].length; j++) { if (j != 0) { writer.print(TAB); } if (data[i][j] != null) { writer.print(data[i][j]); } } writer.println(); } writer.flush(); } }