?

Welcome to my blog. I do my utmost to make my code transparent and easy to understand. Send me an email with feedback!

←Return Home

Random walkers, made with D3.js and p5.js

I wrote my first line of code when I was 25, as a PhD student at Caltech. That was one year ago, and it was all Python. Now, I'm practicing JavaScript every day, because I think it will help me be a better journalist, merging writing with interactive visualizations. I'm still very much learning, and I used to be ashamed of that. I used to think that, since I was learning, I could not possibly post examples of my work because they wouldn't be good enough. I now feel that's a foolish mindset, and so I've been trying to put everything I do on this website; by tracking my posts over time, I can see the coding progress that I am making.

Today, I built a two-dimensional random walker (2D) in two different ways. In the first iteration, I'll use D3.js and a bit of vanilla JavaScript. Then, I'll show how that code can be reduced considerably by using p5.js. Join me!

The random walker above was made with D3.js. The first thing I did was create an asynchronous function, called d3RandomWalk, and then call it. In that function, I set three variables that specify the length of each "step" in the random walker, as well as the width and height of the svg wrapper that holds the animation.


async function d3RandomWalk() {
	const width = 400;
	const height = 400;
	const step_length = 5;
}

d3RandomWalk();

Next, I use the D3.js library to select a div element in my HTML, and append an svg to it.


var svg = d3.select("#random-walk")
	.append("svg")
	.attr("viewBox", [0, 0, width, height])

Now we can append the random walker to that svg element, and it will display on the page. To create the actual random walker, there are three functions that are needed: 'direction', 'take_step', and 'add_line'.


function direction() {
	return Math.random() > .5 ? 1 : -1;
}

function take_step(position) {
	var step = step_length * direction();
	if (Math.random() > 0.5)
		return {"x" : position.x + step, "y" : position.y};
	return {"x" : position.x, "y" : position.y + step};
}

function add_line(position, next_position) {
	svg.append("line")
		.attr("x1", position.x)
		.attr("y1", position.y)
		.attr("x2", next_position.x)
		.attr("y2", next_position.y)
		.attr("stroke", "black")
		.attr("stroke-width", 2);
	}

The first function, 'direction', uses JavaScript's Math.random() function, coupled to a switch statement, to return a +1 or -1 digit. The next function, 'take_step', then uses that +1 or -1, in addition to another Math.random() statement, to "decide" where to step next; left, right, up, or down. Finally, the 'add_line' function uses D3.js to draw the physical, black line that renders on the SVG. I've set the stroke to black, and the stroke-width to 2, but you could easily make these lines appear in a myriad of colors.

In the final bit of code, I set up a timer function that stops the random walker after 30 seconds. It uses the functionality of d3.timer().


let pos = {"x" : width/2, "y" : height/2};
let next_pos;

var timePassed = d3.timer(function(elapsed) {
	next_pos = take_step(pos);
	add_line(pos, next_pos);
	pos = next_pos;
	if (elapsed > 30000) timePassed.stop();
})

And that's it! That's a simple way to make a two-dimensional random walker using JavaScript. Next, let's see how all that code can be condensed into ~40 lines of code, using the p5.js library.

The code to create the random walker with p5.js (shown above) is pretty simple. First, define necessary variables for the line (which takes four arguments, initial x and y coordinates, as well as "future" x and y coordinates). I used p5's built-in "random" function to decide which direction to step, and then drew lines for each iteration through the loop. The reason that this code works, and runs repeatedly without any loops, is because the "draw" function in p5.js automatically runs on repeat, while the setup function runs just once. That makes p5.js really versatile and fun to play with to create moving, interactive sketches. You can even set the frame rate of the draw() function to change the speed of each loop.


async function p5RandomWalk() {
	let sketch = function(p) {
		let x;
		let y;
		let x_next;
		let y_next;
		
		p.setup = function(){
		p.createCanvas(400, 400);
		p.background(255);
		x = p.width / 2;
		y = p.height / 2;
		}

		p.draw = function(){
			const step = p.floor(p.random(4));
			switch (step) {
			case 0:
				x_next = x + 5;
				y_next = y;
				break;
			case 1:
				x_next = x - 5;
				y_next = y;
				break;
			case 2:
				y_next = y + 5;
				x_next = x;
				break;
			case 3:
				y_next = y - 5;
				x_next = x;
				break;
		}

		p.stroke(0);
		p.strokeWeight(3);
		p.line(x, y, x_next, y_next);
		x = x_next;
		y = y_next;
		}
	};
	new p5(sketch, 'p5-canvas');
}
	
p5RandomWalk()

In the future, I'd like to make a 3D random walker with Three.js, like this example.

Thanks for reading!

←Return Home