//Removed temperature at the end, based around Brian's note in piazza var table; function preload(){ var origFileName = '698.csv' table = loadTable(origFileName, 'csv'); } var uniqueVertArr = []; var verticesArr = []; var edgesArr = []; var canvasX; var canvasY; //global variables based around the //idealDist = k from the paper: the optimal distance between vertices var idealDist; var iterations; var temperature; function setup() { //initialize basic variables (canvasX/Y = Width/height) canvasX = 1200; canvasY = 1200; temperature = canvasX/10; iterations = 10; createCanvas(canvasX, canvasY); background(750,250,210); var area = canvasX * canvasY; //slow down frame rate to see changes in graph frameRate(.5); //Gets the data stored in the first row, separated by commas var str1 = table.getString(0,0); var strArr = str1.split(","); for(var i = 0; i < strArr.length; i++) { var arrVertStr = strArr[i].split(" "); var edgeData = []; for(var k = 0; k < arrVertStr.length; k++) { //loop through the strArr, convert each value to int vertex; there is an empty NaN var vertex = new Object(); var nodeID = parseInt(arrVertStr[k]); vertex.nodeID = nodeID; vertex.posX = round(random(50, canvasX-50)); vertex.posY = round(random(50, canvasY-50)); vertex.dispX = 0; vertex.dispY = 0; //If nodeID is a number, then addToVertices and build the edgeData Object; if(!isNaN(nodeID)) { addToVertices(uniqueVertArr, vertex); edgeData.push(nodeID); } } //If the edge is a number, push the edge pair to edgesArr if(!isNaN(edgeData[0]) || !isNaN(edgeData[1])) { edgesArr.push(edgeData); } } //sort verticesArr by nodeID, in ascending order sortVertices(); //idealDist = k from the paper: the optimal distance between vertices //paperConst = constant C from the paper (is this temperature?); initially 1 (arbitrary) idealDist = sqrt(area/verticesArr.length); drawNode(); drawEdges(); } // Check if vertex is not in uniueVertArr, then add that to array and to verticesArr function addToVertices (vertices, vertex) { //If the vertex has not been added to the uniqueVertArr list, // then add vertex to verticesArr and vertex.nodeID to uniqueVertArr if (vertices.indexOf(vertex.nodeID) == -1) { vertices.push(vertex.nodeID); verticesArr.push(vertex); } } //Sort the vertices in ascending order: verticesArr then uniqueVertArr function sortVertices() { verticesArr.sort(function(a, b) { return parseFloat(a.nodeID) - parseFloat(b.nodeID); }); uniqueVertArr.sort(function(a, b) { return parseFloat(a) - parseFloat(b); }); } //draw nodes in setup - initial random draw function drawNode() { //nodes radius (the width and height: ellipse(x,y,width,height) to make circle) var radius = 20 for(var v = 0; v < verticesArr.length; v++) { var nodeX = verticesArr[v].posX; var nodeY = verticesArr[v].posY; //TODO: change after seeing changes during drawing //verticesArr[i].posX = verticesArr[i].posX + 1; fill('blue'); ellipse(nodeX, nodeY, radius, radius); if(mouseX > nodeX-10 && mouseY > nodeY-10 && mouseX < nodeX+10 && mouseY < nodeY-10) { var c = color(750,250,210); fill(c); rect(xVal-35, yVal - 60, 130, 40); fill('red'); ellipse(nodeX, nodeY, radius, radius); textSize(30); var txtBox = verticesArr[v].nodeID; text(txtBox, xVal - 30, yVal - 30); } } } //draw the edges as boxes in terms of colored squares function drawEdges() { //edgesArr.length for(var eIndex = 0; eIndex < edgesArr.length; eIndex++) { var firstEdge = edgesArr[eIndex][0]; var secEdge = edgesArr[eIndex][1]; var firstIndex = uniqueVertArr.indexOf(firstEdge); var secIndex = uniqueVertArr.indexOf(secEdge); var xVal1 = verticesArr[firstIndex].posX; var yVal1 = verticesArr[firstIndex].posY; var xVal2 = verticesArr[secIndex].posX; var yVal2 = verticesArr[secIndex].posY; //draw edge as line fill(color('black')); line(xVal1, yVal1, xVal2, yVal2); } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// //calculate attraction force function calculateAttraction() { //for each edge in the edge list for(var eIndex = 0; eIndex < 2 ; eIndex++) { //TODO: may need to change edges object to include displacement, for drawing? var firstEdge = edgesArr[eIndex][0]; var secEdge = edgesArr[eIndex][1]; var firstIndex = uniqueVertArr.indexOf(firstEdge); var secIndex = uniqueVertArr.indexOf(secEdge); //console.log(firstEdge + ', ' + secEdge + ' ::: ' + firstIndex +' , '+secIndex); //console.log(firstIndex); var firstVertex = verticesArr[firstIndex]; var secVertex = verticesArr[secIndex]; //calculate sigma from the paper: difference vector var xDiff = firstVertex.posX - secVertex.posX; var yDiff = firstVertex.posY - secVertex.posY; //Could also be this formula -> then change only dispX as the displacement // var xDiff = sqrt(pow(verticesArr[firstIndex].posX - verticesArr[secIndex].posX, 2) + pow(verticesArr[firstIndex].posY - verticesArr[secIndex].posY,2)); if(xDiff == 0) { xDiff = 0.00001; } if(yDiff == 0) { yDiff = 0.00001; } verticesArr[firstIndex].dispX = verticesArr[firstIndex].dispX - (xDiff/abs(xDiff)) * attractionForce(abs(xDiff)); verticesArr[firstIndex].dispY = verticesArr[firstIndex].dispY - (yDiff/abs(yDiff)) * attractionForce(abs(yDiff)); verticesArr[secIndex].dispX = verticesArr[secIndex].dispX + (xDiff/abs(xDiff)) * attractionForce(abs(xDiff)); verticesArr[secIndex].dispY = verticesArr[secIndex].dispY + (yDiff/abs(yDiff)) * attractionForce(abs(yDiff)); } } function attractionForce(x) { return pow(x,2)/idealDist; } //////////////////////////////////////////////////////////////////////////////// //calculate repulsive force function calculateRepulsion() { //calculate repulsive forces for(var v = 0; v < verticesArr.length; v++) { verticesArr[v].dispX = 0; verticesArr[v].dispY = 0; for(var u = 0; u < verticesArr.length; u++) { if(u != v) { //difference in x positions in xDiff, same for y (e.g. sigma in paper); could be distanceFormula var xDiff = verticesArr[v].posX - verticesArr[u].posX; var yDiff = verticesArr[v].posY - verticesArr[u].posY; //following the piazza notes for graph algorithm if(xDiff == 0) { xDiff = 0.01; } if(yDiff == 0) { yDiff = 0.01; } verticesArr[v].dispX = verticesArr[v].dispX + ((xDiff/abs(xDiff)) * (-1) * repulsiveForce(abs(xDiff))); verticesArr[v].dispY = verticesArr[v].dispY + ((yDiff/abs(yDiff)) * (-1) * repulsiveForce(abs(yDiff))); } } } } function repulsiveForce(x) { return (pow(idealDist,2))/x; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// //after calculating attraction/repulsion, change positions (final for loop in the psuedocode) function reassignPositions() { for(var v = 0; v < verticesArr.length; v++) { verticesArr[v].posX = verticesArr[v].posX + (verticesArr[v].dispX/abs(verticesArr[v].dispX)); verticesArr[v].posY = verticesArr[v].posY + (verticesArr[v].dispY/abs(verticesArr[v].dispY)); //canvasX and canvasY are Width and Length of the frame //offset of 20 to keep it in the right side of the frame //first number is the right edge of the frame, second number should be left edge verticesArr[v].posX = min(canvasX - 20, max(20, verticesArr[v].posX)); verticesArr[v].posY = min(canvasY - 20, max(20, verticesArr[v].posY)); } } function draw() { while(iterations > 0) { calculateRepulsion(); calculateAttraction(); reassignPositions(); temperature = pow(temperature, -2); iterations--; background(750,250,210); drawEdges(); drawNode(); } background(750,250,210); drawEdges(); drawNode(); }