Tutorial 16 - Plotext Advanced Workflows
This tutorial focuses on practical terminal workflows that are easy to miss when moving from Matplotlib to the Plotext backend: layer-by-layer output, subplot dashboards, terminal-safe files, and backend limitations.
[1]:
from pathlib import Path
import matplotlib.patches as patches
import numpy as np
from maxplotlib import Canvas
1. Build a terminal dashboard
Canvas.subplots() works with Plotext too. Keep subplot titles short enough for a terminal and render with keep_colors=False when the output will be logged or tested.
[2]:
canvas, axes = Canvas.subplots(nrows=1, ncols=2)
x = np.linspace(0, 2 * np.pi, 80)
axes[0].plot(x, np.sin(x), label="signal")
axes[0].set_title("Signal")
axes[0].set_grid(True)
axes[0].set_legend(True)
axes[1].bar([0, 1, 2], [4, 7, 3], label="count")
axes[1].set_xticks([0, 1, 2], labels=["A", "B", "C"])
axes[1].set_title("Counts")
print(canvas.render(backend="plotext").build(keep_colors=False))
Signal Counts
┌┬────┬─────┬────┬────┬─────┬────┬┐ ┌─────┬───────────┬───────────┬─────┐
1.00┼┌──────────┐────┼────┼─────┼────┼┤7.0┼┌─────────┐─███████████──────┼─────┤
││ │ │ │signal ││ ││ │ ███████████ │ │
││ ▚ signal │▖ │ │ │ ││ ││ █ count │ ███████████ │ │
││ │▝▖ │ │ │ ││ ││ │ ███████████ │ │
0.50┼└──────────┘─▚──┼────┼─────┼────┼┤5.2┼└─────────┘─███████████──────┼─────┤
││ ▐ │ │ ▘ │ │ │ ││ │ │ ███████████ │ │
││▗▘ │ │ ▝▖│ │ │ ││ │ │ ███████████ │ │
││▖ │ │ ▚│ │ │ ││ │███████████ ███████████ │ │
│▝ │ │ ▖ │ │ ││ │███████████ ███████████ │ │
0.00┼▝────┼─────┼────▝────┼─────┼────▌┤3.5┼███████████─███████████──────┼─────┤
││ │ │ │▚ │ │ ▝││ │███████████ ███████████ ███████████│
││ │ │ │▝▖ │ │ ▗▘││ │███████████ ███████████ ███████████│
││ │ │ │ ▗ │ │ ▌ ││ │███████████ ███████████ ███████████│
-0.50┼┼────┼─────┼────┼──▚─┼─────┼─▝──┼┤1.8┼███████████─███████████─███████████┤
││ │ │ │ ▝▖│ │▗▘ ││ │███████████ ███████████ ███████████│
││ │ │ │ ▝▖ ▗▌ ││ │███████████ ███████████ ███████████│
││ │ │ │ ▝▖ ▄▘ ││ │███████████ ███████████ ███████████│
-1.00┼┼────┼─────┼────┼────┼▝▀▀▀▘┼────┼┤0.0┼███████████─███████████─███████████┤
└┼────┼─────┼────┼────┼─────┼────┼┘ └─────┼───────────┼───────────┼─────┘
0.0 1.0 2.1 3.1 4.2 5.2 6.3 A B C
2. Add uncertainty and annotations
Error bars accept scalar, symmetric-array, and Matplotlib’s two-row asymmetric-array forms. Reference lines, text, and annotations are rendered as terminal primitives.
[3]:
x = np.arange(5)
y = np.array([1.0, 1.8, 1.3, 2.5, 2.0])
canvas, ax = Canvas.subplots()
ax.errorbar(
x,
y,
yerr=[[0.1] * 5, [0.25] * 5],
label="observations",
)
ax.axhline(y.mean(), color="yellow")
ax.annotate("peak", xy=(3, 2.5), xytext=(2, 2.8))
ax.set_title("Measurements")
ax.set_legend(True)
print(canvas.render(backend="plotext").build(keep_colors=False))
Measurements
┌──────────────────────────────────────────────────────────────────────────┐
2.80┤┌────────────────┐ peak │
││ │ observations │
││ ┼ observations │ │ │
││ │───────────────────┼────────────────── │
2.31┤└────────────────┘ │ │
│ │ │
│ │ │
│ │ ─────────────────────────┼────────────────────────│
│ │ │ │
1.81┼────────────┼─────────────────────────────────────────────────────────────┤
│ │ │
│ │ │
│ │ │
1.32┤ ────────────┼───────────── │
││ │ │
│┼ │
││ │
0.82┤│ │
└┬───────────┬───────────┬────────────┬───────────┬───────────┬───────────┬┘
0 1 2 3 4 5 6
3. Render layers incrementally
Layers are useful for progress reports and debugging. Pass a list to render(..., layers=[...]), or use savefig(..., layer_by_layer=True) to write successive text files.
[4]:
canvas, ax = Canvas.subplots()
ax.plot(x, y, label="raw", layer=0)
ax.plot(x, np.maximum.accumulate(y), label="running max", layer=1)
ax.set_title("Layered diagnostics")
ax.set_legend(True)
for selected_layers in ([0], [0, 1]):
text = canvas.render(backend="plotext", layers=selected_layers).build(
keep_colors=False
)
print(f"--- layers={selected_layers} ---")
print(text)
--- layers=[0] ---
Layered diagnostics
┌──────────────────────────────────────────────────────────────────────────┐
2.50┤┌───────┐ ▖ │
││ │ raw │
││ ▚ raw │ │
││ │ │
2.12┤└───────┘ │
│ │
│ ▘│
│ │
│ ▝ │
1.75┤ │
│ │
│ │
│ │
1.38┤ │
│ ▘ │
│ │
│ │
1.00┤▝ │
└┬───────────┬───────────┬────────────┬───────────┬───────────┬───────────┬┘
0.0 0.7 1.3 2.0 2.7 3.3 4.0
--- layers=[0, 1] ---
Layered diagnostics
┌──────────────────────────────────────────────────────────────────────────┐
2.50┤┌───────────────┐ ▖ ▖│
││ │ raw │
││ ▚ raw │ │
││ │ running max │
2.12┤│ ▚ running max │ │
││ │ │
│└───────────────┘ ▘│
│ │
│ ▝ ▘ │
1.75┤ │
│ │
│ │
│ │
1.38┤ │
│ ▘ │
│ │
│ │
1.00┤▝ │
└┬───────────┬───────────┬────────────┬───────────┬───────────┬───────────┬┘
0.0 0.7 1.3 2.0 2.7 3.3 4.0
4. Save terminal output
Plotext output is text, not an image. Saving without ANSI colors makes the file portable to CI logs, issue trackers, and plain-text artifacts.
[5]:
output_path = Path("plotext-output.txt")
figure = canvas.render(backend="plotext")
figure.savefig(output_path, keep_colors=False)
print(f"wrote {output_path}")
wrote plotext-output.txt
5. Matrix plots and patches
Matrix data is displayed with Plotext’s heatmap primitive. Common Matplotlib patches are approximated by their polygon outline, which is useful for lightweight terminal diagnostics.
[6]:
canvas, ax = Canvas.subplots()
ax.add_imshow(np.arange(16).reshape(4, 4))
ax.add_patch(patches.Rectangle((0.5, 0.5), 2, 2, fill=False, label="window"))
ax.add_colorbar(label="intensity")
ax.set_title("Matrix diagnostic")
ax.set_legend(True)
print(canvas.render(backend="plotext").build(keep_colors=False))
Matrix diagnostic | intensity: 0..15
┌───────────────────────────────────────────────────────────────────────────┐
3.0┤┌──────────┐ █ █ █│
││ │ window │
││ ▚ window │ │
││ │▝ ▘ │
2.2┤└──────────┘ │
│ │
│█ █ █ █│
│ │
│ │
1.5┤ │
│ │
│█ █ █ █│
│ │
0.8┤ │
│ ▗ ▖ │
│ │
│ │
0.0┤█ █ █ █│
└┬───────────┬────────────┬───────────┬───────────┬────────────┬───────────┬┘
0.0 0.5 1.0 1.5 2.0 2.5 3.0
Current limitations
The backend intentionally raises NotImplementedError for plot types that do not have a faithful Plotext 6 equivalent, such as histograms, pie charts, stem plots, and secondary/twin axes. Use Matplotlib or Plotly for those cases.