aeh.
A small Python utility for plotting streams of numbers as ASCII histograms — in pipes, in notebooks, in logs.
aeh grew out of the habit of staring at log files and wishing
the distribution of latencies were in front of you, right there, in the
same terminal, without leaving for a notebook. It is not a plotting library.
It is a histogram drawer.
Installation
# from PyPI
pip install aeh
# or for the impatient — single-file, vendorable
curl -O https://aeh.mectest.ru/dl/aeh.py
From the shell
The CLI reads one number per line on stdin and prints a histogram:
$ awk '{print $7}' nginx.log | aeh --bins 20 count: 41,283 min: 0.4 max: 12.1 mean: 1.83 p50: 1.4 p99: 7.8 0.4 ┤▏ 12 0.9 ┤█▌ 1,484 1.4 ┤████████████████▎ 18,221 1.9 ┤█████████▎ 10,388 2.4 ┤████▎ 4,761 2.9 ┤██▏ 2,401 3.4 ┤█▏ 1,210 3.9 ┤▌ 612 4.4 ┤▎ 387 4.9 ┤▎ 281 5.4 ┤▏ 187 5.9 ┤▏ 142 6.4 ┤▏ 96 6.9 ┤▏ 78 7.4 ┤▏ 62 7.9 ┤▏ 41 8.4 ┤▏ 28 8.9 ┤ 18 9.4 ┤ 9 9.9 ┤ 6 10.4+ → 60 (clipped)
The output is plain UTF-8 — works in tmux, journald, less, pagers, copy-paste into a Slack message. No images, no escape sequences, no colour.
From Python
from aeh import histogram
durations = [r.duration_ms for r in records]
print(histogram(durations, bins=20, width=60))
The function returns a multi-line string. It does not write to stdout, does not touch any global state, and does not raise on empty input — empty input yields an empty string. The intent is to be quietly composable.
Logarithmic axis
print(histogram(durations, bins=30, scale="log"))
Switches to log10(1 + x) binning. Useful when the long tail of
your distribution is, well, long.
Reference
| argument | default | notes |
|---|---|---|
| bins | 20 | or pass a list of edges |
| width | auto | terminal width minus margins |
| scale | "linear" | "linear" / "log" |
| clip | 0.999 | quantile beyond which to collapse |
| stats | True | print the count / min / max header |
Why
Because matplotlib over SSH is silly. Because histogram(xs)
is the question I ask of a sequence of numbers an unreasonable number of times
per day. Because everything else either wants a notebook, or wants to be a
"unified data visualisation framework", and neither of those is what fits in a
pipe.
Changelog
- 2.1.0 — Unicode bar glyphs at quarter resolution (▏▎▍▌▋▊▉█).
- 2.0.0 — clip parameter; emptied input returns "". Breaking.
- 1.4 — log scale.
- 1.0 — first usable version.