–––
A Graph in Processing

Before we being you should have completed Daniel Shiffman's fantastic Hello Processing introduction and tutorials. Processing is the simplest and most elegant codeing language for a visual artist to get introduced to programming. That is what it was built to do.

Most procossing sketches begin the same way with two functions. One that runs once and stops, setup() and one that keeps repeating, draw().

image
void setup(){

}
void draw(){

}

We'll make the canvas bigger with size() and we'll add a background color to draw() this way we can adjust the background color in tweak mode (Command+Shift+T)

void setup(){
	size(800,800);
}
void draw(){
	background(170);
}

Let's draw a line. We refer to the Processing reference and see that the basic structure is beginShape(), a series of points, vertex(x,y), and finally close it with endShape().

void setup(){
	size(800,800);
}
void draw(){
	background(170);
	
	beginShape();
	vertex(50, 490);
	vertex(293, 504);
	vertex(581, 340);
	vertex(747, 524);
	endShape();
}

This works but it's super tedius. We also need a way of parsing the data in our spreadsheet to the points in the line. So the first thing we need to lokk at are variables. Variable are containers that store information that you can retrieve later. We need to give each variable a name and in Processing we need to declare what kind of datatype the varaible is. In some other languages such as Javascript this is handled dynmaically.

We also use println() to test our code and see our vaiables in the console. Another very useful testing tool is commenting. Commenting lets us turn code on and off or insert notes to explain the code. We can either comment one line or a block of code at a time.

image
void setup(){
   // if we want comment out a line of code we use this -> // 
   //size(800,800);
  
  // Declare an integer
  int myInteger = 490;
  println(myInteger);
  
  // Declare an float, a number with a decimal
  float myFloat = 490.0;
  println(myFloat);
  
  // Declare a boolean, true or false, 0 or 1
  boolean mySwitch = true;
  println(mySwitch);
  
  // Declare a String, text
  String myName = "Peter";
  println(myName);
}

/// If we want to comment out a whole block of code we use this
/**/

/* 
void draw(){
  background(170);
  noFill();
  
  beginShape();
  vertex(100, 490);
  vertex(300, 265);
  vertex(500, 647);
  vertex(700, 72);
  endShape();
}
*/

Let's try plugging a variable into one of our vertex values.

void setup(){
  size(800,800);
  int myInteger = 490;
}

void draw(){
  background(170);
  noFill();
  
  beginShape();
  vertex(100, myInteger);
  vertex(300, 265);
  vertex(500, 647);
  vertex(700, 72);
  endShape();
}

Hmmm... when we do this it gives us the error in the console "My integer cannot be resolved to a variable". Why?

Well in coding we have to think about a concept known as scope."Scope refers to the visibility of variables." or which parts of your program can see or use it. If you define a variable outside of all of your functions it has a global scope and every part of your program can access a it. Often though it can be useful to limit a variable's scope to a single function and give it a limited scope. This way changes inside the function can't affect the main program in unexpected ways

Remember we bgaan with "Most procossing sketches begin the same way with two functions." So our myIntegerVariable is inside the setup() function as is only visible there. If we move the varable out of the function it will be visible everywhere

int myInteger = 490;

void setup(){
  size(800,800);
}

void draw(){
  background(170);
  noFill();
  
  beginShape();
  vertex(100, myInteger);
  vertex(300, 265);
  vertex(500, 647);
  vertex(700, 72);
  endShape();
}

Now our variable works. We'll see when we start creating many variables for it once again get's very tedious. A way to deal with this is to use an array.

int myInteger1 = 490;
int myInteger2 = 265;
int myInteger3 = 647;
int myInteger4 = 72;

void setup(){
  size(800,800);
}

void draw(){
  background(170);
  noFill();
  
  beginShape();
  vertex(100, myInteger1);
  vertex(300, myInteger2);
  vertex(500, myInteger3);
  vertex(700, myInteger4);
  endShape();
}

An array is a list of variables. We can create array of variables and then call their postion in the list to retrieve their values. An important note is that the first slot in an array is 0 not 1.

image
int[] myIntegers = {490,265,647,72};

void setup(){
  size(800,800);
}

void draw(){
  background(170);
  noFill();
  beginShape();
  vertex(100,myIntegers[0]);
  vertex(300,myIntegers[1]);
  vertex(500,myIntegers[2]);
  vertex(700,myIntegers[3]);
  endShape();
}

If you look the values of the array slots used the Y positions for the vertxes you should see a pattern. To take at vantage of this pattern we'll use one of the most useful tools in programming the for() loop.

A for loop often use the same basic structure. First we declare an integer i it's starting value. Next we declare the end value in this case 4. Finally we add one to the i value each time the loop exacutes, i++. This ++ is where C++ comes from. It is also often very useful to use i's value to do math within the loop. So here we use i's value create a consistent offset between X values.

int[] myIntegers = {490,265,647,72};

void setup(){
  size(800,800);
}

void draw(){
  background(170);
  noFill();
  int offset = 200; 
  
  beginShape();
  for(int i=0; i<4;i++){  
  	vertex((100 + (i * offset)),myIntegers[i]);
  }
  endShape();
}

We can take this further by querying values we've already established. We can use .length to get the length of the the myIntegers array. We can query the width canvas to help us postion our line.


int[] myIntegers = {490,265,647,72};
float margin = 100;

void setup(){
  size(800,800);
}

void draw(){
  background(170);
  noFill();

  /// Determine the interval for the line X
  float offset = (width -2*margin)/(myIntegers.length - 1);
  beginShape();
  for(int i=0; i< myIntegers.length;i++){  
    vertex(((offset*i)+margin),myIntegers[i]);
  }
  endShape();
}

So this looks the same as before but now it's dynamic. When we can change the margin and the length of the array and the line will adapt.

int[] myIntegers = {490,265,647,72,400,50,300};
float margin = 150;

void setup(){
  size(800,800);
}

void draw(){
  background(170);
  noFill();

  /// Determine the interval for the line X
  float offset = (width -2*margin)/(myIntegers.length - 1);
  beginShape();
  for(int i=0; i< myIntegers.length;i++){  
    vertex(((offset*i)+margin),myIntegers[i]);
  }
  endShape();
}

The last thing we need before we start bringing in data is a way to scale the height of to fit the bounds we define within the canvas. To do this we find the minimum value in our array with min() the maximum value with max() and the remap the value to a range we define with the map()function.

int[] myIntegers = {490,265,647,72,500,42};
float margin = 50;

void setup(){
  size(800,800);
  println(margin);
}

void draw(){
  background(170);
  noFill();
  /// find the min and max values in the array
  float myMin = min(myIntegers);
  float myMax = max(myIntegers);
  
  /// Determine the interval for the line X
  float offset = (width -2*margin)/(myIntegers.length - 1);
  beginShape();
  for(int i=0; i< myIntegers.length;i++){  
    float remappedYpos = map(myIntegers[i], myMin, myMax, margin, (height - margin));
    vertex(((offset*i)+margin),remappedYpos);
  }
  endShape();
}