HAHS.
Back to Catalog

Donut Chart

chart

Also known as: doughnut chart, ring chart

Show composition CategoricalNumerical Arc/Radial

Description

The donut chart is a variant of the pie chart in which the center of the circle is removed, creating a ring of arc segments. Each segment’s angular sweep and arc length represent a category’s proportion of the whole, just as in a standard pie chart. The hollow center is often used to display a summary metric (total count, percentage of a key segment, or a label), making the chart both a compositional display and a big-number indicator.

Perceptually, the donut chart shifts emphasis from the area of wedges (pie) to the length of arcs along the ring. Some researchers argue this makes comparison slightly harder than in a standard pie chart, while others suggest the difference is negligible for the typical use case of 2-5 categories. In practice, donut charts are often preferred for aesthetic reasons: the center hole reduces visual clutter and creates a natural focal point for key information.

Donut charts are extremely common in dashboards and data products because they serve double duty as both a proportion display and a KPI widget. When used thoughtfully — few categories, clear labeling, and a meaningful center metric — they communicate effectively. When overloaded with many thin slices or stacked as nested rings, they become difficult to read.

Donut Chart — interactive example

When to Use

  • Displaying part-to-whole proportions with 2-5 categories
  • Dashboard KPI widgets where you want to show both a key number and its compositional context
  • When you need to place a summary statistic or icon in the center of the chart
  • When visual style calls for a lighter, more modern look than a solid pie chart

When NOT to Use

  • When precise comparison between categories matters — use a bar chart
  • When there are more than 6 categories — thin arcs become unreadable
  • When the data does not represent parts of a meaningful whole
  • Nested donut rings for hierarchical data — use a sunburst or treemap instead, which handle multiple levels more clearly
  • Comparing proportions across multiple groups — use stacked bar charts

Anatomy

  • Arcs (segments): Ring-shaped segments whose angular extent encodes each category’s proportion.
  • Inner radius: The radius of the center hole. Typically 40-70% of the outer radius for a balanced appearance.
  • Outer radius: The outer edge of the ring.
  • Center area: The hollow space, often used for a total, percentage, icon, or label.
  • Colors: Each arc segment has a distinct color from a qualitative palette.
  • Labels: Direct labels (category name + percentage) placed near each arc or connected via leader lines.
  • Legend: An alternative to direct labeling, placed beside or below the chart.

Variations

  • Half donut (gauge chart): A semicircular donut showing a single value’s progress toward a goal, often used for KPIs and dashboards.
  • Nested donut: Concentric rings where each ring represents a different categorical breakdown. Functions like a simplified sunburst.
  • Multi-donut (small multiples): Several donut charts placed side by side for comparison across groups, each showing the same set of categories.
  • Animated donut: Arcs grow from zero with a transition, drawing attention and making the assembly of the whole visible.
  • Progress donut: A single arc showing completion toward 100%, with the remaining portion in a muted color. Very common in fitness apps and dashboards.

Code Reference

// D3 - donut chart with center label
const pie = d3.pie().value(d => d.value).sort(null)(data);
const arc = d3.arc().innerRadius(70).outerRadius(120);

const svg = d3.create("svg").attr("viewBox", "-150 -150 300 300");
svg.selectAll("path")
  .data(pie)
  .join("path")
  .attr("d", arc)
  .attr("fill", (d, i) => d3.schemeTableau10[i])
  .append("title")
  .text(d => `${d.data.label}: ${d.data.value}`);

svg.append("text")
  .attr("text-anchor", "middle")
  .attr("dy", "0.35em")
  .attr("font-size", "24px")
  .text(d3.sum(data, d => d.value));