ggplot-rs
A Rust implementation of ggplot2's Grammar of Graphics, rendering through the plotters backend.
No polars required. polars is a convenient — and fully
optional — input adapter. The core pipeline runs on its own internal DataFrame,
so you can plot straight from plain Rust vectors, or from
Apache Arrow RecordBatches produced by
DuckDB — with polars switched off entirely. See
Data Input and Feature Flags.
Gallery
Every image below is produced by examples/gallery.rs —
regenerate them all with cargo run --example gallery.
Quick Start
use *;
use *;
Features
Geoms
geom_point, geom_line, geom_bar, geom_col, geom_histogram, geom_boxplot, geom_violin, geom_smooth, geom_density, geom_area, geom_ribbon, geom_errorbar, geom_segment, geom_rug, geom_text, geom_label, geom_tile, geom_raster, geom_bin2d, geom_hex, geom_contour, geom_contour_filled, geom_path, geom_step, geom_hline, geom_vline, geom_abline, and more (40+)
Stats
StatIdentity, StatCount, StatBin, StatBoxplot, StatSmooth (Lm + Loess), StatDensity, StatLoess, StatSummary, StatEcdf, StatFunction, StatEllipse, StatContour, StatBin2d, StatBinHex, StatSum, StatYDensity, StatQQ, StatSummary2d, StatQuantile (feature regression), and more
Scales
- Continuous: linear, log10, log2, ln, sqrt, reverse, logit, probit, pseudo-log, reciprocal, exp, and Box–Cox transforms
- Discrete: automatic categorical mapping
- Color: discrete palettes (Viridis, Brewer Set1/Dark2, etc.), continuous gradients, diverging gradient2, binned/stepped scales (
scale_color_steps/fermenter), manual color assignment - Shape & Linetype: discrete mapping for point shapes and line styles
Coordinates
coord_cartesian, coord_flip, coord_fixed, coord_polar, coord_trans
Faceting
facet_wrap and facet_grid with configurable free/fixed scales
Themes
theme_gray, theme_bw, theme_classic, theme_minimal, theme_dark, theme_light, theme_linedraw, theme_void — plus full customization via ElementText, ElementLine, ElementRect
Annotations
annotate_text, annotate_rect, annotate_segment
Axis label rotation
GGPlot::axis_text_x_angle(deg) / axis_text_y_angle(deg) rotate tick labels (R's guide_axis(angle = ...)), useful for long category labels. Call after any theme_*() preset.
Computed aesthetics
An aesthetic can map an expression over columns, not just a bare column name:
new
.aes
.geom_point;
Supports + - * / % ^, parentheses, and ln/log/log10/log2/sqrt/exp/abs/sin/cos/tan/floor/ceil/round/sign. A plain column name is used directly (so existing mappings are unchanged); anything else is parsed and evaluated per row. The same expressions work in after_stat mappings, plus aggregate functions (sum, mean, max, min, count, median, prod) that reduce over all rows — e.g. .after_stat_y("count / sum(count)") for proportion histograms.
Data Input
GGPlot::new accepts anything implementing the GGData trait. Nothing here
requires polars — pick whichever source fits your stack.
Plain Rust — zero optional dependencies:
// Column-oriented
let cols: = vec!;
new
// Row-oriented
let rows: = vec!;
new
Apache Arrow / DuckDB — feed a RecordBatch straight from a DuckDB query
result, with polars switched off:
# Cargo.toml — no polars in the dependency tree
= { = "0.1", = false, = ["arrow"] }
let batch: RecordBatch = /* DuckDB query → Arrow */;
new
polars (optional, enabled by default) — for df! and polars pipelines:
let df = df! ?;
new
Rendering
Save to a file (format inferred from the extension — svg, png, jpg, ...):
plot.save?; // 800x600 default
plot.save_with_size?;
plot.ggsave?; // width_in, height_in, dpi
Or render in memory — no temp files — which is what you want when serving charts from a web/MCP service:
let svg: String = plot.clone.render_svg?; // or render_svg_with_size(w, h)
let png: = plot.render_png_with_size?; // fully-encoded PNG bytes
Headless / no system fonts. Rendering uses plotters' ab_glyph text backend
with a bundled font (DejaVu Sans), not font-kit/fontconfig — so text renders
deterministically in a minimal container with no system fonts installed. Nothing
to configure; there is no dependency on the host's font stack.
Theming & brand color
Everything about a theme is set at runtime, so one render process can serve many tenants' brands without touching chart code.
Inject a brand/primary color — it becomes the default for any single-series
geom that has no color/fill aesthetic mapped (an explicit mapping always wins):
new
.aes
.geom_col
.primary_color // DataZoo teal — no per-chart color code
.render_svg?;
Build a whole Theme at runtime and compose the brand into it:
let theme = theme_minimal.with_primary;
new.aes.geom_line.theme;
Supply an arbitrary sequential ramp (e.g. a green→red risk score) instead of
the built-in viridis/brewer scales — pass explicit (offset, color) stops:
new
.aes
.geom_point
.scale_color_gradientn;
Feature Flags
| Feature | Default | Provides |
|---|---|---|
polars |
yes | impl GGData for polars::DataFrame + polars re-export |
arrow |
no | impl GGData for arrow::RecordBatch (Arrow/DuckDB input) |
regression |
no | stat_quantile/geom_quantile + geom_smooth glm/rlm via anofox-regression |
To skip the heavy polars dependency (e.g. an Arrow-only service), disable defaults:
= { = "0.1", = false, = ["arrow"] }
Examples
Run any example with:
Dependencies
- plotters 0.3 — SVG/PNG rendering (
ab_glyphtext backend; no fontconfig) - image 0.24 — in-memory PNG encoding
- indexmap 2 — ordered maps for internal data
- rand 0.8 — jitter positioning
- polars 0.46 — DataFrame input (optional, default)
- arrow 53 — Arrow
RecordBatchinput (optional)
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Bundled font
assets/fonts/DejaVuSans.ttf is bundled for headless text rendering. DejaVu Sans
is distributed under a permissive, freely-redistributable license (Bitstream Vera
- Arev) — see
assets/fonts/LICENSE-DejaVu.txt.