Beautiful terminal charts using only the Python standard library
Project description
termplotx
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
Table of contents
- Install
- Quick start
- Charts
- Themes & color
- Loading data
- Command-line interface
- How it adapts to your terminal
- API reference
- Optional dependencies
- FAQ
- Development
- License
Install
pip install termplotx
Optional extras:
pip install "termplotx[numpy]" # faster histogram binning
pip install "termplotx[windows]" # colorama for older Windows consoles
pip install "termplotx[all]" # everything optional
termplotx requires Python 3.9+ and has no required dependencies.
Quick start
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.
Charts
Sparklines
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
Line charts
# 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
Bar charts
# 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
Histograms
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.
Scatter plots
print(tp.scatter(xs, ys, title="x vs y", width=60, height=20))
Heatmaps
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 ░▒▓█.
Live charts
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)
Themes & color
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.
Loading data
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"))
Command-line interface
# 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.
How it adapts to your terminal
- 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.
API reference
| 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.
Optional dependencies
| 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.
FAQ
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.
Development
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]"
pytest
See INSTRUCTIONS.md for the complete build-and-publish
walkthrough.
License
MIT © 2026 Aman Mukati
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file termplotx-0.1.0.tar.gz.
File metadata
- Download URL: termplotx-0.1.0.tar.gz
- Upload date:
- Size: 42.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3431d25d3f5176861468590dd836690ffb39261a91db422a86a0879368b88a2c
|
|
| MD5 |
05041df22458566fd46acbcc0782e87d
|
|
| BLAKE2b-256 |
7f7b246df23293d7a2f247715fb7390c76eab3fa9f2303f5a4659b7cc5bd77d1
|
File details
Details for the file termplotx-0.1.0-py3-none-any.whl.
File metadata
- Download URL: termplotx-0.1.0-py3-none-any.whl
- Upload date:
- Size: 37.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9f607b7e56672e1477bdc020f1bff49c24de8bada388f2844cadcb10134c6cf3
|
|
| MD5 |
02d7ceb9dd619641000ee185a2e92c4c
|
|
| BLAKE2b-256 |
3110a7c04a0674cdb6c69c91d1ed4274e32408202ea6ad3fb030dfdb79c69cfc
|