Skip to content

Latest commit

 

History

History
200 lines (166 loc) · 8.66 KB

README.md

File metadata and controls

200 lines (166 loc) · 8.66 KB

kaz

Pipe data to an honest terminal plot. A stdin-first CLI over malevich. The first look at any data, drawn in the shell. Every chart, explained and illustrated, is at shergin.github.io/malevich.

cat loss.tsv | kaz line -t training
awk '{print $5}' access.log | kaz hist
cut -f2 species.tsv | kaz count

The plot goes to stderr by default, so stdout stays the data. -O echoes the input through, so the plot can sit in the middle of a pipeline without breaking it:

cat data.tsv | kaz line -O | next-tool     # plot on stderr, data flows on
                        sine
20 ┤      ⡠⠤⠒⠉⠉⠉⠉⠉⠒⠤⣀
   │   ⡠⠔⠊           ⠉⠢⡀
   │ ⠔⠊                ⠈⠢⢄                       ⢀⡠⠊
10 ┤                      ⠑⠤⡀                  ⢀⠔⠁
   │                        ⠈⠢⢄⡀            ⢀⠤⠒⠁
   │                           ⠈⠢⣀⡀     ⢀⡠⠔⠊⠁
 0 ┤                              ⠈⠉⠉⠒⠉⠉⠁
   └┬───────────┬───────────┬──────────┬───────────┬
    0          10          20         30          40

count tallies bare labels, so sort | uniq -c is unnecessary:

awk '{print $9}' access.log | kaz count -t 'status codes'
              status codes
5 ┤  ███████
  │  ███████  ▁▁▁▁▁▁
  │  ███████  ██████
  │  ███████  ██████  ▂▂▂▂▂▂▂  ▂▂▂▂▂▂
0 ┤  ███████  ██████  ███████  ██████
  └─────────────────────────────────────
       200      404      301     500

Install

brew install shergin/tap/kaz     # Homebrew (builds from source)
cargo install malevich-cli       # or via cargo

The Homebrew formula (homebrew/kaz.rb) also installs the completions and the man page. Shell completions (bash, zsh, fish) live in completions/, and the man page is man/kaz.1. To wire them up by hand:

cp completions/kaz.fish ~/.config/fish/completions/   # fish
source completions/kaz.bash                            # bash
man ./man/kaz.1

Charts

Command Alias What Input shape
line l line chart, one line per series y | xy | xyy | xyxy | yx
scatter s scatter plot xy | xyy
bar b one bar per label (--horizontal, --stack, --group) label value | label v1 v2 …
hist — histogram (--bins N to fix the count; --normalize, --cumulative) columns of numbers
count c value frequencies as bars one column of labels
density d kernel density estimate columns of numbers
ecdf — empirical cumulative distribution columns of numbers
box — a box plot per column columns are groups
violin — a violin plot per column columns are groups
hist2d — 2D histogram (density grid) xy
heatmap — shade a row-major matrix rows of numbers
spark — sparkline: bars from zero, no axes, one row tall columns of numbers
describe — summary statistics per column columns are groups
table — the numbers as an aligned table rows of numbers
spec — render a serialized malevich document JSON
caps — what detection sees for this terminal —

No other CLI plotter ships ecdf, violin, or hist2d.

Input

Fields split on any run of whitespace by default, so bare numbers, TSV, and column-style output all come through. -d CHAR sets one explicit separator (-d, for CSV-shaped data). -H reads a header row and uses its names to label the series.

--fmt says how the columns sit on the axes:

  • y — each column is a y-series over its row index (default: one column)
  • xy — first column x, second column y
  • xyy — first column x, every remaining column a series (default: 2+ columns)
  • xyxy — columns pair up: (x0,y0) (x1,y1) …
  • yx — first column y, second column x (YouPlot compatibility)

A field that will not parse becomes an honest gap in the plot. A one-line tally (3 values could not be parsed) goes to stderr afterward, and -q silences it. This parses fields, not CSV. For quotes and embedded delimiters, shape the data upstream (xsv select …, mlr --c2t …) and pipe the result in.

Options

-o TARGET      plot destination: stderr (default), - for stdout, or a FILE
-O             pass input through to stdout (mid-pipeline mode)
-d CHAR        field separator (default: any run of whitespace)
-H             first row is a header; its names label the series
--fmt FMT      column mapping: y | xy | xyy | xyxy | yx
-w N, -h N     frame width and height in cells (0..4096; max 4194304 cells)
-t TITLE       plot title
--xlabel TEXT  --ylabel TEXT
--xlim A,B     --ylim A,B         fix an axis range
--log-x  --log-y
--time-x       read the x column as time (unix seconds or ISO 8601)
--bins N       histogram bin count (hist; 1..1000000; default: automatic)
--binwidth W   histogram bin width (exclusive with --bins)
--horizontal   bar: sideways
--stack        bar: stack the value columns of `label v1 v2 …` rows
--group        bar: group them side by side within each band
--unit U       label the value axis: an SI unit, bytes, or a suffix such as %
--hline V      horizontal reference line (repeatable)
--vline V      vertical reference line (repeatable)
--normalize N  histogram heights: count (default) | probability | percent | density
--cumulative   accumulate histogram bins left to right
--cols LIST    select/reorder columns: header names (with -H) or 0-based indices
--by COL       scatter: color points by this column's categories
--colormap M   heatmap/hist2d: viridis | magma | cividis | greys | red-blue | purple-orange
--midpoint V   center the colormap on a value (signed data)
--log-color    logarithmic colormap (decades share equal color steps)
--labels-x A,B band labels across heatmap columns
--labels-y A,B band labels down heatmap rows, top to bottom
--reduce R     dense-heatmap bucket summary: mean | max | min | median
--emit-code    print the equivalent malevich Rust program, data inlined
--color WHEN   auto | always | never
--charset SET  auto | ascii | half | quad | sextant | braille | octant
--pixels WHEN  auto | always | never   — sixel/kitty/iTerm2 image panel from a pipe
-q             suppress the unparsed-values tally
--version      --help

Color follows the destination stream. The glyph tier defaults to quadrants in UTF-8, and to ASCII for a non-UTF-8 locale. Use --charset or MALEVICH_CHARSET to opt into a denser tier your font supports. Where the terminal speaks a pixel protocol, the plot panel becomes a real image, even mid-pipeline. MALEVICH_GRAPHICS=kitty|sixel|iterm2|none names the protocol when the sniff cannot. -h is height. Help is --help only.

--emit-code is the way out of the shell. Once the piped chart looks right, it prints the equivalent malevich Rust program: the same calls, your parsed data inlined as literals, ready to paste into a project:

kaz scatter penguins.tsv -H --by species --emit-code > plot.rs

Live

--live reads stdin forever, one value per line, and repaints a sliding line in place. There is no alt-screen, so the final frame stays in your scrollback, and Ctrl-C restores the cursor. Each repaint is one synchronized-output frame. When the plot's destination is not a terminal (2>log), the frames append as plain text and no escape byte is written. Line only.

ping -i.2 host | grep -oE 'time=[0-9.]+' | tr -d 'time=' | kaz line --live -t ping
vmstat 1 | awk 'NR>2{print $1}' | kaz line --live -t runnable

--window N sets the window length (1..1000000). --fps N sets the repaint rate (1..1000; default 10). --rate plots the per-interval delta of a monotonic counter.

If a live plot looks frozen, the producer is buffering. Pipes hold output until a block fills. Unbuffer at the source: stdbuf -oL producer, grep --line-buffered, or awk '{print; fflush()}'.

Design

kaz contains zero rendering logic. It parses arguments, frames stdin, and calls the public malevich API. Every flag names an existing library concept: a frame field, a preset argument, a scale option, or plot furniture. It is the proof of the library's central claim, that a pure string-renderer is enough.

License

MIT or Apache-2.0, matching malevich.