D3 is a good library for data visualisation. I wanted to visualise an ideal particle in a rectangular 2 dimensional box bouncing off the walls then progress to including gravity in the solution. The mathematics for such a particle is simple. In the process I learned a few things about D3, for example use of map attribute to initialise data and the use of the timer function.

**Theory**

A particle moving in an otherwise empty two dimensional box has a velocity

__= (v__

**v**_{x},v

_{y}). The walls are taken to be parallel to the x and y axes. When the particle hits a wall parallel to the x axis v

_{y}→ - v

_{y}.

When it hits a wall parallel to the y axis v

_{x}→ - v

_{x }.

Clearly such a particle will bounce off the walls forever. In a package like Director this was easy to implement but proved a little tricky in D3

The effect of gravity is included by noting that for the y velocity

dv = g.dt and setting dt = 1.

**Computational Aspects**

A real particle moves continuously. In the simulation the virtual particle moves in discrete steps and may never “hit” the virtual wall of the box. Suppose it moves v

_{x}pixels along the x axis per time step then if at the end of a step it is v

_{x}/2 pixels from the wall it will go through the wall unless told to stop.

So the particle must be told to reverse its motion when it is about to cross a wall. This risks the virtual particle bouncing before it touches the wall, which is unconvincing, though it can be prevented. Here the problem of non rectangular boxes is ignored.

**Some code details**

The first step is to initialise the data.

// Map the range to an array of data of the same size

// For a large number of balls produces seemingly random motion instantly

var numballs=<your chosen value>;

var acceleration = <your chosen value>;

var data = d3.range(numballs).map(

function(d,i)

{

// Assign random x and y velocities to each particle

var vx = randomVelocity(1);

var vy = randomVelocity(1);

// make some velocity components negative

if(Math.random()<0.5) vx = -vx;

if(Math.random()<0.5) vy= -vy;

// Assign random positions to the particles.

var itsx = itsx = 10*Math.random() -5;

var itsy = itsy =10*Math.random()-5;

return {xloc: itsx, yloc: itsy, xvel: vx, yvel: vy};

}

);

**Scaling the data**

var y = d3.scale.linear().domain([-5, 5])range([0, height]);

This puts the origin at the centre of the screen.

**The Timer Function**

d3.timer(

function()

{

data.forEach( function(d) { update(d);} );

// Move each circle; define a coordinate transform

// translate circle by scaled coordinates

circle.attr("transform", function(d)

{ return "translate(" + x(d.xloc) + "," + y(d.yloc) + ")"; }

)

// just for fun shrink circle radius near the origin

.attr("r", function(d)

{return Math.sqrt(d.xloc*d.xloc +d.yloc*d.yloc)} ) ;

}

);

**Updating coordinates**

function update(d)

{

// record old positions, calculate new positions, update positions.

var oldx = d.xloc;

var newx = oldx + d.xvel;

d.xloc= newx;

var oldy = d.yloc

var newy= d.yloc + d.yvel;

d.yloc = newy;

// The upper and lower limits were established empirically-

// to convincing right bounce action

var lowerlimit = -5.1;

var upperlimit = 4.7;

// iscrossing returns true if the ball is about to hit a wall.

xcrossing = iscrossing(oldx,newx,upperlimit,lowerlimit);

ycrossing= iscrossing(oldy,newy,upperlimit,lowerlimit);

// reverse appropriate velocities if about to hit a wall.

if(ycrossing )

{

d.yvel = -d.yvel;

d.yloc += d.yvel;

}

if(xcrossing )

{

d.xvel = -d.xvel;

d.xloc += d.xvel;

}

}

Here is the function that decides if the particle is about to hit a wall.

Basically if it is about to cross a wall reverse the velocity component.

function iscrossing(old, new, upperlimit,lowerlimit)

{

var crossing = old< upperlimit && new > upperlimit;

crossing = crossing || old > upperlimit && new < upperlimit;

crossing = crossing || old < lowerlimit && new>= lowerlimit;

crossing = crossing || old > lowerlimit && new<=lowerlimit;

return crossing;

}

**Including Gravity**

The effect of gravity was included by updating the y velocity immediately before updating the position. Failure to do this resulted in unrealistic behaviour.

var oldy = d.yloc

// The velocity update needs to be applied before not after updating position

d.yvel += acceleration;

var newy= d.yloc + d.yvel;

d.yloc = newy;

The initial value of the acceleration was set at 0.01.

**Results**

After some experimentation with the parameters I managed to get realistic behaviour. For an initially localised swarm of particles the swarm gradually diverged and appeared eventually to reach a state close to random motion, but with some sets of particles moving in unison.

The behaviour was improved, as would be expected, by assigning each particle a random initial velocity and position.

Introducing acceleration led to an apparent bunching of particles at “ground” level while high accelerations resulted in the swarm rising and falling together something like the motion of waves on the sea

**The Wrap**

The results so far show that an originally localised swarm would slowly tend to approximate particles in an ideal gas but assigning random initial positions resulted in almost instant approximation to an ideal gas.

They also showed that watching the swarm is hypnotic.