Language selection

Health Infobase Design Manual

  Table of contents


Pie chart and doughnut chart

A pie chart is a visual representation of data of the relative sizes or proportions of different data points.

A doughnut chart is similar to a pie chart, but it has a hole in the centre, which makes it easier to compare the proportions of different data points.

When to use

  • To show the relative size or proportion of different data points
  • To compare the proportions of different data points
  • To illustrate a “part-to-whole” relationship

Examples

  • A pie chart showing how much is spent on healthcare by different categories, such as hospital care, prescription drugs, and preventive care
  • A doughnut showing the proportion of deaths due to different causes in a population

What to avoid

  • Don’t use pie charts or doughnut charts to show data that does not have a clear numeric value
  • Don’t use pie charts or doughnut charts to show data with different units or different scales
  • Pie charts or doughnut charts are usually hard to read if there are too many categories, so avoid using pie charts with more than 5-6 categories
  • In most cases, there are better alternatives to Pie chart and doughnut charts (such as bar graphs or stacked bar graphs)

Design and code

HTML
<!-- Add D3 library in the head section -->
<script src="https://d3js.org/d3.v7.min.js"></script>
   
<!-- Add a div in the section where you want the graph -->
<div id="pieGraph"></div>
JS
<script>
    const width = 650, height = 650, margin = 100;
        
        // radius of the pie graph is half the width or half the height
        const radius = Math.min(width, height) / 2 - margin;
        
        const svg = d3.select("#pieGraph")
          .append("svg")
            .attr("width", width)
            .attr("height", height)
          .append("g")
            .attr("transform", `translate(${width/2},${height/2})`);
        
        // dummy fruit data
        const data = {Apples: 26, Oranges: 12, Pears:33, Bananas:8, };
        
        const color = d3.scaleOrdinal()
          .domain(["Apples", "Oranges", "Pears", "Bananas",])
          .range(d3.schemeDark2);
        
        // compute the position of each group
        const pieGraph = d3.pie()
          .sort(null) 
          .value(d => d[1]);
          
        const pieData = pieGraph(Object.entries(data));
        
        const arc = d3.arc()
        // size of the inner hole (to get a pie chart instead od a doughnut chart, change inner radius to 0)
          .innerRadius(radius * 0.5)
          .outerRadius(radius * 0.8);
        
        // arc for label positioning
        const outerArc = d3.arc()
          .innerRadius(radius * 0.9)
          .outerRadius(radius * 0.9);
    
        // build the pie chart path
        svg
          .selectAll('path')
          .data(pieData)
          .join('path')
              .attr('d', arc)
              .attr('fill', d => color(d.data[1]))
              .attr("stroke", "white")
              .style("opacity", 0.7)
              .style("stroke-width", "2px");
    
        // Add lines for labels
        svg
          .selectAll('polyline')
          .data(pieData)
          .join('polyline')
            .attr("stroke", "black")
            .style("fill", "none")
            .attr("stroke-width", 1.3)
            .attr('points', function(d) {
              const position1 = arc.centroid(d);
              const position2 = outerArc.centroid(d);
              const position3 = outerArc.centroid(d); 
              const middleAngle = d.startAngle + (d.endAngle - d.startAngle) / 2;
              position3[0] = radius * 0.95 * (middleAngle < Math.PI ? 1 : -1); 
              return [position1, position2, position3]
            })
    
        // Add the polylines between chart and labels:
        svg
          .selectAll('text')
          .data(pieData)
          .join('text')
            .text(d => d.data[0])
            .attr('transform', function(d) {
                const position = outerArc.centroid(d);
                const middleAngle = d.startAngle + (d.endAngle - d.startAngle) / 2
                position[0] = radius * 0.99 * (middleAngle < Math.PI ? 1 : -1);
                return `translate(${position})`;
            })
            .style('text-anchor', function(d) {
                const middleAngle = d.startAngle + (d.endAngle - d.startAngle) / 2
                return (middleAngle < Math.PI ? 'start' : 'end')
            });
</script>

Content and design guidelines

  • Try to limit the number of categories to avoid confusion
  • Use colour wisely to differentiate the different categories
  • Consider having the labels directly within the areas of the chart, if possible
  • Follow the general design guidelines

Accessibility guidelines

  • Provide a data table with the chart
  • If the pie chart or doughnut chart tells a clear story, include that story in the alt text. For example, if the graph shows that category has a much higher value than the others, spell that out in the alt text
  • Follow the general accessibility guidelines
Date modified: