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

PriorityRule
1--delimiter flag
2File extension: .csv,, .tsv/.txt → tab
3Sniff 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:

InputHow it's detected
File path.parquet extension (case-insensitive)
stdinMagic 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

FlagEffect
(omitted)SVG to stdout
-o out.svgSVG to file
-o out.pngPNG (requires --features png)
-o out.pdfPDF (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

FlagDefaultDescription
-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>800Canvas width in pixels
--height <PX>500Canvas height in pixels
--theme <NAME>lightTheme: light, dark, solarized, minimal
--palette <NAME>category10Color palette for multi-series plots
--cvd-palette <NAME>Colour-vision-deficiency palette: deuteranopia, protanopia, tritanopia. Overrides --palette.
--bwoffBlack & 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

FlagDefaultDescription
--embed-fontoffEmbed 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

FlagDefaultDescription
--interactiveoffEmbed 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

FlagDefaultDescription
--terminaloffRender 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. Running kuva upset --terminal prints a message and exits cleanly; use -o file.svg instead.

Axes (most subcommands)

FlagDefaultDescription
--x-label <TEXT>X-axis label
--y-label <TEXT>Y-axis label
--ticks <N>5Hint for number of tick marks
--no-gridoffDisable background grid

Log scale (scatter, line, histogram, density, hist2d)

FlagDescription
--log-xLogarithmic X axis
--log-yLogarithmic Y axis

Date/time X axis (scatter, line)

FlagDefaultDescription
--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>autoTick 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>1Draw one tick every N units instead of every 1.

Default tick format per unit (used when --x-date-tick-format is omitted):

UnitDefault formatExample
years%Y2024
months%b %YJan 2024
weeks%b %dJan 15
days%Y-%m-%d2024-01-15
hours%H:%M14:30
minutes%H:%M14: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)

FlagDescription
--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-y2Log-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

FlagDescription
--headerForce first row as a header (overrides auto-detection)
--no-headerTreat 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

SubcommandDescription
histogramFrequency histogram from one or more numeric columns
hist2dTwo-dimensional histogram (density grid) from two numeric columns
densityKernel density estimate curve
ridgelineStacked KDE density curves, one per group
ecdfEmpirical cumulative distribution function
qqQ-Q (quantile-quantile) plot
boxBox-and-whisker plot
violinKernel-density violin plot
stripStrip / jitter plot
raincloudHalf-violin KDE cloud, box, and jittered points combined
hexbinHexagonal-bin density plot from two numeric columns
heatmapColor-encoded matrix heatmap

Relationships & correlation

SubcommandDescription
scatterScatter plot of (x, y) point pairs
lineLine plot
contourContour plot from scattered (x, y, z) triplets
parallelParallel coordinates, one axis per variable
polarPolar coordinate scatter/line plot
ternaryTernary (simplex) scatter plot
quiver2-D vector field rendered as arrows

Categorical & comparison

SubcommandDescription
barBar chart from label/value pairs
piePie or donut chart
waffleProportional grid of filled cells
funnelStage-by-stage attrition funnel
paretoBars sorted descending, plus a cumulative-percentage line
pyramidPopulation pyramid (back-to-back horizontal bars)
lollipopDot-and-stem alternative to bar charts
slopePaired before/after comparisons
dotDot plot (size + color at categorical positions)
mosaicMosaic / Marimekko two-way contingency table
vennVenn diagram, 2 to 4 overlapping sets
upsetUpSet plot for set-intersection analysis
radarRadar / spider chart
roseNightingale rose (coxcomb) chart

Time series

SubcommandDescription
stacked-areaStacked area chart
streamgraphFlowing stacked area with a displaced baseline
candlestickOHLC candlestick chart
waterfallRunning total built from incremental bars
horizonFolded stacked time series for many series in limited height
calendarGitHub-style daily contribution grid
ganttTask bars with milestones and a "now" line
bumpRank changes over time

Statistical & model evaluation

SubcommandDescription
rocROC curve for binary classifiers
prPrecision-recall curve
survivalKaplan-Meier survival curve
forestPoint estimates with confidence intervals

Hierarchical & network

SubcommandDescription
treemapTile a rectangle proportionally to values
sunburstRadial hierarchy chart
networkGraph diagram from an edge list or adjacency matrix
sankeySankey / alluvial flow diagram
chordChord diagram for pairwise flow data
phyloPhylogenetic tree from a Newick string or edge-list

Genomics & bioinformatics

SubcommandDescription
manhattanManhattan plot for GWAS results
volcanoVolcano plot for differential expression
syntenyGenomic alignment ribbon plot

3D

SubcommandDescription
scatter3d3D scatter plot with orthographic projection
surface3d3D surface mesh with depth-sorted rendering

Composite & Utility

SubcommandDescription
twin-yTwo 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