Cartesian charts
Compose line, area, and bar layers over shared scales.
Try it
These previews run the exact builder functions in the code sample below.
Line and area layers share the sample’s dataset and axes.
Drawing layers
Each LineLayer, AreaLayer, or BarLayer selects a series by ID. Multiple layers can share a dataset and scales. Style methods change appearance; they do not add drawing layers.
use gpui::rgb;
use xgpui_luma_plot::{
AreaLayer, AreaPresentation, Axis, AxisPresentation, AxisSide,
BarLayer, BarLayout, BarGrouping, BarOrientation, BarPresentation,
CartesianChartBuilder, CartesianChartView, CategoryScale,
Dataset, DatasetError, Decimation, Interpolation, LineLayer,
LinePresentation, NumericScale, Sample, Series,
};
fn combined_chart() -> Result<CartesianChartView, DatasetError> {
let data = Dataset::new().with_series(Series::new("visits", "Visits", [
Sample::new(0.0, 12.0), Sample::new(1.0, 24.0), Sample::new(2.0, 18.0),
]))?;
let axis = AxisPresentation::new(rgb(0x64748b).into());
Ok(CartesianChartBuilder::new(data)
.id("visits-chart")
.x_scale(CategoryScale::new(["Mon", "Tue", "Wed"]))
.y_scale(NumericScale::new().domain(0.0..=30.0).tick_count(4))
.area(AreaLayer::new("visits").baseline(0.0)
.interpolation(Interpolation::Monotone))
.area_style("visits", AreaPresentation::new(rgb(0xdbeafe)))
.line(LineLayer::new("visits")
.interpolation(Interpolation::Monotone)
.decimation(Decimation::MinMax))
.line_style("visits", LinePresentation::new(rgb(0x2563eb).into()))
.axes([
Axis::new(AxisSide::Bottom, axis.clone()).title("Day"),
Axis::new(AxisSide::Left, axis).title("Visits"),
])
.build())
}
fn bar_chart(data: Dataset) -> CartesianChartView {
CartesianChartBuilder::new(data)
.id("sales-chart")
.x_scale(CategoryScale::new(["Mon", "Tue", "Wed"]))
.bar(BarLayer::new("desktop"))
.bar(BarLayer::new("mobile"))
.bar_layout(BarLayout::new().grouping(BarGrouping::Stacked))
.bar_orientation(BarOrientation::Up)
.bar_style("desktop", BarPresentation::new(rgb(0x2563eb)))
.bar_style("mobile", BarPresentation::new(rgb(0x14b8a6)))
.build()
}For the bar example, supply a dataset with desktop and mobile series. Each sample uses X for category index and Y for value, including horizontal bar orientations. Render either built chart inside a sized host, as shown in Getting started.
Scales and axes
NumericScale supports automatic or explicit domains, linear or logarithmic mapping, tick counts, explicit tick values, and label overrides. CategoryScale maps zero-based numeric category indices to labels.
Axis placement is presentation: top/bottom axes use the X scale, and left/right axes use the Y scale. Opposing axes share a scale; adding a right axis does not create a second independent Y domain. Grid styling is configured separately.
Bar layout
BarLayout selects grouped or stacked series, group alignment, occupied category-band width, and grouped-slot gap. BarOrientation chooses Up, Down, Left, or Right. Positive and negative stacked values accumulate separately from each layer’s baseline; differing baselines form separate stacks.
Use .bar_template(...) for custom bar rendering and .bar_labels(...) or .bar_value_labels(...) for labels.
Line behavior
Linear interpolation is the default. Interpolation::Monotone smooths suitable runs without overshooting neighboring values, with straight-segment fallbacks for repeated or reversing X values and short runs. Non-finite observations break lines.
Decimation::MinMax reduces drawing points by pixel column while preserving the stored samples. It is intended for dense lines; evaluate the appearance with your data and viewport.
Interaction and view state
Cartesian builders expose .on_point_event(...), point/slice tooltips, legend interaction, annotations, and render statistics. PlotPointEvent reports hover changes and picked observations. The host owns persistent selection.
.viewport(&viewport) applies numeric domains from Viewport; category axes remain unchanged. Pan/zoom input handling and redraws belong to the host. Supplying a viewport alone does not install gestures.