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.