Joey Lee /
@joeyklee
Geographical Sciences 472: Data Visualization & Cartography
Eyeo 2015 – Casey Reas from Eyeo Festival // INSTINT on Vimeo.
See: 36:40
In this workshop we will be introduced to Processing - a programming language and environment developed "to promote literacy within the visual arts and visual literacy within technology". Processing is used across a variety of communities but has had particular success within the art and design community (and data visualization community) for its strength in generating visual and interactive output.
We will use the concepts learned in this workshop throughout the rest of the course to learn how to systematically approach data visualization problems and explore other tools and methods of producing visuals with data.
For your assignment choose one these three Proun drawings by El Lissitzsky.
You will develop 2 versions:
"Processing is for writing software to make images, animations, and interactions. The idea is to write a single line of code, and have a circle show up on the screen. Add a few more lines of code, and the circle follows the mouse. Another line of code, and the circle changes color when the mouse is pressed. We call this sketching with code. You write one line, then add another, then another, and so on. The result is a program created one piece at a time. " - Casey Reas & Ben Fry, Getting Started With Processing
"Processing relates software concepts to principles of visual form, motion, and interaction. It integrates a programming language, development environment, and teaching methodology into a unified system. Processing was created to teach fundamentals of computer programming within a visual context, to serve as a software sketchbook, and to be used as a production tool. Students, artists, design professionals, and researchers use it for learning, prototyping, and production" - Casey Reas, Processing, A Programming Handbook for Visual Designers and Artists
"Software is a unique medium with unique qualities... Every programming language is a distinct material...Sketching is necessary for the development of ideas...Programming is not just for engineers..." - Casey Reas, Processing, A Programming Handbook for Visual Designers and Artists
In the last 10 years, Processing has become one of the most used tools for creating visual outputs (among other things). It has a wide usership in many communities, one being the data visualization community because it allows for flexible and custom exploration of data, it is powerful in dealing with large datasets, and has a relatively friendly syntax and large user community.
The ethos of Processing is to create an open environment to engage with technology. There's an active community of artists, designers, and scientists from all different domains helping to develop the language & make Processing more accessible. If you continue to work in Processing, you'll definitely find lots of examples and support to help turn your ideas into something tangible. These are some photos of the people that are helping to make Processing bigger, better, and easier to learn.
The Processing Development Environment (IDE) looks like this:
PDE Elements:
If you did the One hour of code with Dan Shiffman, you should now be familiar with with these fundamental concepts in the context of a static sketch and dynamic sketch:
A static program runs sequentially, from top to bottom.
setting the canvas size using the size() function.
// size();
size(700, 500);
setting the background color of a canvas using RGB color parameters.
// background();
background(217, 250, 240);
adding color to shapes and strokes using RGB color parameters to the following functions:
// fill();
fill(255, 137, 82);
// stroke();
stroke(255, 82, 82);
drawing shapes using functions and using screen coordinates values to set the shapes. Some Processing shape functions you know are:
// ellipse();
ellipse(width * 0.25, height * 0.25, 50, 50);
// rect();
rect(width * 0.5, height * 0.5, 50, 50);
A dynamic sketch makes use of Processing's setup() and draw() functions to structure a logic for interaction and animations.
Together they look something like this:
A Responsive Ellipse-drawing tool
Run this in your PDE and we'll break it down line-by-line:
void setup() {
size(700, 500);
background(255);
}
void draw() {
if (mousePressed) {
background(255);
}
ellipse(mouseX,mouseY,40,40);
}
setup() Set up your sketch by calling all statements that only need to occur once during your drawing - this might be things like the size() of your canvas.
draw() Continuously repeat the statements within this function - continually evaluate the statements in a loop, over and over and over, forever.
Here, the computer is continually asking, "is the mousePressed?", "how about now?", "and now?", "how about now?", for infinity. When you finally press the mouse, it will change the background color to white and "erase" the ellipses you've drawn, but only as long as your mouse is pressed.
NOTE: mousePressed is equal to TRUE whenever your mouse is pressed and FALSE otherwise. Therefore it is a variable which stores a boolean of either TRUE or FALSE in response to a mouse event.
What the above example shows is:
Take 5 minutes now and remix the code from the "dynamic sketch":
Here's a sample of a sketch that tracks the speed of your mouse in the X and Y direction and maps it to colored bars:
void setup() {
size( 700, 500);
smooth();
noStroke();
}
void draw() {
if (mousePressed) {
background(255);
fill( 0, 0, 255);
} else {
// create a random fill with transparency
fill(random(100), random(255), random(255), random(50, 100));
}
// make a variable for the radius which calculates a radius for the ellipse based on the speed of the mouse
// mouseX is the current screen location of the mouse
// pmouseX is the previous screen location of the mouse
// thus the absolute difference of the current location minus the previous location is the speed
int speedX = abs(mouseX-pmouseX );
int speedY = abs(mouseY-pmouseY );
// responsive bar
rect(width*0.25, height*0.75, 30, speedY*-2);
rect(width*0.25+30, height*0.75+15, speedX*2, 30);
}
When you're programming, saving your work is super important. Let's save our first program.
You'll notice when you save your "sketch" the file type will be added to the end of whatever you called your progam. So if you named your project "myFirstSketch", you will see in your folder "myFirstSketch.pde". The ".pde" is the processing file type (similar to when you see a .csv or .py or .r or .xls, etc etc).
Voltaire once said, "If you wish to converse with me, define your terms". In this section, we're going to define a number of terms so we can all speak the same language when refering to the different elements of a program.
What you should learn and remember from this section are:
Remember seeing those double forward slashes (//) in the programs above? these are called comments - they are invisible to the computer and do not get evaluated by the computer.
These are useful when programming to help you (and others who read your code) keep track of what's happening in your program and allows you to test different functions and statements.
We can use two methods of comments:
For single line comments: //
// fill(255, 0, 0);
// ellipse(250, 100, 50, 50);
OR
Block comments for multiple lines of code:
/*
fill(255, 0, 0);
ellipse(250, 100, 50, 50);
*/
TIP: We can use comments to help us structure our logical steps when writing code. For example:
// first set the canvas size
// next set the canvas color
// next draw a circle in the center of the canvas. Since the canvas is 700 pixels wide and 500 pixels tall, the center must be at (350, 250).
// next draw a triangle about 1/3 the width of the canvas
// ...
The most basic way to get feedback from a computer is by "printing to the console." We can do this by using the print() or println() functions. The difference between print() and println() is that print() does not start a new line break after each function call. If this seems like a bunch of hogwash, try out the examples below :)
print()
print("Hello World");
print("My name is Joey");
print("It is raining outside");
println()
println("Hello World");
println("My name is Joey");
println("It is raining outside");
Functions allow you to draw shapes, set colors, calculate numbers, and to execute many other types of actions. A function’s name is usually a lowercase word followed by parentheses. Functions have parameters in which you fill in with arguments.
The comma-separated elements between the parentheses are the parameters that you fill with arguments, and they affect the way the function works. Some functions have no parameters and others have many. This program demonstrates the size() and background() functions. cont.
// The size function has two parameters.
//The first sets the width of the display window and the second sets the height
// the arguements here are 200, 200
size(200, 200);
// This version of the background function has one parameter.
// It sets the gray value for the background of the display window in the range of 0 (black) to 255 (white)
// the argument here is 102
background(102);
Using an analogy to human languages, a software expression is like a phrase. Software expressions are often combinations of operators such as +, *, and / that operate on the values to their left and right. A software expression can be as basic as a single number or can be a long combination of elements. An expression always has a value, determined by evaluating its contents.
Expressions
// expression // value
10 < 50 true
// expression // value
5*3 15
A Statement
A statement - composed of a set of expressions - is like a sentence that gets translated into machine readable code that instructs the computer to do something. For example we see that the collection of these expressions makes a statement (below) that tell the computer to do a particular task.
size(200, 200); // Runs the size() function to set the canvas size
int x; // Declares a new variable x as an integer type
x = 102; // Assigns the value 102 to the variable x
background(x); // Runs the background() function
Let's dive into how we can draw shapes with Processing.
The coordinate space of a Processing canvas is set using the size() function. The parameters for width and height sets the number of pixels that will be in the x-coordinate space and y-coordinate space.
The Processing canvas starts at (0,0) at the top-left corner of the canvas.
Processing's primitive shapes are the bread and butter of making visual output with code. As we saw in our first program in which we made a square and circle with one function, there are other primitive shapes that we can use. These primitives are listed below:
point(x,y)
Experiment: draw 5 points in a row on your screen
line(x1, y1, x2, y2)
Experiment: draw 3 "x's" on your screen using lines
triangle(x1, y1, x2, y2, x3, y3)
Experiment: draw 3 triangles if different sizes slightly overlapping eachother
quad(x1, y1, x2, y2, x3, y3, x4, y4)
Experiment: draw 1 funky quadrilateral
rect(x, y, width, height)
Experiment: draw 2 rectangles with exactly the same arguements - use the rectMode(CENTER) function for 1 of the rectangles and see what it does.
ellipse(x, y, width, height)
Experiment: draw a "bullseye" target with 6 ellipses. Play will fill colors to change the color of each ellipse.
bezier(x1, y1, cx1, cy1, cx2, cy2, x2, y2)
Experiment: draw 1 bezier curve to see how it works.
In Processing we can change the properties of the shapes to affect their fill color, stroke color, and drawing mode. Let's go over a few of them here:
If we use RGB color space:
* value1 = red (between 0 - 255)
* value2 = green (between 0 - 255)
* value3 = blue (between 0 - 255)
* alpha = transparency (between 0 - 100)
Processing comes with a handy Color tool to select colors
fill()
fill(value1, value2, value3)
fill(value1, value2, value3, alpha)
noFill()
Use the noFill() function if you don't want a fill color
size(700, 500);
// with fill
fill(242, 172, 20);
ellipse(width*0.25, height * 0.5, 150, 150);
// no fill
noFill();
ellipse(width*0.75, height * 0.5, 150, 150);
Experiment: make your own example using noFill() with another set of shapes like a triangle and rectangle.
stroke()
stroke(value1, value2, value3)
stroke(value1, value2, value3, alpha)
noStroke()
Use the noStroke() function if you don't want a stroke color
size(700, 500);
// no stroke
noStroke();
fill(242, 172, 20);
ellipse(width*0.25, height * 0.5, 150, 150);
// black stroke
stroke(0);
fill(242, 172, 20);
ellipse(width*0.75, height * 0.5, 150, 150);
strokeWeight()
You can use the strokeWeight() function to change the width of the stroke.
size(700, 500);
strokeWeight(1);
line(width*0.25, height * 0.25, width*0.75, height * 0.25);
strokeWeight(3);
line(width*0.25, height * 0.35, width*0.75, height * 0.35);
strokeWeight(5);
line(width*0.25, height * 0.45, width*0.75, height * 0.45);
strokeWeight(7);
line(width*0.25, height * 0.55, width*0.75, height * 0.55);
strokeWeight(9);
line(width*0.25, height * 0.65, width*0.75, height * 0.65);
strokeWeight(10);
line(width*0.25, height * 0.75, width*0.75, height * 0.75);
Experiment: make your own example using strokeWeight(), noFill(), stroke(), and noStroke() with a set of slightly overlapping rectangles.
In Processing we can create our own shapes from a series of vertices. We can do by sandwiching a series of vertex(x,y) functions in between the beginShape() and endShape() functions.
For example - let's make a funny fish:
size(700, 500);
strokeWeight(4);
// right eye
fill(255);
ellipse(width*0.6, height*0.2, 50, 100);
fill(0);
ellipse(width*0.6, height*0.15, 25, 50);
// body
fill(255);
stroke(0);
beginShape();
vertex(width*0.25, height*0.75);
vertex(width*0.35, height*0.15);
vertex(width*0.45, height*0.25);
vertex(width*0.65, height*0.25);
vertex(width*0.55, height*0.85);
endShape(CLOSE);
// left eye
fill(255);
ellipse(width*0.5, height*0.35, 50, 100);
fill(0);
ellipse(width*0.5, height*0.3, 25, 50);
What is data? Data could be anything from the time of day, the location of a bus stop, the color of your hair, and even the location of your mouse on the screen and the keys you pressed to login to your email. In general, data often consists of measurements of physical characteristics whether it be a digital photo of your dog or the precipitation in Vancouver.
Processing can store, modify, and manipulate many different kinds of data, including numbers, letters, words, colors, images, fonts, and boolean values (true, false).
One of the key features of programming is the ability to store values and/or data to variables. Below are the main data types in Processing - and programming in general - and examples of how to store them to a variable in Processing. NOTE: Processing (the java version) is strongly typed and thus we must declare what the data type will be when assigning data to a variable. If this sounds crazy, have a look at the examples below :)
In the following sections we are going to quick go through:
Here's a list of the main arithmetic functions in Processing. There are others including functions for making exponents, doing square roots, making log transformations, etc - for a full list check the Processing Documentation.
+ (add)
- (subtract)
* (multiply)
/ (divide)
% (modulus)
() (parentheses)
++ (increment)
-- (decrement)
+= (add assign)
-= (subtract assign)
*= (multiply assign)
/= (divide assign)
- (negation)
ceil()
floor()
round()
min()
max()
A relational expression is made up of two values that are compared with a relational operator. In Processing, two values can be compared with relational operators as follows:
Expression Evaluation
3> 5 false
3< 5 true
5< 3 false
5> 3 true
In Processing, we have these relational operators at our fingertips in order to evaluate truthy or falsy values:
Operator Meaning
> greater than
< less than
>= greater than or equal to <= less than or equal to
== equivalent to
!= not equivalent to
In the earlier examples we saw the use of variables like mouseX, mouseY , and mousePressed. What we know about these variables is that they store data like the location of the x- and y- coordinate of the mouse or if the mouse is pressed.
In programming languages, we can define our own variables to store data and in turn work with that data running calculations, statistics and/or visualizing it.
Before we work through an example here are the fundamental data types in Processing, how to declare them, and assign them a value:
NOTE: remember our fancy dancy println() function? For each of the following examples, pass each of these variables into the println() function to show the value of the variables in the PDE console. Otherwise, your code will run, but you won't get any feedback ;)
Assign single values to a variable:
// x is an integer equal to 10
int x = 10;
Assign an expression to a variable:
// y is an integer equal to 5 times 5
int y = 5 * 5;
Assign an expression involving other variables to a variable:
// z is an integer equal to the sum of x and y
int z = x - y ;
Assign single values to a variable:
// i is an floating number equal to 95.7
float i = 10.5
Assign an expression to a variable:
// j is an float equal to 5.0 times 5.0
float j = 5.0 * 5.0;
Assign an expression involving other variables to a variable:
// k is a normalized difference between variables i and j
float k = i - j / i + j ;
Assign single values to a variable:
// exclamation is a string containing the sentence "hello world!"
String exclamation = "My Gosh! ";
Assign an expression to a variable:
// task is a String expression "Hey yo"
String task = "I'm" + " " + "programming.";
Assign an expression involving other variables to a variable:
// realization is a string concatenating the variable exclamation and task
String realization = exclamation + task;
// use the text() function to render the text to the canvas
text(realization, width/2, height/2);
Assign single values to a variable:
// trueLove is a a boolean type set to true
boolean trueLove = true;
Assign an expression to a variable:
// falseExpression is a boolean type showing false for the expression 10 is less than 5
boolean falseExpression = 10 < 5;
Assign an expression involving other variables to a variable:
// trueExpression is a boolean type that is equal to the expression that trueLove does not equal falseExpression
boolean trueExpression = trueLove != falseExpression;
Assign a list values to a variable:
// an array of integers:
int[] d1 = {1, 2, 3, 4, 5, 6};
// calculate the maximum value of the array
int d1_max = max(d1);
print(d1_max);
// use the printArray() function to print it
printArray(d1);
Create an empty array, then append values to it:
// an empty array:
int[] d2 = {};
// add numbers to it
d2 = append(d2, 20);
d2 = append(d2, 40);
d2 = append(d2, 60);
Create an array of a known size, then append values to it:
int[] numbers = new int[3];
numbers[0] = 90; // Assign value to first element in the array
numbers[1] = 150; // Assign value to second element in the array
numbers[2] = 30; // Assign value to third element in the array
int a = numbers[0] + numbers[1]; // Sets variable 'a' to 240
int b = numbers[1] + numbers[2]; // Sets variable 'b' to 180
Don't worry if I just lost you with arrays - they can be a little intimidating, but they are awesome, and they will hold onto our data so we can make stuff like this:
We will clear the air once we go through some control structures like conditionals and looping.
Conditionals allow a program to make decisions about which lines of code run and which do not. They let actions take place only when a specific condition is met. Conditionals allow a program to behave differently depending on the values of their variables.
if/else statements are ways to control the behavior of your program. This allows us to make decisions about what happens in our code. if/else statements might allow us to filter out data, change the size of an ellipse or rectangle depending on the value of a variable, or react to a mouse or key input (oooh fancy!).
So this is the basic structure of an if statement. It basically says: "if a condition is met, execute the statements within the brackets."
// psuedo code - this wont run in Processing
if (test) {
statements
}
In our first sketch example (below), we played with conditional statements by using the if/else statement in conjunction with the mousePressed variable to tell the computer:
"if the mouse is pressed, then change the background color and clear the ellipses from the canvas."
void setup() {
size(700, 500);
background(255);
}
void draw() {
if (mousePressed) {
background(255);
}
ellipse(mouseX,mouseY,40,40);
}
But let's say we want more control over our program... what can we do? The if/else statement allows you to say:
"if a condition is met, then execute the statements within the brackets of the "if" statement, HOWEVER if those conditions are NOT met, then run the statements within the brackets of the "else" statement."
// psuedo code - this wont run in Processing
if (test) {
statements
} else {
statements
}
Take our code from above and write an if/else statement that draws ellipses with orange stroke when the mouse is pressed and rectangles with purple stroke if it is not pressed.
We've now made an if statement, and if/else statement, and now we want to add 1 more layer of control to our decision making. Here we introduce the "else if" conditional.
The else if statement allows us to say "if a condition is met, then execute the statements within the brackets of the if statement, HOWEVER if those conditions are NOT met, then evaluate whether or not the condition is met for the "else if" statement. If the condition is met in the "else if statement", then run the statements within those brackets, if not, then check if the conditions are met in the next else if statement and so on and so forth. And if none of those are met, then run the else statement."
// psuedo code - this wont run in Processing
if (test) {
statements
} else if (test) {
statements
} else if {
statements
}
... (as many else if statements as you'd like)...
else{
statements
}
Here's some kind of an 80's pattern you might have seen on a fanny pack.
void setup() {
size(700, 500);
background(255);
frameRate(10);
noStroke();
}
void draw() {
if (mousePressed) {
if (frameCount % 4 == 0) {
fill(#FFAB0D);
ellipse(mouseX, mouseY, 60, 60);
} else if (frameCount % 4 == 1) {
fill(#0DDDFF);
rect(mouseX, mouseY, 60, 60);
} else if (frameCount % 4 == 2) {
fill(#650DFF);
triangle(mouseX, mouseY, mouseX+ 60, mouseY+60, mouseX-60, mouseY+60);
} else {
fill(#FF0D66);
quad(mouseX, mouseY, mouseX, mouseY+60, mouseX-75, mouseY+60, mouseX+75, mouseY);
}
}
}
Wasn't that fun?! This may seem trivial, but essentially you can now write code that is responding to data and producing visuals based on the control structures you've put in place.
We can have multiple "tests" conditions in an if or else if statement. Using the logical operators (such as the ones you see below) allow you to combine test conditions in an if/else if/ else statement makes it possible to do this.
Operator Meaning
&& AND
|| OR
! NOT
Expression Evaluation
true && true true
true && false false
false && false false
true || true true
true || false true
false || false false
!true false
!false true
Run this code and see what happens when you:
void setup() {
size(700, 500);
background(0);
rectMode(CENTER);
noStroke();
}
void draw() {
if (mousePressed && keyPressed) {
background(0);
} else if (mousePressed){
fill(255);
rect(mouseX, mouseY, 60, 60);
} else if (keyPressed) {
fill(0);
rect(mouseX, mouseY, 60, 60);
}
}
Add comments to the code at each conditional statement in the draw() function telling us what will happen if that stement is TRUE.
Computers are excellent at executing repetitive tasks accurately and quickly. Modern computers are also logic machines. Building on the work of the logicians Leibniz and Boole, modern computers use logical operations such as AND, OR, and NOT to determine which lines of code are run and which are not.
The for loop is probably the coolest thing since ever. At the most basic level for loops allow your to repeat a statement or statements over and over again until a condition is met.
Why are for loops so awesome? Let's look at an example of how a loop can be used to take a program which takes 14 lines of code to make 14 lines...
// original hard-coded program
size(200, 200);
line(20, 20, 20, 180);
line(30, 20, 30, 180);
line(40, 20, 40, 180);
line(50, 20, 50, 180);
line(60, 20, 60, 180);
line(70, 20, 70, 180);
line(80, 20, 80, 180);
line(90, 20, 90, 180);
line(100, 20, 100, 180);
line(110, 20, 110, 180);
line(120, 20, 120, 180);
line(130, 20, 130, 180);
line(140, 20, 140, 180);
... and make the program 4 lines of code:
size(200, 200);
for (int i = 20; i < 150; i += 10) {
line(i, 20, i, 180);
}
If you were to read this out loud it would sound like: "for the integer i equals 20, as long as i is less than 80, increment i by 5, drawing a line each time with new y coordinates based on i."
Let's get a little crazy and make a nested loop. A nested loop? You can do that?! Sure!
size(400, 400);
noStroke();
for (int i = 20; i < width - 20; i += 20) {
for (int j = 20; j < height - 20; j += 20) {
fill(random(255), random(255), random(255));
ellipse(i, j, 10, 10);
}
}
How does a nested loop work? First, the outer loop starts. Then the inner loop runs until the condition is met at which point the outer loop increments, repeating the inner loop again until the condition is met at which point the outer loop increments, and over and over until the outer loop condition is met. This means that columns of ellipses are drawn from left to right with each complete loop.
*NOTE: the random() function generates a random number from 0 to the value of the input parameter. In this case, for each iteration in the loop, a random number is generated between 0 and 255 for each parameter in the fill() function.
As our last examples, we will work with arrays to make some simple animations. We will use the following concepts we've picked up in this workshop:
// Declare the arrays - globally
int[] y = {};
int[] x = {};
// declare a counter variable i to increment through the arrays later
int i = 0;
// set the size and background color
void setup() {
size(700, 500);
background(255);
}
// continuously evaluate the draw function
void draw() {
if (mousePressed){
// append the x & y coordinates of the mouse to array x and y
x = append(x, mouseX);
y = append(y, mouseY);
// draw a point with a strokeWeight 2 where the mouse is
strokeWeight(2);
stroke(150, 150, 150, 80);
point(mouseX, mouseY);
}
// when you press a key and
// as long as the index is less than the length of the array
// so we don't run out of data points to draw
if (keyPressed && i+1 < y.length) {
// increment i by 1
i++;
// choose a random stroke color
stroke(random(255), random(255), random(255), 60);
// use the modulo to select a strokeWeight from 0 to 8
// as the numbers increment
strokeWeight(i % 8);
// draw a line using the data from the array by
// selecting the index positions
line(x[i-1], y[i-1], x[i], y[i]);
}
}
Let's make an animation of a taxi cab in Vancouver.
before you continue: 1. save your sketch as "taxi_trail", 2. copy the "assets/data" folder into your "taxi_trail" folder you just created.
// To read in an image:
// 1. instantiate the PImage class &
// 2. declare the image object
PImage backgroundmap;
// An array of arrays of coordinates of a taxi in Vancouver
int[][] coords = {{274,487},{274,487},{318,441},{328,428},{341,419},{353,410},{362,399},{365,392},{407,426},{447,446},{462,455},{506,473},{517,478},{526,484},{547,493},{551,497},{556,503},{559,507},{559,507},{566,512},{566,512},{573,518},{573,518},{581,524},{586,533},{598,542},{598,547},{584,560},{578,568},{567,578},{556,586},{549,597},{529,613},{523,619},{523,619},{521,622},{548,646},{562,658},{566,667},{556,681},{551,685},{534,668},{517,657},{508,648},{501,642},{491,656},{468,680},{457,671},{445,653},{430,636},{414,622},{398,607},{382,595},{350,571},{334,556},{346,544},{359,533},{339,504},{329,493},{319,483},{326,476},{335,468},{342,460},{336,448},{327,443},{315,451},{304,459},{293,466},{288,471},{278,479},{271,488},{267,476},{264,466},{257,456},{247,448},{237,442},{237,442},{231,436},{231,436},{224,430},{201,416},{200,415},{197,396},{200,381},{200,369},{200,369},{198,355},{189,345},{184,339},{201,335},{214,328},{228,324},{248,321},{261,316},{278,308},{314,302},{324,310},{326,313},{336,322},{339,316},{354,310},{361,311},{386,304},{394,298},{420,307},{422,310},{430,321},{437,321},{445,307},{454,296},{476,291},{481,293},{498,294},{507,288},{514,286},{533,284},{548,287},{556,281},{561,277},{561,270},{561,248},{552,254},{547,259},{532,262},{529,261},{511,254},{505,252},{476,244},{463,235},{452,223},{449,222},{419,214},{411,212},{403,207},{390,192},{383,176},{374,161},{353,148},{346,139},{341,128},{338,102},{330,88},{317,76},{306,64},{295,51},{288,84},{285,109},{263,108},{254,97},{260,85},{265,77},{268,63},{262,54},{260,42},{254,36},{237,39},{222,53},{206,62},{186,72},{178,90},{166,99},{153,105},{135,125},{130,150},{140,182},{140,205},{131,222},{120,230},{101,236},{89,256},{86,282},{93,293},{113,302},{133,303},{156,317},{170,328},{178,332},{196,333},{233,324},{264,322},{274,316},{289,301},{306,298},{320,303},{329,323},{331,345},{344,367},{355,378},{372,392},{390,409},{396,420},{414,438},{431,450},{439,460},{452,467},{460,476},{461,478},{448,502},{433,498},{424,490},{409,471},{401,463},{395,459},{393,467},{383,472},{375,467},{369,462},{363,467},{360,471},{360,476},{374,484},{386,495},{388,498},{392,504},{401,512},{402,513},{415,522},{422,532},{423,539},{413,544},{405,550},{396,556},{394,562},{402,567},{416,578},{421,582},{417,598},{397,616},{388,624},{373,632},{369,639},{366,647},{366,652},{376,661},{383,666},{377,676},{365,679},{348,688},{340,693},{333,697},{307,709},{291,717},{269,728},{256,735},{236,743},{228,757},{229,771},{228,782},{241,783},{265,783},{272,783},{275,784},{276,785},{281,800},{284,815},{299,826},{302,824},{310,805},{321,799},{345,784},{355,772},{357,770},{384,744},{387,736},{391,730},{399,725},{404,724},{417,721},{423,716},{432,706},{435,705},{446,698},{452,692},{478,665},{485,658},{487,655},{501,647},{513,632},{525,621},{538,608},{549,598},{556,591},{576,573},{589,551},{595,544},{609,552},{620,573},{632,582},{653,593},{681,599},{701,604},{737,606},{764,603},{765,613},{765,632},{763,650},{764,657},{783,658},{803,664},{804,679},{785,671},{752,663},{727,669},{709,671},{680,671},{661,666},{651,662},{638,649},{619,639},{601,624},{596,620},{589,614},{578,603},{571,594},{564,586}};
// global counter variable i to increment the animation
int i = 0;
// set the size and background color
void setup() {
size(960, 840);
background(255);
// read in the map image
// Images must be in the "data" directory to load correctly
backgroundmap = loadImage("backgroundmap_960x840.png");
// reduce the frame rate to slow the animation
frameRate(20);
}
// the draw function
void draw(){
// load the image using the image() function
//so the map is drawn every frame of the animation
image(backgroundmap, 0, 0);
// add annotations
// fill(255);
// stroke(255);
// rect(width*0.60, 35, 500, 50);
//
// fill(255, 0, 0);
// textSize(32);
// text("click to show the route", width*0.62, 40, width*0.75, 200);
// animate the taxi as long as there data data available
// by incrementing i by 1 each frame
if(i+1 < coords.length){
i++;
fill(255, 214, 46, 75);
strokeWeight(3);
stroke(255, 214, 46);
ellipse(coords[i][0], coords[i][1], 20, 20);
}
// if the mouse is pressed, draw the entire route of the taxi in red
if(mousePressed){
// using a for loop, we iterate through all the data points
// to draw the whole taxi route
for(int j = 0; j < coords.length - 1; j++){
strokeWeight(4);
stroke(255, 0, 0, 85);
// draw a line from position x1, y1 to x2, y2
line(coords[j][0], coords[j][1], coords[j+1][0], coords[j+1][1]);
}
}
}
Whew! That's a lot of stuff. Take some time to play around with the code, decompress, have some coffee and a snack. If you made it this far you are amazing. I don't know about you but my mind is blown!
There's so much more to learn and so much cool stuff we haven't yet done with data! Throughout the course I hope you can reference back to this workshop as you learn more about Processing and as a way to help you understand some of the other tools we will be using like R or Mapbox Studio, and others.
I have to mention P5.js which is the javascript library inspired by Processing not only because it is super cool, but because I, along with many others, believe the age of the web is here! P5.js is a javascript library that takes the soul of Processing and implements it in javascript meaning that you can sketch with code using web technologies (html, css, & javascript). I would argue that the syntax is friendlier and is more flexible in terms of sharing your work. Besides the fact that the browser can crash if you send it a ton of data, P5.js may be an interesting way to move out of your desktop and onto the web.
*NOTE: I decided not to teach P5.js since I thought introducing html, css, and javascript would be maybe too much for the first class. Please let me know if you have other thoughts!
P5.js website:
http://p5js.org/
P5.js tutorials:
http://p5js.org/tutorials/
"Processing, A Programming Handbook for Visual Artists and Designers" by Casey Reas and Ben Fry
"Getting Started with Processing" - Ben Fry
"Learning Processing" - Dan Shiffman
Learning Processing With Dan Shiffman - this dude is handsdown the best guy ever.
"Programming Handbook for Visual Artists and Designers" by Casey Reas and Ben Fry
P5.js tutorials
"Getting Started with Processing" - Ben Fry
"Visualziing Data " - Ben Fry
Processing.org