charts-rs is a charting library for rust. It's simple and fast.
charts-rs provides a straightforward approach to generating charts with support for multiple output formats including svg, png, jpeg, webp, and avif. The library offers ten distinct themes: light, dark, grafana, ant, vintage, walden, westeros, chalk, shine, and shadcn, with light as the default theme.
The library supports twenty-two chart types: Bar, HorizontalBar, Line, Pie, Radar, Scatter, Candlestick, Table, Heatmap, Funnel, Waterfall, MultiChart, Calendar, Gauge, Treemap, BoxPlot, Sunburst, Sankey, Tree, Graph, Parallel, and ThemeRiver. Drawing inspiration from Apache ECharts, charts-rs enables developers to create charts with similar functionality and appearance.
- Ten built-in themes; custom themes supported via
add_theme() - Custom font loading from ttf or otf files
- Advanced line chart features: smooth curves, area filling, mark points and mark lines
- Multiple legend styles across all charts:
round rect,circle, andrect - Dual y-axis support via
y_axis_configsandseries.y_axis_index - Logarithmic scale support (
"log","log2", or{"type":"log","base":N}) - Gradient fill for bars, areas, and pie slices (
Fill::LinearGradient) - Per-series mixed chart types (bar + line on the same chart)
- Series stacking, dash patterns, and per-bar custom colors
- SVG animation support (duration, easing, stagger) for bar, line, pie, sunburst, funnel, treemap, and sankey charts
- Null / missing data points via
Option<f32>(nullin JSON; legacyNIL_VALUEstill accepted) - JSON-based chart configuration for all chart types
- Multiple output formats: svg, png, jpeg, webp, avif
- Scaled image export via
svg_to_png_with_sizeand equivalent functions - Web-based JSON editor for interactive chart configuration and testing
Add charts-rs to your Cargo.toml:
[dependencies]
charts-rs = "0.7"SVG output works with the default build. Raster export (png, jpeg, webp,
avif) — the svg_to_png, svg_to_png_with_size, and related functions used
below — requires the image-encoder feature:
[dependencies]
charts-rs = { version = "0.7", features = ["image-encoder"] }You can try to use the web demo page, it's simple and useful.
Charts Web Demo Page: https://charts.npmtrend.com/
Charts Web Source: https://github.com/vicanso/charts-rs-web
Runnable examples live in examples/; each writes an svg file:
cargo run --example bar # basic bar chart
cargo run --example line # smooth line with area fill and mark line / points
cargo run --example pie # nightingale (rose) chart
cargo run --example sunburst # sunburst with label formatter, ring thickness, animation
cargo run --example sankey # sankey flow diagram (nodes auto-derived from links)
cargo run --example tree # node-link tree with curved links (LR layout)use charts_rs::{
BarChart, Box, SeriesCategory, THEME_GRAFANA
};
let mut bar_chart = BarChart::new_with_theme(
vec![
("Evaporation", vec![2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6]).into(),
(
"Precipitation",
vec![2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6],
)
.into(),
("Temperature", vec![2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3]).into(),
],
vec![
"Mon".to_string(),
"Tue".to_string(),
"Wed".to_string(),
"Thu".to_string(),
"Fri".to_string(),
"Sat".to_string(),
"Sun".to_string(),
],
THEME_GRAFANA,
);
bar_chart.title_text = "Mixed Line and Bar".to_string();
bar_chart.legend_margin = Some(Box {
top: bar_chart.title_height,
bottom: 5.0,
..Default::default()
});
bar_chart.series_list[2].category = Some(SeriesCategory::Line);
bar_chart.series_list[2].y_axis_index = 1;
bar_chart.series_list[2].label_show = true;
bar_chart
.y_axis_configs
.push(bar_chart.y_axis_configs[0].clone());
bar_chart.y_axis_configs[0].axis_formatter = Some("{c} ml".to_string());
bar_chart.y_axis_configs[1].axis_formatter = Some("{c} °C".to_string());
println!("{}", &bar_chart.svg().unwrap());
svg_to_png(&bar_chart.svg().unwrap()).unwrap();use charts_rs::{BarChart, svg_to_png};
let bar_chart = BarChart::from_json(
r###"{
"width": 630,
"height": 410,
"margin": {
"left": 10,
"top": 5,
"right": 10
},
"title_text": "Bar Chart",
"title_font_color": "#345",
"title_align": "right",
"sub_title_text": "demo",
"legend_align": "left",
"series_list": [
{
"name": "Email",
"label_show": true,
"data": [120.0, 132.0, 101.0, 134.0, 90.0, 230.0, 210.0]
},
{
"name": "Union Ads",
"data": [220.0, 182.0, 191.0, 234.0, 290.0, 330.0, 310.0]
}
],
"x_axis_data": [
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"Sun"
]
}"###,
).unwrap();
println!("{}", bar_chart.svg().unwrap());
svg_to_png(&bar_chart.svg().unwrap()).unwrap();use charts_rs::{BarChart, svg_to_png_with_size};
let chart = BarChart::from_json(r###"{ ... }"###).unwrap();
let svg = chart.svg().unwrap();
// Scale to exactly 800×400
let png = svg_to_png_with_size(&svg, Some(800), Some(400)).unwrap();
// Scale to width 800, preserve aspect ratio
let png = svg_to_png_with_size(&svg, Some(800), None).unwrap();Use null in JSON arrays to represent missing data; the chart skips rendering for those positions.
{
"series_list": [{
"name": "Sales",
"data": [120.0, null, 101.0, null, 90.0]
}]
}In Rust, build the series with Option<f32> values (None is a missing point):
use charts_rs::Series;
let series = Series::new_nullable(
"Sales".to_string(),
vec![Some(120.0), None, Some(101.0), None, Some(90.0)],
);
// or via the tuple conversion
let series: Series = ("Sales", vec![Some(120.0), None, Some(101.0)]).into();The legacy NIL_VALUE sentinel (Series::new / Vec<f32>) still works and is treated as None.
Formatters are supported in series_label_formatter, axis_formatter, and value_formatter (GaugeChart).
| Placeholder | Meaning |
|---|---|
{c} |
Data value |
{a} |
Series name |
{b} |
Category (x-axis label) |
{d} |
Percentage (pie / funnel) |
{t} |
Thousands notation (1.2K, 5.6M) |
let buf = fs::read(file).unwrap();
add_fonts(&[&buf]).unwrap();This project is licensed under the Apache-2.0 license.

















