plotext renders scatter, line, bar, and histogram charts directly in the terminal with optional color themes. pip install plotext. Line: import plotext as plt; plt.plot([1,2,3,4]); plt.title("Line"); plt.show(). Scatter: plt.scatter(x, y). Bar: plt.bar(["A","B","C"],[10,20,15]); plt.show(). Simple bar H: plt.simple_bar(labels, values). Histogram: plt.hist(data, bins=20). Multiple series: plt.plot(y1, label="A"); plt.plot(y2, label="B"). XY: plt.scatter(x_data, y_data). Axes labels: plt.xlabel("Time"); plt.ylabel("Value"). Limits: plt.xlim(0, 100); plt.ylim(-1, 1). Grid: plt.grid(True). Theme: plt.theme("dark") — also “clear”, “pro”, “matrix”, “dreamland”, “grandpa”, “salad”, “elegant”, “girly”. Date: plt.date_form("Y-m-d") then plt.plot(dates, values). Subplots: plt.subplots(2, 2); plt.subplot(1, 1); plt.plot(...). plt.plotsize(100, 30) — set width/height in characters. plt.canvas_color("black"). plt.axes_color("black"). plt.ticks_color("white"). Build (no show): plt.build() → returns string. plt.clear_figure(). Image: plt.image_plot("img.png"); plt.show(). Frame: plt.frame(True). Save: plt.save_fig("chart.txt"). Horizontal bar: plt.bar(labels, values, orientation="h"). Stacked bar: plt.stacked_bar(labels, matrix_of_values). Get: plt.terminal_size() for width/height. Claude Code generates plotext charts, dashboards, and real-time metric visualizations.
CLAUDE.md for plotext
## plotext Stack
- Version: plotext >= 5.3 | pip install plotext
- Line: plt.plot(y) | plt.plot(x, y) | plt.show()
- Scatter: plt.scatter(x, y, marker="braille") — braille for high-res dots
- Bar: plt.bar(labels, values) | plt.bar(labels, values, orientation="h")
- Hist: plt.hist(data, bins=20, label="dist") — distribution view
- Themes: plt.theme("dark") | "pro" | "matrix" | "clear" | "elegant"
- Build: plt.build() → str for embedding; plt.clear_figure() to reset
plotext Terminal Chart Pipeline
# app/charts.py — plotext line, scatter, bar, histogram, and subplot dashboards
from __future__ import annotations
import math
import time
from collections import deque
from typing import Any
import plotext as plt
# ─────────────────────────────────────────────────────────────────────────────
# 1. Basic chart helpers
# ─────────────────────────────────────────────────────────────────────────────
def line_chart(
y: list[float],
x: list[float] | None = None,
title: str = "",
xlabel: str = "",
ylabel: str = "",
label: str = "",
color: str = "blue",
theme: str = "dark",
width: int = 80,
height: int = 20,
) -> str:
"""Render a single-series line chart and return as string."""
plt.clear_figure()
plt.plotsize(width, height)
plt.theme(theme)
if title:
plt.title(title)
if xlabel:
plt.xlabel(xlabel)
if ylabel:
plt.ylabel(ylabel)
if x is not None:
plt.plot(x, y, label=label, color=color)
else:
plt.plot(y, label=label, color=color)
return plt.build()
def scatter_chart(
x: list[float],
y: list[float],
title: str = "",
xlabel: str = "",
ylabel: str = "",
label: str = "",
marker: str = "braille",
color: str = "green",
theme: str = "dark",
width: int = 80,
height: int = 20,
) -> str:
"""Render a scatter chart and return as string."""
plt.clear_figure()
plt.plotsize(width, height)
plt.theme(theme)
if title:
plt.title(title)
if xlabel:
plt.xlabel(xlabel)
if ylabel:
plt.ylabel(ylabel)
plt.scatter(x, y, label=label, marker=marker, color=color)
return plt.build()
def multi_line_chart(
series: dict[str, list[float]],
x: list[float] | None = None,
title: str = "",
xlabel: str = "",
ylabel: str = "",
theme: str = "dark",
width: int = 80,
height: int = 20,
) -> str:
"""
Render multiple named series on one chart.
series: {"label": [values], ...}
"""
colors = ["blue", "red", "green", "yellow", "magenta", "cyan"]
plt.clear_figure()
plt.plotsize(width, height)
plt.theme(theme)
if title:
plt.title(title)
if xlabel:
plt.xlabel(xlabel)
if ylabel:
plt.ylabel(ylabel)
for (label, values), color in zip(series.items(), colors):
if x is not None:
plt.plot(x, values, label=label, color=color)
else:
plt.plot(values, label=label, color=color)
return plt.build()
# ─────────────────────────────────────────────────────────────────────────────
# 2. Bar charts
# ─────────────────────────────────────────────────────────────────────────────
def bar_chart(
labels: list[str],
values: list[float],
title: str = "",
horizontal: bool = False,
color: str = "blue",
theme: str = "dark",
width: int = 80,
height: int = 20,
) -> str:
"""Vertical or horizontal bar chart."""
plt.clear_figure()
plt.plotsize(width, height)
plt.theme(theme)
if title:
plt.title(title)
orientation = "h" if horizontal else "v"
plt.bar(labels, values, color=color, orientation=orientation)
return plt.build()
def stacked_bar_chart(
labels: list[str],
series: dict[str, list[float]],
title: str = "",
theme: str = "dark",
width: int = 80,
height: int = 20,
) -> str:
"""
Stacked bar chart.
series: {"group_label": [value_per_bar], ...}
"""
plt.clear_figure()
plt.plotsize(width, height)
plt.theme(theme)
if title:
plt.title(title)
matrix = list(series.values())
series_labels = list(series.keys())
plt.stacked_bar(labels, matrix, labels=series_labels)
return plt.build()
# ─────────────────────────────────────────────────────────────────────────────
# 3. Histogram
# ─────────────────────────────────────────────────────────────────────────────
def histogram(
data: list[float],
bins: int = 20,
title: str = "",
label: str = "Distribution",
color: str = "cyan",
theme: str = "dark",
width: int = 80,
height: int = 20,
) -> str:
"""Frequency histogram."""
plt.clear_figure()
plt.plotsize(width, height)
plt.theme(theme)
if title:
plt.title(title)
plt.hist(data, bins=bins, label=label, color=color)
return plt.build()
def multi_histogram(
datasets: dict[str, list[float]],
bins: int = 20,
title: str = "",
theme: str = "dark",
width: int = 80,
height: int = 20,
) -> str:
"""Multiple overlaid histograms."""
colors = ["blue", "red", "green", "yellow"]
plt.clear_figure()
plt.plotsize(width, height)
plt.theme(theme)
if title:
plt.title(title)
for (label, data), color in zip(datasets.items(), colors):
plt.hist(data, bins=bins, label=label, color=color)
return plt.build()
# ─────────────────────────────────────────────────────────────────────────────
# 4. Subplots / grid dashboard
# ─────────────────────────────────────────────────────────────────────────────
def grid_dashboard(
panels: list[dict[str, Any]],
rows: int = 2,
cols: int = 2,
theme: str = "dark",
width: int = 120,
height: int = 40,
) -> str:
"""
Render multiple charts in a grid layout.
panels: list of chart config dicts, one per cell:
{"type": "line"|"bar"|"scatter"|"hist",
"title": ..., "y": [...], "x": [...],
"labels": [...], "values": [...], "data": [...]}
"""
plt.clear_figure()
plt.plotsize(width, height)
plt.theme(theme)
plt.subplots(rows, cols)
for i, panel in enumerate(panels[:rows * cols]):
r = i // cols + 1
c = i % cols + 1
plt.subplot(r, c)
chart_type = panel.get("type", "line")
if panel.get("title"):
plt.title(panel["title"])
if chart_type == "line":
if "x" in panel:
plt.plot(panel["x"], panel["y"], color=panel.get("color", "blue"))
else:
plt.plot(panel.get("y", []), color=panel.get("color", "blue"))
elif chart_type == "scatter":
plt.scatter(panel.get("x", []), panel.get("y", []),
marker=panel.get("marker", "dot"))
elif chart_type == "bar":
plt.bar(panel["labels"], panel["values"],
color=panel.get("color", "blue"))
elif chart_type == "hist":
plt.hist(panel.get("data", []), bins=panel.get("bins", 10))
return plt.build()
# ─────────────────────────────────────────────────────────────────────────────
# 5. Scrolling / live chart
# ─────────────────────────────────────────────────────────────────────────────
class LiveChart:
"""
Scrolling line chart backed by a deque — update and re-render each tick.
Usage:
chart = LiveChart(width=70, title="Requests/s")
while True:
chart.push(rps())
chart.display()
time.sleep(1)
"""
def __init__(
self,
maxlen: int = 60,
width: int = 80,
height: int = 15,
title: str = "Live",
ylabel: str = "",
color: str = "green",
theme: str = "dark",
ymin: float | None = None,
ymax: float | None = None,
):
self._buf: deque[float] = deque([0.0] * maxlen, maxlen=maxlen)
self._width = width
self._height = height
self._title = title
self._ylabel = ylabel
self._color = color
self._theme = theme
self._ymin = ymin
self._ymax = ymax
def push(self, value: float) -> None:
self._buf.append(value)
def render(self) -> str:
data = list(self._buf)
plt.clear_figure()
plt.plotsize(self._width, self._height)
plt.theme(self._theme)
plt.title(self._title)
if self._ylabel:
plt.ylabel(self._ylabel)
if self._ymin is not None:
plt.ylim(self._ymin, self._ymax or max(data) or 1)
plt.plot(data, color=self._color)
return plt.build()
def display(self) -> None:
import os
os.system("clear")
print(self.render())
# ─────────────────────────────────────────────────────────────────────────────
# 6. pandas / numpy integration
# ─────────────────────────────────────────────────────────────────────────────
def from_series(
series,
title: str = "",
color: str = "blue",
chart_type: str = "line",
theme: str = "dark",
width: int = 80,
height: int = 20,
) -> str:
"""
Plot a pandas Series or numpy array.
chart_type: "line" | "scatter" | "bar" | "hist"
"""
import numpy as np
y = list(series)
x = list(range(len(y)))
if chart_type == "hist":
return histogram(y, title=title, color=color, theme=theme, width=width, height=height)
elif chart_type == "bar":
labels = [str(i) for i in range(len(y))]
return bar_chart(labels, y, title=title, color=color, theme=theme, width=width, height=height)
elif chart_type == "scatter":
return scatter_chart(x, y, title=title, color=color, theme=theme, width=width, height=height)
else:
return line_chart(y, title=title, color=color, theme=theme, width=width, height=height)
def from_dataframe(
df,
columns: list[str],
title: str = "",
theme: str = "dark",
width: int = 80,
height: int = 20,
) -> str:
"""Plot selected columns of a pandas DataFrame as multi-line chart."""
series = {col: list(df[col]) for col in columns}
return multi_line_chart(series, title=title, theme=theme, width=width, height=height)
# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
import random
print("=== Line chart (sine) ===")
x_vals = [i * 0.1 for i in range(100)]
y_vals = [math.sin(x) for x in x_vals]
print(line_chart(y_vals, title="Sine Wave", ylabel="sin(x)", color="blue"))
print("\n=== Scatter chart ===")
xs = [random.gauss(0, 1) for _ in range(200)]
ys = [random.gauss(0, 1) for _ in range(200)]
print(scatter_chart(xs, ys, title="Random Scatter", marker="braille"))
print("\n=== Multi-line chart ===")
series = {
"sin": [math.sin(i * 0.1) for i in range(80)],
"cos": [math.cos(i * 0.1) for i in range(80)],
"tan÷5":[math.tan(i * 0.1) / 5 for i in range(80)],
}
print(multi_line_chart(series, title="Trig Functions", ylabel="value"))
print("\n=== Bar chart ===")
print(bar_chart(
["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
[12500, 14200, 16800, 15100, 18300, 21000],
title="Monthly Revenue ($)",
color="green",
))
print("\n=== Histogram ===")
data = [random.gauss(50, 10) for _ in range(500)]
print(histogram(data, bins=20, title="Normal Distribution (μ=50, σ=10)"))
print("\n=== Grid dashboard (2×2) ===")
panels = [
{"type": "line", "title": "CPU %", "y": [random.uniform(20,80) for _ in range(60)], "color": "green"},
{"type": "bar", "title": "Traffic", "labels": ["US","EU","APAC","Other"], "values": [45,30,20,5], "color": "blue"},
{"type": "hist", "title": "Latency", "data": [random.expovariate(0.1) for _ in range(200)], "bins": 15},
{"type": "scatter", "title": "Error Rate","x": list(range(50)), "y": [random.uniform(0,5) for _ in range(50)]},
]
print(grid_dashboard(panels, rows=2, cols=2, width=120, height=40))
For the asciichartpy alternative — asciichartpy is a minimal single-file library ideal for pure line charts with no external dependencies; plotext supports scatter plots (with braille marker), bar charts, histograms, stacked bars, subplots, date axes, and even inline image display, making it the richer choice when your CLI tool needs multiple chart types. For the uniplot alternative — uniplot renders Unicode braille charts with superior visual resolution and good NumPy/pandas integration via its plot() function, but is line/scatter focused; plotext has a more complete API covering bar, histogram, subplot grids, and theming, making it better for dashboard-style CLI output. The Claude Skills 360 bundle includes plotext skill sets covering plt.plot()/scatter()/bar()/hist() core charts, multi_line_chart() multi-series overlay, bar_chart() vertical and horizontal, stacked_bar_chart(), histogram() and multi_histogram(), grid_dashboard() subplot grid, LiveChart deque-backed scrolling display, from_series()/from_dataframe() pandas integration, plt.theme() dark/pro/matrix styles, plt.build() for string capture, and plt.plotsize() for fixed dimensions. Start with the free tier to try terminal chart code generation.