kuva CLI
kuva is the command-line front-end for the kuva plotting library. It reads tabular data from a TSV or CSV file (or stdin) and writes an SVG — or PNG/PDF with the right feature flag — to a file or stdout.
kuva <SUBCOMMAND> [FILE] [OPTIONS]
Installation
Step 1 — install Rust
If you don't have Rust installed, get it via rustup:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Follow the on-screen prompts (the defaults are fine). Then either restart your shell or run:
source ~/.cargo/env
Verify with cargo --version. You only need to do this once.
kuva itself only needs Rust 1.87. The one exception is PDF output: --features pdf/full pulls in krilla, which requires Rust >= 1.92. If rustup show reports an older version and you plan to use --features full or pdf, run rustup update first.
Step 2 — install kuva
From crates.io (recommended once a release is published):
cargo install kuva --features cli # SVG output
cargo install kuva --features cli,full # SVG + PNG + PDF
From a local clone (install to ~/.cargo/bin/ and put it on your $PATH):
git clone https://github.com/Psy-Fer/kuva && cd kuva
cargo install --path . --features cli # SVG output
cargo install --path . --features cli,full # SVG + PNG + PDF
After either method, kuva is available anywhere in your shell — no need to reference ./target/release/kuva or modify $PATH manually. Confirm with:
kuva --help
Building without installing
If you only want to build and run from the repo without installing:
cargo build --release --bin kuva --features cli,full
./target/release/kuva --help
Input
Every subcommand takes an optional positional FILE argument. If omitted or -, data is read from stdin.
# from file
kuva scatter data.tsv
# from stdin
cat data.tsv | kuva scatter
# explicit stdin
kuva scatter - < data.tsv
Delimiter detection
| Priority | Rule |
|---|---|
| 1 | --delimiter flag |
| 2 | File extension: .csv → ,, .tsv/.txt → tab |
| 3 | Sniff first line: whichever of tab or comma appears more often |
Header detection
The first row is treated as a header when either its first field fails to parse as a number, or some column holds a non-numeric label sitting atop an otherwise all-numeric column (so a leading numeric key column no longer hides the header, e.g. 5,data above 0,1 / 1,2).
Two flags override the auto-detection (they are mutually exclusive):
--header: force the first row to be a header even if it looks like data (useful for all-numeric column names such as years).--no-header: force the first row to be data even if it looks like a header.
Column selection
Columns are selected by 0-based integer index or header name:
kuva scatter data.tsv --x 0 --y 1 # by index
kuva scatter data.tsv --x time --y value # by name (requires header)
Parquet input
Every subcommand that reads tabular data also accepts .parquet files, not just scatter or any single subcommand: parquet support lives in the shared input layer every subcommand goes through, so it applies uniformly across all of them.
kuva scatter data.parquet --x x --y y -o plot.svg
cat data.parquet | kuva histogram --value-col value # also detected via stdin
Requires building with the parquet feature (cargo build --features cli,parquet, or cli,full,parquet for every backend). Without it, a .parquet file is read as plain text and will fail to parse.
Detection is automatic, no flag needed:
| Input | How it's detected |
|---|---|
| File path | .parquet extension (case-insensitive) |
| stdin | Magic bytes (PAR1 header) sniffed from the piped data |
Column selection (--x, --y, --value-col, etc.) works identically to CSV/TSV, by index or header name. Under the hood, only the requested columns are decoded from disk (a projected Arrow read), so memory and time scale with the columns you actually select rather than the full schema, useful for wide parquet files with many unused columns.
--header, --no-header, and --delimiter are ignored for parquet input (with a warning) since parquet is self-describing: it always carries its own schema and column names, so there's no header row to skip and no delimiter to guess.
Output
| Flag | Effect |
|---|---|
| (omitted) | SVG to stdout |
-o out.svg | SVG to file |
-o out.png | PNG (requires --features png) |
-o out.pdf | PDF (requires --features pdf; needs Rust >= 1.92 to build — higher than kuva's own MSRV, see Installation) |
Format is inferred from the file extension case-insensitively. Output paths must end in .svg, .png, or .pdf; other or missing extensions are rejected before input is read.
Shared flags
These flags are available on every subcommand.
Output & appearance
| Flag | Default | Description |
|---|---|---|
-o, --output <FILE> | stdout (SVG) | .svg, .png, or .pdf output path, case-insensitive (mutually exclusive with --terminal) |
--title <TEXT> | — | Title displayed above the chart |
--subtitle <TEXT> | — | Secondary line under the title, smaller and muted (Reference → Layout) |
--width <PX> | 800 | Canvas width in pixels |
--height <PX> | 500 | Canvas height in pixels |
--theme <NAME> | light | Theme: light, dark, solarized, minimal |
--palette <NAME> | category10 | Color palette for multi-series plots |
--cvd-palette <NAME> | — | Colour-vision-deficiency palette: deuteranopia, protanopia, tritanopia. Overrides --palette. |
--bw | off | Black & white / accessibility mode — replaces colors with grey shades, hatch patterns, dash styles, and marker shapes so the plot stays legible in greyscale |
--background <COLOR> | (theme default) | SVG background color (any CSS color string) |
Fonts
| Flag | Default | Description |
|---|---|---|
--embed-font | off | Embed DejaVu Sans directly in SVG output (mutually exclusive with --terminal) |
By default, SVG output references fonts by name and relies on the viewer to resolve them. This works fine in browsers and on any system where DejaVu Sans, Verdana, Liberation Sans, or Arial is installed. In environments with no system fonts — headless servers, containers, CI pipelines — text may be missing or fall back to an unexpected face.
--embed-font bakes DejaVu Sans as a base64 @font-face block into the SVG <style> element, making the file fully self-contained at the cost of roughly 1 MB of extra size. PNG and PDF output is unaffected: those backends always have the font available regardless of this flag.
# Self-contained SVG for use with rsvg-convert or similar tools in containers
kuva scatter data.tsv --x x --y y --embed-font -o plot.svg
# Pipe into rsvg-convert in a minimal container
kuva scatter data.tsv --x x --y y --embed-font | rsvg-convert -o plot.png
SVG interactivity
| Flag | Default | Description |
|---|---|---|
--interactive | off | Embed browser interactivity in SVG output (ignored for PNG/PDF/terminal) |
When --interactive is set the output SVG contains a self-contained <script> block with no external dependencies. Features:
- Hover tooltip — hovering a data point shows its label and value.
- Click to pin — click a point to keep its highlight; click again or press Escape to clear all pins.
- Search — type in the search box (top-left of the plot area) to dim non-matching points. Escape clears.
- Coordinate readout — mouse position inside the plot area is shown in data-space coordinates.
- Legend toggle — click a legend entry to show/hide that series.
- Save button — top-right button serialises the current SVG DOM (including any pinned/dimmed state). Note: the download is not yet functional.
Supported in this release: scatter, line, bar, strip, volcano. All other subcommands accept --interactive and load the UI chrome (coordinate readout, search box) but do not yet have per-point hover/search — full renderer coverage is planned for a future release.
kuva scatter data.tsv --x x --y y --color-by group --legend --interactive -o plot.svg
kuva volcano hits.tsv --gene gene --log2fc log2fc --pvalue pvalue --legend --interactive -o volcano.svg
Terminal output
| Flag | Default | Description |
|---|---|---|
--terminal | off | Render directly in the terminal using Unicode braille and block characters; mutually exclusive with -o |
--term-width <N> | (auto) | Terminal width in columns (overrides auto-detect) |
--term-height <N> | (auto) | Terminal height in rows (overrides auto-detect) |
Terminal output uses Unicode braille dots (U+2800–U+28FF) for scatter points and continuous curves, full-block characters (█) for bar and histogram fills, and ANSI 24-bit colour. Terminal dimensions are auto-detected from the current tty; pass --term-width and --term-height to override (useful in scripts or when piping).
# Scatter plot directly in terminal
kuva scatter data.tsv --x x --y y --terminal
# Explicit dimensions
kuva bar counts.tsv --label-col gene --value-col count --terminal --term-width 120 --term-height 40
# Manhattan plot on a remote server
cat gwas.tsv | kuva manhattan --chr-col chr --pvalue-col pvalue --terminal
Note: Terminal output is not yet supported for
upset. Runningkuva upset --terminalprints a message and exits cleanly; use-o file.svginstead.
Axes (most subcommands)
| Flag | Default | Description |
|---|---|---|
--x-label <TEXT> | — | X-axis label |
--y-label <TEXT> | — | Y-axis label |
--ticks <N> | 5 | Hint for number of tick marks |
--no-grid | off | Disable background grid |
Log scale (scatter, line, histogram, density, hist2d)
| Flag | Description |
|---|---|
--log-x | Logarithmic X axis |
--log-y | Logarithmic Y axis |
Date/time X axis (scatter, line)
| Flag | Default | Description |
|---|---|---|
--x-date-format <FMT> | — | Parse the X column as a date/time using this strftime-style format (e.g. %Y-%m-%d, %m/%d/%Y %H:%M) instead of a plain number. Formats with no time component parse as midnight UTC. |
--x-date-unit <UNIT> | auto | Tick spacing unit: years, months, weeks, days, hours, or minutes. Omit for auto mode, which inspects the data range and picks one. Ignored unless --x-date-format is set. |
--x-date-tick-format <FMT> | (per-unit default) | Tick label format, overriding the unit's default (see table below). Ignored in auto mode. |
--x-date-tick-step <N> | 1 | Draw one tick every N units instead of every 1. |
Default tick format per unit (used when --x-date-tick-format is omitted):
| Unit | Default format | Example |
|---|---|---|
years | %Y | 2024 |
months | %b %Y | Jan 2024 |
weeks | %b %d | Jan 15 |
days | %Y-%m-%d | 2024-01-15 |
hours | %H:%M | 14:30 |
minutes | %H:%M | 14:30 |
# Auto mode: format and unit picked from the data range
kuva line prices.tsv --x date --y close --x-date-format "%Y-%m-%d"
# Explicit unit and tick format
kuva scatter prices.tsv --x date --y close \
--x-date-format "%Y-%m-%d" --x-date-unit months --x-date-tick-format "%b %y"
# One tick every 2 weeks
kuva line prices.tsv --x date --y close \
--x-date-format "%Y-%m-%d" --x-date-unit weeks --x-date-tick-step 2
See Reference → Date & Time Axes for the underlying DateTimeAxis API.
Secondary Y axis (twin-y)
| Flag | Description |
|---|---|
--y2-label <TEXT> | Label for the secondary (right) Y axis |
--y2-min <F> | Fix the secondary Y axis lower bound; overrides auto-range |
--y2-max <F> | Fix the secondary Y axis upper bound; overrides auto-range |
--log-y2 | Log-scale the secondary Y axis |
--y2-tick-format <FORMAT> | Tick label format for the secondary Y axis: auto (default), int, sci, percent, or fixed:N |
Input
| Flag | Description |
|---|---|
--header | Force first row as a header (overrides auto-detection) |
--no-header | Treat first row as data, not a header |
-d, --delimiter <CHAR> | Override field delimiter |
Subcommands
All 57 subcommands, grouped the same way plot pages are grouped in the sidebar. Each link goes straight to that subcommand's CLI section at the bottom of its library-equivalent page, right next to the Rust API it wraps — so full per-flag documentation, usage examples, and the builder reference live together on one page instead of two.
Distributions
| Subcommand | Description |
|---|---|
| histogram | Frequency histogram from one or more numeric columns |
| hist2d | Two-dimensional histogram (density grid) from two numeric columns |
| density | Kernel density estimate curve |
| ridgeline | Stacked KDE density curves, one per group |
| ecdf | Empirical cumulative distribution function |
| Q-Q (quantile-quantile) plot | |
| box | Box-and-whisker plot |
| violin | Kernel-density violin plot |
| strip | Strip / jitter plot |
| raincloud | Half-violin KDE cloud, box, and jittered points combined |
| hexbin | Hexagonal-bin density plot from two numeric columns |
| heatmap | Color-encoded matrix heatmap |
Relationships & correlation
| Subcommand | Description |
|---|---|
| scatter | Scatter plot of (x, y) point pairs |
| line | Line plot |
| contour | Contour plot from scattered (x, y, z) triplets |
| parallel | Parallel coordinates, one axis per variable |
| polar | Polar coordinate scatter/line plot |
| ternary | Ternary (simplex) scatter plot |
| quiver | 2-D vector field rendered as arrows |
Categorical & comparison
| Subcommand | Description |
|---|---|
| bar | Bar chart from label/value pairs |
| pie | Pie or donut chart |
| waffle | Proportional grid of filled cells |
| funnel | Stage-by-stage attrition funnel |
| pareto | Bars sorted descending, plus a cumulative-percentage line |
| pyramid | Population pyramid (back-to-back horizontal bars) |
| lollipop | Dot-and-stem alternative to bar charts |
| slope | Paired before/after comparisons |
| dot | Dot plot (size + color at categorical positions) |
| mosaic | Mosaic / Marimekko two-way contingency table |
| venn | Venn diagram, 2 to 4 overlapping sets |
| upset | UpSet plot for set-intersection analysis |
| radar | Radar / spider chart |
| rose | Nightingale rose (coxcomb) chart |
Time series
| Subcommand | Description |
|---|---|
| stacked-area | Stacked area chart |
| streamgraph | Flowing stacked area with a displaced baseline |
| candlestick | OHLC candlestick chart |
| waterfall | Running total built from incremental bars |
| horizon | Folded stacked time series for many series in limited height |
| calendar | GitHub-style daily contribution grid |
| gantt | Task bars with milestones and a "now" line |
| bump | Rank changes over time |
Statistical & model evaluation
| Subcommand | Description |
|---|---|
| roc | ROC curve for binary classifiers |
| pr | Precision-recall curve |
| survival | Kaplan-Meier survival curve |
| forest | Point estimates with confidence intervals |
Hierarchical & network
| Subcommand | Description |
|---|---|
| treemap | Tile a rectangle proportionally to values |
| sunburst | Radial hierarchy chart |
| network | Graph diagram from an edge list or adjacency matrix |
| sankey | Sankey / alluvial flow diagram |
| chord | Chord diagram for pairwise flow data |
| phylo | Phylogenetic tree from a Newick string or edge-list |
Genomics & bioinformatics
| Subcommand | Description |
|---|---|
| manhattan | Manhattan plot for GWAS results |
| volcano | Volcano plot for differential expression |
| synteny | Genomic alignment ribbon plot |
3D
| Subcommand | Description |
|---|---|
| scatter3d | 3D scatter plot with orthographic projection |
| surface3d | 3D surface mesh with depth-sorted rendering |
Composite & Utility
| Subcommand | Description |
|---|---|
| twin-y | Two series sharing an x-axis with independent primary/secondary y-scales |
Tips
Pipe to a viewer:
kuva scatter data.tsv | display # ImageMagick
kuva scatter data.tsv | inkscape --pipe # Inkscape
Quick PNG without a file:
kuva scatter data.tsv -o /tmp/out.png # requires --features png
Themed dark output:
kuva manhattan gwas.tsv --chr-col chr --pvalue-col pvalue \
--theme dark --background "#1a1a2e" -o manhattan_dark.svg
Colour-vision-deficiency palette:
kuva scatter data.tsv --x time --y value --color-by group \
--cvd-palette deuteranopia