Simple animated graph

Posted .

Using transitions we can easily animate a graph. In this example we will be sampling a multivariate normal distribution for our data points.

Here is the source of the final graph (and the source of the fallback).

Sampling

We will not cover how to generate samples from a multivariate normal distribution. Assume there exists a sample function that can do the following.

let s = sample()
console.log(s)
//{
//  x: -1.338422862851693,
//  y: -0.2415765924800481,
//  p: 0.16190472411102744
//}

If you want to know how we did this you can reference the source code.

Colour scale

There are a whole lot of different color schemes available in d3. There are various interpolate functions that map the [0, 1] domain onto a range of colours, we will be using the d3.interpolateRdYlBu to map probabilities onto a colour scale. Alternatively you could reference the various scheme arrays when defining the range of a scale. These arrays contain arrays of colours themselves. So d3.schemeRdBu[k] returns an array of length k with colours ranging from red to blue, the size k can range from 3 to 11.

Transitions

First we need to define a transition, unless you are satisfied with the defaults.

var t = d3.transition()
  .duration(300) // default 250ms
  .ease(d3.easeLinear) // default d3.easeCubic

Then we need to use it while setting an attribute of an element by calling the transition method. Here we place a circle at 100x100 and have it grow from a radius of 0 to a radius of 10 over 300ms.

svg.append("circle")
  .attr("transform", "translate(100, 100"")
  .transition(t)
  .attr("r", 10)

If we had placed the transition before setting the transform the transform would have been animated as well. You can delay a transition by calling the delay method with number of milliseconds as a parameter.

Animation

By combining the things described above we can create a draw function that draws a circle at a random location (determined by a multivariate normal distribution), gives it a colour corresponding to its probability, and fades it into and out of existence.

function draw() {
  let s = sample()

  var t = d3.transition()
    .duration(800)
    .ease(d3.easeLinear);

  graph.append("circle")
    .attr("transform", `translate(${x(s.x)}, ${y(s.y)})`)
    .attr("fill", d3.interpolateRdYlBu(s.p))
    .transition(t)
    .attr("r", 3)
    .transition(t)
    .delay(400)
    .attr("r", 0)
    .remove()
}

Then we can use the setInterval function to call the draw function at 20ms intervals.

setInterval(draw, 20)

The result is an animated graph that shows a cloud of 100 samples of the distribution all randomly fading into and out of existence. See fig. 1.

x-3.0-2.5-2.0-1.5-1.0-0.50.00.51.01.52.02.53.0y-3.0-2.5-2.0-1.5-1.0-0.50.00.51.01.52.02.53.0