malevich 0.7.0

Terminal plotting: a small grammar of marks, honest axes, millions of points
Documentation

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!("{}", malevich::line(&[1.0, 5.0, 2.0, 8.0][..]));
8 ┤                         ⡠⠊
  │                       ⡠⠊
  │       ⣀⠤⠒⠤⣀        ⢀⠔⠉
4 ┤    ⡠⠔⠊     ⠉⠒⠤⣀  ⢀⠔⠁
  │⢀⡠⠔⠉            ⠉⠒⠁
0 ┤⠁
  └┬────────┬───────┬────────┬
   0        1       2        3
println!("{}", malevich::bar(["mon", "tue", "wed", "thu", "fri"], &[3.0, 7.0, 4.5, 8.0, 6.0][..]));
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; NaN is 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.