Radar charts

Compare series across a shared set of category spokes.

Try it

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

Series comparison

Hover a spoke to compare observations.

Open example separately ↗

Basic use

RadarChartBuilder combines a RadarPlot, dataset, categories, and presentation. Supply at least three categories to form a radar polygon.

Rust
use gpui::{div, prelude::*, px};
use xgpui_luma::controls::tooltip::Tooltip;
use xgpui_luma_plot::{
    Dataset, DatasetError, RadarChartBuilder, RadarGridShape,
    RadarPresentation, Sample, Series,
};

fn comparison() -> Result<impl IntoElement, DatasetError> {
    let data = Dataset::new()
        .with_series(Series::new("current", "Current", [
            Sample::new(0.0, 80.0), Sample::new(1.0, 60.0), Sample::new(2.0, 90.0),
        ]))?
        .with_series(Series::new("previous", "Previous", [
            Sample::new(0.0, 65.0), Sample::new(1.0, 75.0), Sample::new(2.0, 70.0),
        ]))?;
    let chart = RadarChartBuilder::new(data, "current")
        .id("performance-radar")
        .series("previous")
        .categories(["Speed", "Quality", "Reliability"])
        .maximum(100.0)
        .style(|| {
            let mut style = RadarPresentation::default();
            style.grid_shape = RadarGridShape::Circle;
            style.legend.visible = true;
            style
        })
        .spoke_tooltip(|spoke| {
            Tooltip::new(format!("{}: {} series", spoke.category, spoke.points.len()))
        })
        .build();
    Ok(div().w_full().h(px(340.0)).child(chart))
}

Handle the dataset result in the owner and render the returned element. Rebuild the element from retained application data when the owner renders.

Spokes and scale

X is an integer, zero-based category/spoke index. Y is a nonnegative radial value. All series use the same category order and zero-based radial scale. Invalid category coordinates and invalid or negative values do not supply valid spoke observations.

Automatic scaling considers valid values across the selected series. .maximum(...) sets a shared positive radial maximum; values above it are clamped visually. Use a fixed maximum when comparing charts or values across time. .start_angle(...) is degrees clockwise from the rightward ray; the default −90 places the first spoke at the top.

Styling and category labels

.style(...) accepts a closure returning RadarPresentation on every render. Its per-series map contains RadarSeriesPresentation values for fills, strokes, and dots; other series use the palette.

Configure polygon/circle grid boundaries, fractional grid levels, spokes, background fill, labels, legend, and spacing through presentation. Circle grids do not turn series polygons into curves. The legend is hidden by default. .category_labels(...) customizes category text. Theme changes still require an owner redraw.

Interaction and motion

.spoke_tooltip(...) targets the nearest angular category inside the outer grid and receives a RadarSpoke containing accepted observations across series. Each RadarPoint retains its source sample and index.

.on_spoke_event(...) reports SelectionEvent<RadarSpoke> hover changes and activation. Persistent selection and application updates belong to the host. .legend_interaction(...) handles legend activation separately.

.draw_progress(...) controls radial growth from the center, clamped to 0–1. The host drives time and redraws. .tooltip_motion(...) controls anchor transitions between spokes; hover delay is configured on the supplied SDK Tooltip.

Source

Radar builder and events · Radar presentation · Native gallery