Beautiful terminal charts using only the Python standard library.
termplotx renders crisp charts directly in your terminal — no matplotlib, no
browser, zero required dependencies. It's built for ML engineers, data
scientists, and DevOps folks who live in SSH sessions, CI logs, Jupyter
terminals, or just want a quick plot without leaving the shell.
Note on the name: the import name and the install name are both
termplotx(the shortertermplotwas already taken on PyPI).
200 ┤ ╭───╮
│ ╭───╯ ╰╮
145 ┤ ╭──────╯ ╰────
│╭──╯
90 ┤╯
└────────────────────────
Jan Mar May
- 📈 Sparklines — inline mini charts for metrics:
▂▅▃▇▁▆ - 📊 Line charts — single and multi-series, high-res braille rendering
- 📊 Bar charts — horizontal and vertical
- 📉 Histograms — auto or fixed bins (NumPy-accelerated if installed)
- ✨ Scatter plots — braille sub-pixel resolution
- 🔥 Heatmaps — truecolor or shade-glyph fallback
- ⏱️ Live charts — update in place with ANSI escapes
- 🎨 Themes —
dark,light,neon,minimal - 📐 Responsive — auto-detects terminal width/height
- 🪟 Cross-platform — Linux, macOS, Windows (auto-enables ANSI)
- 🧩 Typed — ships
py.typed, great Pylance/mypy experience
- Install
- Quick start
- Charts
- Themes & color
- Loading data
- Command-line interface
- How it adapts to your terminal
- API reference
- Optional dependencies
- FAQ
- Development
- License
pip install termplotxOptional extras:
pip install "termplotx[numpy]" # faster histogram binning
pip install "termplotx[windows]" # colorama for older Windows consoles
pip install "termplotx[all]" # everything optionaltermplotx requires Python 3.9+ and has no required dependencies.
import termplotx as tp
# A sparkline for a row of metrics
print(tp.sparkline([1, 5, 3, 9, 2, 7, 4, 8]))
# A line chart
import math
print(tp.line([math.sin(i / 5) for i in range(60)], title="sine wave"))
# A bar chart
print(tp.bar([120, 150, 90, 170, 200], labels=["Jan", "Feb", "Mar", "Apr", "May"]))Every function returns a plain string, so you can print it, log it, write
it to a file, put it in an f-string, or embed it in a TUI.
Compact, one-line charts — perfect for dashboards, log lines, and metrics.
tp.sparkline([1, 5, 3, 9, 2, 7]) # ▁▅▃█▂▆
tp.sparkline(values, width=20) # resample to 20 chars
tp.sparkline(values, min=0, max=100) # fixed scale
tp.sparkline(values, theme="neon") # colored# Single series
print(tp.line(values, title="latency (ms)", width=70, height=15))
# Multiple series with a legend
print(tp.line(
[series_a, series_b],
labels=["train", "val"],
title="loss",
))
# Custom x-axis and fixed y-range
print(tp.line(y, x=timestamps, y_min=0, y_max=1)) loss
0.9996 ┤⡠⠊⠉⠒⠤⡀ ⢀⠔⠊⠉⠒⡄
│⡜ ⠈⢆ ⡠⠃ ⠱⡀
-2.08e-4 ┤ ⠘⡄ ⡎ ⢣
-1 ┤ ⠉ ⠈
└────────────────────────
0 29.5 59
■ train ■ val
# Horizontal (default)
print(tp.bar([3, 7, 2, 9], labels=["a", "b", "c", "d"]))
print(tp.barh(values, labels)) # explicit
# Vertical (columns)
print(tp.barv([3, 7, 2, 9, 5], labels=["a", "b", "c", "d", "e"], height=8))
# Or dispatch by keyword
print(tp.bar(values, labels, orientation="vertical")) a ████████ 3
bb ██████████████████▋ 7
ccc █████▍ 2
d ████████████████████████ 9
print(tp.histogram(samples)) # automatic bin count
print(tp.histogram(samples, bins=20)) # fixed bins[-2.84, -2.15) █▋ 3
[-2.15, -1.46) ███▏ 6
[-1.46, -0.77) ███████████████▊ 30
[-0.77, -0.08) ███████████████████████▋ 45
[-0.08, 0.61) ██████████████████████████████ 57
Install the numpy extra for faster binning on large arrays — the output is
identical either way.
print(tp.scatter(xs, ys, title="x vs y", width=60, height=20))matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(tp.heatmap(matrix, row_labels=["r1", "r2", "r3"], col_labels=["a", "b", "c"]))With color it paints each cell with a gradient background; without color it
falls back to shade glyphs ░▒▓█.
Update a chart in place without scrolling the terminal:
import random, time
import termplotx as tp
window = []
with tp.LiveChart() as chart:
for _ in range(100):
window.append(random.random())
window = window[-60:]
chart.update(tp.sparkline(window, min=0, max=1, width=60))
time.sleep(0.1)Or use the convenience loop:
tp.live(lambda: tp.sparkline(next_window()), frames=200, interval=0.1)Four built-in themes: dark (default), light, neon, minimal.
tp.line(values, theme="neon")
tp.bar(values, labels, theme="light")Color is auto-detected from the output stream. You can force it:
tp.sparkline(values, color=True) # force on
tp.sparkline(values, color=False) # force off (e.g. for log files)termplotx honors the NO_COLOR and FORCE_COLOR
environment variables.
termplotx reads many formats out of the box via tp.load:
table = tp.load("data.csv") # CSV (header auto-detected)
table = tp.load("data.tsv") # TSV
table = tp.load("data.json") # list / list-of-lists / list-of-dicts / dict-of-lists
table = tp.load("data.txt") # whitespace/newline-separated numbers
table = tp.load("-") # read from stdin
# Columns by name or index
prices = table.column_floats("price")
first = table.column_floats(0)
print(tp.line(prices, title="price"))# Inline numbers
termplotx sparkline 1 5 3 9 2 7
# From files (column by name or index)
termplotx line data.csv --column price --title "Price"
termplotx bar data.csv --label name --column score
termplotx hist data.csv -c value --bins 20
termplotx scatter data.csv --x lon --y lat
termplotx heatmap matrix.csv
# Auto-detect a sensible chart from the data shape
termplotx plot data.csv
# Pipe data in
cat metrics.txt | termplotx sparkline -
psql -c "..." | termplotx line -Common flags: --theme, --color / --no-color, --ascii, --width,
--height, --title, --column/-c (repeatable), --format.
Run termplotx <command> --help for the full list.
- Width/height are auto-detected (
shutil.get_terminal_size) and respectCOLUMNS/LINES; passwidth=/height=to override. - Color is emitted only when the output is an interactive TTY (so piped or redirected output stays clean), unless you force it.
- Unicode glyphs are used when the stream can encode them; otherwise charts
fall back to ASCII automatically. Force ASCII with
unicode=Falseor theTERMPLOT_ASCII=1environment variable. - Windows: ANSI is enabled automatically via colorama (if installed) or a built-in ctypes fallback — nothing to configure.
| Function | Description |
|---|---|
sparkline(data, *, width, min, max, color, theme, unicode) |
One-line sparkline |
line(data, x=None, *, labels, width, height, title, y_min, y_max, ...) |
Line chart (1D or list of series) |
bar(values, labels=None, *, orientation="horizontal", ...) |
Bar chart dispatcher |
barh(values, labels=None, *, width, show_values, ...) |
Horizontal bars |
barv(values, labels=None, *, height, bar_width, gap, ...) |
Vertical bars |
histogram(data, bins=None, *, width, show_counts, ...) |
Histogram |
scatter(x, y, *, width, height, title, ...) |
Scatter plot |
heatmap(matrix, *, row_labels, col_labels, cell_width, ...) |
2D heatmap |
LiveChart(stream=None, *, hide_cursor=True) |
Context manager for in-place updates |
live(render, *, frames=None, interval=0.2) |
Convenience live loop |
load(path, *, fmt=None) |
Load CSV/TSV/JSON/TXT/stdin into a Table |
THEMES, get_theme(name) |
Theme registry |
terminal_size(), supports_color(), supports_unicode() |
Terminal helpers |
All chart functions return str.
| Extra | Installs | Enables |
|---|---|---|
numpy |
numpy | Faster histogram binning |
windows |
colorama | ANSI on older Windows consoles |
all |
numpy + colorama | Everything optional |
dev |
pytest, build, twine, … | Development & release |
None are required — the core is pure standard library.
Why is there no color in my logs / CI output?
That's intentional — color is disabled for non-TTY streams so files and CI logs
stay clean. Use color=True (or FORCE_COLOR=1) to force it.
I see ? boxes / garbled characters.
Your terminal can't render the Unicode glyphs. Pass unicode=False or set
TERMPLOT_ASCII=1 for ASCII-only output.
Does it work in Jupyter? Yes — in a terminal-attached kernel. Printed strings show up fine; truecolor depends on the front-end.
git clone https://github.com/amanmukati09/termplot
cd termplot
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # macOS/Linux
pip install -e ".[dev]"
pytestSee INSTRUCTIONS.md for the complete build-and-publish
walkthrough.
MIT © 2026 Aman Mukati