Radial charts

Show observations as concentric progress arcs or stacked angular segments.

Try it

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

Goal completion

Hover a bar to see its goal and value.

Open example separately ↗

Basic use

RadialChartBuilder combines a RadialPlot, one series, and presentation. Each accepted observation becomes a bar, rather than a separate series.

Rust
use gpui::{div, prelude::*, px};
use xgpui_luma::controls::tooltip::Tooltip;
use xgpui_luma_plot::{
    Dataset, DatasetError, RadialChartBuilder, RadialLayout,
    RadialPresentation, Sample, Series,
};

fn completion() -> Result<impl IntoElement, DatasetError> {
    let data = Dataset::new().with_series(Series::new("goals", "Goals", [
        Sample::new(0.0, 80.0), Sample::new(1.0, 60.0), Sample::new(2.0, 40.0),
    ]))?;
    let chart = RadialChartBuilder::new(data, "goals")
        .id("goal-completion")
        .bar_names(["Build", "Test", "Review"])
        .layout(RadialLayout::Concentric)
        .maximum(100.0)
        .angles(-90.0, 270.0)
        .style(|| {
            let mut style = RadialPresentation::default();
            style.rounded = true;
            style.legend.visible = true;
            style
        })
        .bar_labels(|bar| format!("{:.0}%", bar.fraction * 100.0).into())
        .center_text("Goals", "Completion")
        .bar_tooltip(|bar| Tooltip::new(format!("{}: {}", bar.label, bar.sample.y)))
        .build();
    Ok(div().w_full().h(px(340.0)).child(chart))
}

Handle the dataset result in the owner and render the sized element. In this example, percentages are relative to the explicit maximum of 100, not the sum of observations.

Layout and normalization

LayoutMapping
Concentric (default)One track per observation. Automatic normalization uses the largest accepted value.
StackedObservations share one track. Automatic normalization uses their total.

A positive explicit .maximum(...) overrides automatic normalization in either layout. Finite samples with positive Y are accepted; invalid samples and nonpositive values are omitted. Original sample indices, names, and colors remain aligned. .bar_names(...) uses source sample positions.

.angles(start, sweep) uses degrees from the rightward ray. Positive sweeps grow clockwise, negative sweeps counterclockwise; sweeps clamp to −360–360. The default is a complete counterclockwise circle. Radial bars measure values against a maximum; unlike pie slices, concentric bars do not necessarily sum to a whole.

Styling and labels

.style(...) accepts a closure returning RadialPresentation each render. Configure palette and source-index fill overrides, inner/outer radius ratios, track backgrounds, rounded caps, gaps, grid, legend, empty state, and label text there. The legend is hidden by default.

.bar_labels(...) supplies text inside visible bars. .center_text(...) is host-supplied; it does not compute a total. Resolve theme colors in the style closure and request an owner redraw when the theme changes. See Styling.

Interaction and motion

.bar_tooltip(...) receives a RadialBar with the original series, sample, sample index, label, and displayed fraction of the maximum. Configure hover delay on the returned SDK Tooltip.

.on_bar_event(...) reports SelectionEvent<RadialBar> hover changes and activation. The host owns persistent selection. Legend interaction uses .legend_interaction(...).

.draw_progress(...) controls angular growth from 0–1. The host drives replay time and redraws; source values remain unchanged. .tooltip_motion(...) controls tooltip anchor transitions.

Source

Radial builder and events · Radial presentation · Native gallery