Skip to main content Skip to navigation

Visualisation Lab 2

In this lab we'll be modelling a random walker. Random walks can be used to model phenomena that occur in the real world, from the movements of molecules in a gas to the behavior of a gambler spending a day at the casino.

The random walker will serve as a template for how we will use object-oriented design to make things that move around a Processing window.

This lab is adapted from the Introduction Chapter of The Nature of Code by Daniel Shiffman, and Chapter 4 of Visualizing Data by Ben Fry

There is also a Processing tutorial on objects and classes if you want to have a look.


Classes and objects

An object in Processing is an entity that has both data and functionality. We want to design a Walker object that both keeps track of its data (where it exists on the screen) and has the capability to perform certain actions (such as draw itself or take a step).

A class is the template for building actual instances of objects. Think of a class as the cookie cutter; the objects are the cookies themselves.

Defining the Walker Class

The walker.pde code implements a random walker. The Walker only needs two pieces of data—a number for its x-location and one for its y-location.

class Walker{
//data
int x;
int y;

Every class must have a constructor, a special function that is called when the object is first created.

   //constructor
Walker() {
//initialise the starting position
x = width/2;
y = height/2;
} //constructor

in addition to data, classes can be defined with functionality. A Walker has two functions. The first allows the object to display itself (as a white dot).

   void display() {
stroke(0);
point(x,y);
}//end display

The second function directs the Walker object to take a step. There are four possible steps. A step to the right can be simulated by incrementing x (x++); to the left by decrementing x (x--); forward by going down a pixel (y++); and backward by going up a pixel (y--). How do we pick from these four choices? We can pick a random number using random().

   void step() {
int choice = int(random(4));

if (choice == 0) {
x++;
} else if (choice == 1) {
x--;
} else if (choice == 2) {
y++;
} else {
y--;
}//end if

} //end step


In the main part of our sketch, we declare one global variable of type Walker, and then create the object in setup(). Then, during each cycle of the draw() function, the Walker takes a step and draws a dot.

Walker walker; // Declare object

void setup() {
size(600, 600);
walker = new Walker(); // Create object
} //setup

void draw() {
walker.step();
walker.display();
} //draw



EX1 Implement two random walkers of different colours that can step to any neighbouring pixel (or stay put). Try extending this to an array of 10 walkers and updating them sequentially? Follow this link if you need a reminder about arrays in processing - https://processing.org/reference/Array.html

L2EX1out

Answer EX1.pde


EX2 Make sure that the random walkers always remain in the sketch. You may want to investigate the constrain() function

Answer EX2.pde


EX3 Modify your code to simulate a population of bacteria moving as random walkers. You can use an ellipse to visualise a single bacteria. Hint: You should redraw your background in the draw() function to display the current position only (rather than a trace)

L2EX3out

Answer EX3.pde



Saving the output of a sketch

You can use "File > Export" to package your current sketch. However, you may just want to create an image of the output. Images are saved with the saveFrame() function. Adding saveFrame() at the end of draw() will produce a numbered sequence of TIFF-format images of the program's output, saving a new file each time draw is run (be careful as this can quickly fill your sketch folder with hundreds of files. You can also specify your own name and file type using saveFrame("output.png").Processing has a Movie Maker Tool accessed via "Tools > Movie Maker". This creates a Quicktime movie from a sequence of images.

For high-quality output (which will be useful for your first assignment), you can write geometry to a pdf instead of to the screen. This example draws a single frame to a PDF file and quits. (Note that no display window will open; this helps when you're trying to create large PDF images that are far larger than the screen size.)

import processing.pdf.*;

void setup() {
size(400, 400, PDF, "filename.pdf");
}

void draw() {
// Draw something good here
line(0, 0, width/2, height);

// Exit the program
println("Finished.");
exit();
}

Saving frames can also be combined with event listeners, for example the following code will save a frame when the "s" key is pressed:

void keyPressed(){
if(key == 's'){
println("Saving...");
save("output.png");
println("Done saving.");
}
}


EX4 Update your code to save a frame when the "s" key is pressed


Points on a graph

Next week we are going to start to look at time series, so we will spend the remainder of this lab modifying our Bacteria code so that we can arrange an array of Point objects along an x and y axis.

  • The first step is to turn our Bacteria object into a Point object
  • You should also add an identifier (ID) to each Point object
  • x position - for now you want to equally space your points along the x axis - we can do this in a number of ways e.g. scaling the objects manually using the ID or use the map() function - this re-maps a number from one range to another - in this case re-mapping between 0 and the population/sample size to 0 and the width of the display. For now set the x value to the ID and use the map function in your display method
  • y position - for now we'll equally space the points along the y axis too using the same method (set the y value to the ID and use the map function in your display method). Remember that the origin is in the top left
  • Finally in the main part of our sketch our point does not need to take a step - we only need to display it

EX5 Modify your Bacteria code as detailed above. It should look something a bit like this:

Answer: EX5.pde

graph


Ok, so that doesnt look that great. So lets work on making it look more like a graph.

Set the boundaries for the plot location

Create the global variables plotX1, plotY1, plotX2, plotY2 to define the corners of the plot area and draw a filled white rectangle for the plotting area. To provide a nice margin you should set plotX1 to 50 and plotX2 to width-50. The same technique is used for plotY1 and plotY2.

void drawPlotArea() {
fill(255);
noStroke();
rectMode(CORNERS);
rect(plotX1, plotY1, plotX2, plotY2);
}

The rect() function normally takes the form rect(x, y, width, height), but rectMode(CORNERS) changes the parameters to rect(left, top, right, bottom).

We can use those variables in the map function within the display method to plot our points within the plot area.

void display() {
noStroke();
fill(colour);
float tempx = map(x, minX, maxX, plotX1, plotX2);
float tempy = map(y, minY, maxY, plotY2, plotY1);
ellipse(tempx, tempy, dia, dia);
}//end display


EX6 Set the background to light grey and draw a filled white rectangle for the plotting area. Plot the points in the plotting area


Giving it a title

The font.pde code shows an example of working with fonts in Processing

PFont font;

void setup() {
size(630, 120);
font = createFont("SansSerif", 20);
textFont(font);
} //setup

void draw() {
background(102);
textSize(36);
text("Hello world", 27, 90);
} //draw

The text line draws the text at coordinate (27, 90). The createFont() function is used to create a font from one of the built-in typefaces.

Processing can display text in many fonts other than the default. However, before you can display text in a different font, you need to convert one of the fonts on your computer to the VLW format, which stores each letter as a small image. To do this, select Tools > Create Font to open the dialog box. Specify the font you want to convert, as well as the size and whether you want it to be smooth (anti-aliased). When you click the OK button in the Create Font tool, the VLW font is created and placed in the sketch's data folder. Now it is possible to load the font and add words to a sketch. See https://processing.org/reference/PFont.html

Once we have added the font, we can create a function to give our graph a title

void drawTitle(){
fill(0);
textSize(36);
text("My Plot", plotX1, plotY1-10);
}


EX7 Give your plot a title

L2EX7


Labelling the axes

Labelling the axes is straightforoward. You will need to decide on an interval and add this to the code before setup(). Then the following function can be used.

void drawXlabels() {
fill(0);
textSize(10);
textAlign(CENTER, TOP);
for (int i = 0; i <= maxX; i++) {
if (points[i].id % Xinterval == 0) {
float x = map(points[i].id, 0, maxX, plotX1, plotX2);
text(points[i].id, x, plotY2 + 10);
}
}
}

The fill colour is black, the text size 10 and the alignment to the CENTER so that the label centers on the position of the relevant data point. The alignment TOP sets the vertical alignment of the text.

The %, or modulo, operator is used to only draw a label when the remainder is 0 so if Xinterval was set to 3 it would draw 0, 3, 6, and 9.

EX8 Add axis labels

L2EX8

Next steps

In the next lab we'll look at time series. If you have finished early take some time to follow up some of the links to data sets in the lectures and post the most interesting on the datasets forum - https://warwick.ac.uk/fac/sci/dcs/teaching/material/cs142/datasets/