Skip to content

Pie and Donut

Polar share series. angleField sets the sector value, labelField the name (legend, callout labels, tooltip).

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'Browser share' },
    series: [
      {
        type: 'pie',
        angleField: 'share',
        angleName: 'Share, %',
        labelField: 'browser',
        sectorLabel: { enabled: true },
      },
    ],
  };
}
ts
export function getData() {
  return [
    { browser: 'Chrome', share: 64 },
    { browser: 'Safari', share: 19 },
    { browser: 'Edge', share: 6 },
    { browser: 'Firefox', share: 5 },
    { browser: 'Other', share: 6 },
  ];
}

Spacing and corner rounding for pie

The same sectorSpacing and cornerRadius also work without a ring:

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'Pie with spacing and rounded corners' },
    series: [
      {
        type: 'pie',
        angleField: 'share',
        angleName: 'Share, %',
        labelField: 'device',
        sectorSpacing: 3,
        cornerRadius: 7,
        sectorLabel: { enabled: true },
      },
    ],
  };
}
ts
export function getData() {
  return [
    { device: 'Smartphones', share: 48 },
    { device: 'Laptops', share: 24 },
    { device: 'Tablets', share: 14 },
    { device: 'Desktops', share: 9 },
    { device: 'Other', share: 5 },
  ];
}

Donut

innerRadiusRatio creates a ring; innerLabels adds text in the center.

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'Order statuses' },
    series: [
      {
        type: 'donut',
        angleField: 'count',
        angleName: 'Orders',
        labelField: 'status',
        innerRadiusRatio: 0.62,
        // callout lines: length and style of each segment are configured separately
        calloutLine: {
          radial: { length: 10, strokeWidth: 1 },
          horizontal: { length: 14, strokeWidth: 1 },
        },
        innerLabels: [
          { text: '2193', fontSize: 22, fontWeight: 'bold' },
          { text: 'orders', fontSize: 12 },
        ],
      },
    ],
    legend: { position: 'right' },
  };
}
ts
export function getData() {
  return [
    { status: 'Completed', count: 1840 },
    { status: 'Cancelled', count: 215 },
    { status: 'Refunded', count: 96 },
    { status: 'Failed', count: 42 },
  ];
}

Rotation, colors, sector labels

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'Rotation and sector labels' },
    subtitle: { text: 'rotation: -90, sectorLabel + custom colors' },
    series: [
      {
        type: 'pie',
        angleField: 'amount',
        angleName: 'Share, %',
        labelField: 'source',
        rotation: -90,
        fills: ['#1d4fd7', '#27c08d', '#f4a236', '#9a7bff'],
        sectorLabel: { enabled: true },
        calloutLabel: { enabled: false },
      },
    ],
    legend: { position: 'right' },
  };
}
ts
export function getData() {
  return [
    { source: 'Organization', amount: 46 },
    { source: 'Grants', amount: 28 },
    { source: 'Partners', amount: 16 },
    { source: 'Other', amount: 10 },
  ];
}

Custom tooltip

The series tooltip.renderer receives the whole datum, so the tooltip can display any fields:

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'Custom sector tooltip' },
    series: [
      {
        type: 'donut',
        angleField: 'visits',
        labelField: 'channel',
        innerRadiusRatio: 0.55,
        tooltip: {
          renderer: ({ datum, color }) => ({
            heading: String(datum.channel),
            rows: [
              { label: 'Visits', value: String(datum.visits), color },
              { label: 'Conversion', value: `${datum.conversion}%` },
            ],
          }),
        },
      },
    ],
    legend: { enabled: false },
  };
}
ts
export function getData() {
  return [
    { channel: 'Organic', visits: 18200, conversion: 4.1 },
    { channel: 'Ads', visits: 9400, conversion: 2.6 },
    { channel: 'Social', visits: 6100, conversion: 1.9 },
    { channel: 'Email', visits: 2800, conversion: 6.4 },
  ];
}

Spacing and corner rounding

sectorSpacing is the gap between sectors (px), cornerRadius rounds the corners:

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

const money = new Intl.NumberFormat('en-US');

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'Sector spacing and corner radius' },
    series: [
      {
        type: 'donut',
        angleField: 'amount',
        labelField: 'fund',
        innerRadiusRatio: 0.55,
        sectorSpacing: 6,
        cornerRadius: 8,
        calloutLabel: { enabled: true },
        calloutLine: {
          radial: { length: 12, strokeWidth: 1 },
          horizontal: { length: 16, stroke: '#9aa1ad', strokeWidth: 1 },
        },
        tooltip: {
          renderer: ({ label, value, color }) => ({
            heading: label,
            rows: [{ label: 'Amount', value: money.format(Number(value)), color }],
          }),
        },
      },
    ],
    legend: { enabled: false },
  };
}
ts
export function getData() {
  return [
    { fund: 'Stocks', amount: 32129675 },
    { fund: 'Bonds', amount: 9196461 },
    { fund: 'Funds', amount: 5248310 },
    { fund: 'Deposits', amount: 3933726 },
    { fund: 'Currency', amount: 3354246 },
  ];
}

Values in the legend

legendValue shows the sector value to the right of the label; the tooltip here is anchored to the cursor (tooltip.position.anchorTo: 'pointer'):

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'Values in the legend' },
    series: [
      {
        type: 'donut',
        angleField: 'amount',
        labelField: 'source',
        innerRadiusRatio: 0.62,
        sectorSpacing: 3,
        cornerRadius: 4,
        calloutLabel: { enabled: false },
        innerLabels: [
          { text: 'Total', fontSize: 13 },
          { text: '$86K', fontSize: 24, fontWeight: 'bold' },
        ],
        legendValue: {
          enabled: true,
          formatter: ({ value }) => `$${value}K`,
        },
      },
    ],
    legend: { position: 'right' },
    tooltip: { position: { anchorTo: 'pointer', yOffset: -8 } },
  };
}
ts
export function getData() {
  return [
    { source: 'Equipment sales', amount: 35 },
    { source: 'Online training', amount: 12 },
    { source: 'Athlete contracts', amount: 5 },
    { source: 'Merchandise', amount: 21 },
    { source: 'Sponsored events', amount: 13 },
  ];
}

Donut progress

A thin ring + innerLabels makes a compact indicator:

ts
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';

export function createOptions(): ChartOptions {
  return {
    data: getData(),
    title: { text: 'Year progress' },
    series: [
      {
        type: 'donut',
        angleField: 'value',
        labelField: 'state',
        innerRadiusRatio: 0.78,
        rotation: 0,
        fills: ['#21a06c', '#e8eaee'],
        calloutLabel: { enabled: false },
        innerLabels: [
          { text: '68%', fontSize: 26, fontWeight: 'bold' },
          { text: 'of plan complete', fontSize: 12 },
        ],
      },
    ],
    legend: { enabled: false },
  };
}
ts
export function getData() {
  return [
    { state: 'Done', value: 68 },
    { state: 'Remaining', value: 32 },
  ];
}

Options

Options common to all series (name, showInLegend, tooltip.renderer, …) are covered in Common series options.

OptionTypeDefaultDescription
angleFieldstringsector value (required)
labelFieldstringsector name
fillsColorValue[]theme palettesector colors around the circle
strokesColorValue[]theme palettesector colors around the circle
rotationDegrees0start angle
outerRadiusRatioFraction0.85fraction of the available radius used by the chart (labels go in the remaining space)
innerRadiusRatio (donut)Fraction0.6inner radius
angleNamestringangleField namevalue label in the tooltip
sectorSpacingPixels0constant-width gap between sectors
cornerRadiusPixels0sector corner rounding
calloutLabel.enabledbooleanon with labelFieldcallout labels
calloutLabel.fontSizePixels11callout label font
calloutLabel.fontFamilystringtheme fontfont family
calloutLabel.colorColorValueforegroundtext color
calloutLine.radial.lengthPixels20radial segment length
calloutLine.radial.strokeColorValuesector colorradial segment color
calloutLine.radial.strokeWidthPixels1width
calloutLine.horizontal.lengthPixels20length of the tail toward the label
calloutLine.horizontal.strokeColorValuesame as radialtail color
calloutLine.horizontal.strokeWidthPixelssame as radialtail width
sectorLabel.enabledbooleanfalseshare in % inside the sector
sectorLabel.positionRatioFraction0.7position along the radius
sectorLabel.fontSizePixels11font
sectorLabel.colorColorValueauto contrastcolor (halo in the sector color)
legendValue.enabledbooleanfalsesector value in the legend
legendValue.formatter({ datum, label, value, color }) => stringvaluevalue format
tooltip.renderer({ datum, label, value, color }) => …custom tooltip
innerLabels[]{ text, fontSize?, fontWeight?, color? }lines in the donut center
innerCircle.fillColorValuedonut center fill
innerRadiusRatioFraction0.6donut inner radius

Clicking a legend item hides the sector (shares are recalculated); legend items that do not fit are paginated with arrows.