malevich
Terminal plotting for Rust: a small grammar of marks, honest axes, millions of points.
Eight marks. A real statistics layer. Ten million points in 28 milliseconds. Axes
placed by the same algorithm the visualization literature settled on — with labels
that are exact decimals, never 0.30000000000000004. All of it in plain values that
render to a String, degrade gracefully on any terminal, and never touch global
state.
println!;
8 ┤ ⡠⠊
│ ⡠⠊
│ ⣀⠤⠒⠤⣀ ⢀⠔⠉
4 ┤ ⡠⠔⠊ ⠉⠒⠤⣀ ⢀⠔⠁
│⢀⡠⠔⠉ ⠉⠒⠁
0 ┤⠁
└┬────────┬───────┬────────┬
0 1 2 3
println!;
8 ┤ ▁▁▁▁▁ █████
│ █████ █████ ▃▃▃▃▃
│ █████ █████ █████
4 ┤ █████ █████ █████ █████
│ ▆▆▆▆▆ █████ █████ █████ █████
│ █████ █████ █████ █████ █████
0 ┤ █████ █████ █████ █████ █████
└─────────────────────────────────────
mon tue wed thu fri
And the charts no other terminal library ships — box plots, violins, densities, 2D histograms:
three groups, summarized (synthetic)
8 ┤ ⠉⠉⢹⠉⠉
│ ⣀⣀⣀⣀⣀ ⢰⣶⣶⣶⣾⣶⣶⣶⡆ ⣀⣀⣀⣀⣀
│ ⡇ ⠘━━━━━━━━ ⢸
6 ┤ ⢀⣀⣀⣀⣇⣀⣀⣀ ⠒⠒⠚⠒⠒ ⢸
│ ⢸⣿⣿⣿⣿⣿⣿⣿ ⣀⣀⣀⣸⣀⣀⣀⡀
│ ━━━━━━━━━ ⣿⣿⣿⣿⣿⣿⣿⡇
4 ┤ ⡇ ━━━━━━━━
│ ⠒⠒⠓⠒⠒ ⠛⠛⠛⢻⠛⠛⠛⠃
│ ⢸
2 ┤ ⢸
│ ⠒⠒⠚⠒⠒
0 ┤
└─────────────────────────────────────────────────────
alpha beta gamma
Every chart in these docs is real program output, spliced in by
cargo run --example regen_docs and verified in CI — never typed by hand. More in the
gallery: EXAMPLES.md, and cargo run --example showcase renders a
colored tour sized to your terminal.
Why malevich
- A small grammar, not a chart zoo. Eight marks (line, points, bars, area, cells,
range, rule, text) × a stats layer × shared scales compose into the whole basic
chart catalog. Every preset —
line,scatter,bar,hist,stairs,ecdf,heatmap,hist2d,density,box_plot,violin,error_bars— is proven bit-identical to its grammar expansion in tests. - The statistical set no terminal library has. Box plots with type-7 quartiles and Tukey whiskers, violins from a real KDE (Silverman bandwidth), ECDFs, error bars, 2D densities — the charts science and ML actually need.
- Millions of points, measured. Large line layers are aggregated by M4 —
min/max/first/last per raster column, provably pixel-identical to drawing every
point. Ten million points render end to end in ~28 ms single-threaded; a million
KDE samples take 23 ms (
cargo bench --bench render). Every aggregator is a mergeable monoid, so host-side parallelism and streaming are compositions, not features. - Axes that are actually good. Extended-Wilkinson tick placement (Talbot, Lin,
Hanrahan 2010), exact-decimal labels that parse back to their values, one shared SI
prefix per axis (
2.5M,100µ), log axes with superscript decades, calendar time axes with multi-scale labels (14:05,Aug 2,2027), typed axis specs (Scale::{Linear, Log, Time, Bands}), axis titles, band scales with fitted category labels, collision-aware layout that sheds furniture instead of failing. - Renders everywhere, honestly. Four charsets (braille, quadrants, half-blocks,
ASCII) and four color tiers (truecolor → 256 → 16 → plain) with honest downhill
quantization; piped output is automatically clean plain text; CJK labels stay
aligned;
NaNis always a visible gap, never interpolated away. - Live charts without a framework. A thread-shared sliding window plus an
in-place repaint handle (cursor up, erase down, one write): flicker-free streaming
that survives in scrollback and never takes over your terminal
(
cargo run --example live). - Plots are plain values.
Clone + Send + Sync, no globals, rendering is a pure function of plot and frame — build on one thread, render on another, snapshot-test the strings. Two tiny dependencies (terminal_size,unicode-width).
Pre-1.0: APIs break between releases while we make them right. The concept vocabulary is documented in TERMINOLOGY.md and changes are in the CHANGELOG.
What it will not be
Not a TUI framework (it never owns the terminal or handles input). No animations. No file parsing or dataframes in core — ingestion traits only. No config-object kitchen sink: if an option is not a mark channel, stat parameter, scale option, or theme entry, it does not ship.
Name
Kazimir Malevich painted a black square on a plain ground and meant it: a small vocabulary of geometric forms, composed deliberately. That is the design budget of this library.
Acknowledgements
malevich stands on the shoulders of giants — the algorithms, libraries, and grammars that taught this project what it knows are credited, specifically, in ACKNOWLEDGEMENTS.md.
License
MIT OR Apache-2.0.