Processing Code

import traer.physics.*;

//variables for the contact particles
ParticleSystem physics;
Particle[] contacts;

//variables for the contact information, stored by unique id
String[] contactNames; //email address of each contact
int[] numEmails; //number of emails exchanged with contact
int[] ringNumber; //which ring the contact is in
String[] neighbors; //a neighbor list in string format for each contact
float maxEmailNumber = 0; //the largest amount of emails exchanged with one email address

//these define properties of how the visualization looks
int ring1radius = 100;
int ring2radius = 175;
int ring3radius = 250;
int ring4radius = 325;
int minCircleSize = 5;
int maxCircleSize = 50;

PFont emailFont, numberFont;
int selectedID = 0;

boolean mouseDown = false;
boolean contactSelected = false;

//parse the information from the text files and set up the physics
void setup() {
  size( 1000, 800 );
  smooth();
  ellipseMode( CENTER );
  physics = new ParticleSystem( 0, 0.1 );

  //parse the information from contacts.txt
  String[] lines = loadStrings("contacts.txt");
  String[] pieces;
  contacts = new Particle[lines.length+1];
  numEmails = new int[lines.length+1];
  ringNumber = new int[lines.length+1];
  contactNames = new String[lines.length+1];
  for (int counter = 0; counter 2){
       int currentID = int(pieces[0]);
       contacts[currentID] = physics.makeParticle( 1.0, random( 0, width ), random( 0, height ), 0 );
       numEmails[currentID] = int(pieces[2]);
       if(numEmails[currentID]>maxEmailNumber) 
          maxEmailNumber = numEmails[currentID];
       contactNames[currentID] = pieces[1];
       ringNumber[currentID] = int(pieces[3]);
     }
  }
  
  //make every contact repel each other to minimize overlapping & create smooth animation
  float minDist;
  for (int counter = 1; counter1){
        id1= int(pieces[0]);
        neighbors[id1] = pieces[1];
      }
  }

  //load the fonts to use
  emailFont = loadFont("AngsanaNew-BoldItalic-24.vlw"); 
  numberFont = loadFont("BrowalliaNew-18.vlw"); 
}

//draw the visualization
void draw()
{
  physics.tick();
  background(255);
  
  //draw the circles
  fill(255);
  stroke(0);
  strokeWeight(2);
  ellipse(width/2, height/2, ring4radius*2, ring4radius*2);
  ellipse(width/2, height/2, ring3radius*2, ring3radius*2);
  ellipse(width/2, height/2, ring2radius*2, ring2radius*2);
  ellipse(width/2, height/2, ring1radius*2, ring1radius*2);
  strokeWeight(1);
  stroke(0);
  fill(0);
  ellipse(width/2, height/2, 5, 5);

  //draw the selected contact first so that it will be on the bottom
  if (contactSelected){
    //draw the lines for the connections
    String[] pieces = split(neighbors[selectedID], ';');
    for (int counter2 = 0; counter2 1)
      text(numEmails[selectedID] + " emails exchanged", contacts[selectedID].position().x() + ((numEmails[selectedID]/maxEmailNumber)*maxCircleSize)/2 + minCircleSize + 5, contacts[selectedID].position().y()+15, 200, 25);
    else
      text("1 email exchanged", contacts[selectedID].position().x() + ((numEmails[selectedID]/maxEmailNumber)*maxCircleSize)/2 + minCircleSize + 5, contacts[selectedID].position().y()+15, 200, 25);
  }
}

//this puts the location of all the particles on a circle of radius radiusConstraint
void placeOnCircle( Particle p , int radiusConstraint)
{ 
  float xp, yp;
  xp= p.position().x()-width/2;
  yp= p.position().y()-height/2;
  float h = sqrt(sq(xp) + sq(yp));
  p.moveTo((xp/h)*radiusConstraint+width/2,(yp/h)*radiusConstraint+height/2,0);
}

//select a contact
void mousePressed()
{
  contactSelected = false;
  for(int counter = 1; counter