Pie & donut

Show positive weights as angular shares, with optional holes and concentric rings.

Try it

These previews run the exact builder functions in the code sample below.

Hover a slice to see its tooltip.

Open example separately ↗

Basic use

PieChartBuilder combines a PiePlot, dataset, and presentation into a GPUI element. A donut uses the same builder with a nonzero .inner_radius(...); there is no separate donut control.

Rust
use gpui::{div, prelude::*, px};
use xgpui_luma::controls::tooltip::Tooltip;
use xgpui_luma_plot::{
    Dataset, DatasetError, PieChartBuilder, PieLabelPlacement,
    PiePresentation, PieRingPresentation, Sample, Series,
};

fn browser_share() -> Result<impl IntoElement, DatasetError> {
    let data = Dataset::new().with_series(Series::new("browsers", "Browsers", [
        Sample::new(0.0, 275.0), Sample::new(1.0, 200.0), Sample::new(2.0, 125.0),
    ]))?;
    let chart = PieChartBuilder::new(data, "browsers")
        .id("browser-share")
        .style(PiePresentation::default())
        .inner_radius(0.6)
        .slice_names(["Chrome", "Safari", "Other"])
        .slice_labels(|slice| format!("{:.0}%", slice.fraction * 100.0).into())
        .style_override(|style| style.label_placement = PieLabelPlacement::Outside)
        .center_text("600", "Visits")
        .legend(true)
        .slice_tooltip(|slice| Tooltip::new(format!("{}: {}", slice.label, slice.sample.y)))
        .build();
    Ok(div().w_full().h(px(320.0)).child(chart))
}

fn comparison_rings(data: Dataset) -> impl IntoElement {
    let chart = PieChartBuilder::new(data, "current")
        .id("comparison-rings")
        .slice_names(["Chrome", "Safari", "Other"])
        .inner_radius(0.4)
        .outer_radius(0.65)
        .ring("previous", PieRingPresentation::new(0.72, 1.0))
        .build();
    div().w_full().h(px(320.0)).child(chart)
}

Handle DatasetError in the owning view and render the returned element. For the ring example, supply current and previous series. Give sibling charts distinct IDs.

Data and angles

Y contains weights, not required percentages. Only finite samples with positive Y contribute. Accepted weights are normalized within each pie; original sample indices and order remain intact. X is an optional numeric category coordinate, not an angle.

.slice_names(...) indexes names by original sample position; omitted samples do not shift later names or colors. Missing names fall back to X. .start_angle(...) uses degrees from the rightward ray; positive angles point clockwise on screen. .clockwise(true) changes sector traversal from the default counterclockwise direction.

Donuts and concentric rings

.inner_radius(...) is the hole/outer-radius ratio, clamped to 0–0.95. .outer_radius(...) scales the primary pie against the common chart radius. Added PieRingPresentation bands specify inner/outer ratios against that same common radius.

Each added series is normalized independently. Choose separated bands explicitly; the builder allows overlapping bands. Center text is host-supplied and is not an automatically computed total.

Styling and labels

Bind PiePresentation or a live PieStyleProvider using .style(...), then apply local overrides. Binding a new style clears earlier style overrides, including radius helpers. Palette, per-sample fills, labels, leader lines, legend, active expansion, and empty-state appearance belong to presentation.

Labels are opt-in through .slice_labels(...); choose Inside or Outside placement. .slice_style(index, fill) overrides a source sample’s fill. The built-in legend is hidden unless enabled. See Styling for theme and redraw ownership.

Interaction and motion

.on_slice_event(...) reports PieSliceEvent::HoverChanged and Select with original observations. PieSlice includes the series, sample index, normalized fraction, and ring identity: ring_index is None for the primary pie or the added ring’s zero-based index.

The host owns persistent selection. Pass it back with .active_slice(...), .ring_active_slice(...), or .active_ring_slice(...). Use ring-index selection when the same series is added more than once.

.slice_tooltip(...) supplies SDK tooltips; configure delay on the returned Tooltip. .tooltip_motion(...) and .active_motion(...) configure transitions. .draw_progress(...) reveals sectors in angular order; the host drives replay timing and redraws.

Source

Pie builder and events · Pie presentation · Native gallery