Donut chart race

Four donuts charts aligned from left to right

A donut chart race, or a pie chart race, is another great chart to illustrate continuous or categorical data proportion over time. Using Javascript and Highcharts library, it is super easy to create an interactive donut chart race.

In this article, I will show you how to create an interactive donut race chart (see demo below):

The donut race chart above visualizes the nuclear energy production from 1965 to 2021 in the US, UK, France, and Japan.

A donut race chart offers the following advantages: easy understanding, effectively showing proportion, comparisons between categories, visual interest, and dynamic presentation.

Let’s dive into the code to see how you can create such a powerful chart.

The code behind this demo is quite similar to the previous article, bar chart race. I highly recommend reading the bar chart race since it describes the code in very thorough detail, which I will not cover all the details in this article. If you have already read it, well, enjoy the following paragraphs.

Let’s start 🙂
I am collecting the JSON dataset using the fetch API that comes with the native JavaScript dataset = await fetch(...
The dataset is a mixture of the nuclear energy produced and years of production:

"1965": "20.0231569",
"1966": "28.2714305",
"1967": "35.26512",
"1968": "45.27281",
...

I extract the year part with the function getSubtitle() to display it in the donut’s center:

function getSubtitle() {
  const totalNumber = getData(input.value)[0][1].toFixed(2);
  return `<span style="font-size: 80px">${input.value}</span>
        <br>
        <span style="font-size: 22px">
            Total: <b> ${totalNumber}</b> TWh
        </span>`;
}

The rest of the dataset (nuclear energy produced) is extracted by this function getData():

function getData(year) {
  const output = Object.entries(dataset).map(country => {
    const [countryName, countryData] = country;
    return [countryName, Number(countryData[year])];
  });
  return [output[0], output.slice(1, nbr)];
}

The rest of the functions I just borrowed from the bar race chart with no modifications, such as:

function pause(button)
function update(increment)
function play(button)
btn.addEventListener()
input.addEventListener()

I faced some challenges using the labels since the library reserves space for the data labels, but when the data labels move around, this ends up in the shaky chart where the donut keeps resizing. To overcome this challenge, I had to make some modifications in the option section, by setting the connectorWidth option to zero and bringing the label to the donut area. The plotOptions looks like:

plotOptions: {
  series: {
    borderWidth: 0,
    colorByPoint: true,
    type: 'pie',
    size: '100%',
    innerSize: '80%',
    dataLabels: {
      enabled: true,
      distance: -20,
      style: {
        fontWeight: 'bold',
        fontSize: '16px'
      },
      connectorWidth: 0
    }
  }
},

With these modifications, this design is stable since the donut size is the same at all times.

Now, you know how to create a pie race chart, a handy chart to show trends, changes, and comparisons, with all the benefits of an animated chart.