plotilleresample
Python module to resample datasets before plotting with Plotille.
Why resample?
Plotille rasterizes to a terminal canvas of braille dots: width * 2 columns by height * 4 rows. Feeding it far more points than that costs interpolation time on detail the canvas cannot show. Plotille rasterizes; plotilleresample decides what information deserves to reach the rasterizer:
| Function | Strategy | Best for |
|---|---|---|
resample_plot |
uniform stride | smooth lines, cheapest reduction |
resample_plot_minmax |
min/max per bucket | peaks, oscillations, time series |
resample_plot_lttb |
largest triangle per bucket | shape-faithful single line |
resample_plot_minmax_lttb |
minmax preselection + LTTB | shape-faithful line, large inputs |
resample_scatter |
uniform stride | large scatter inputs |
The uniform stride keeps one point every N: fast and predictable, but a narrow peak that falls between two kept points disappears from the plot. resample_plot_minmax instead makes one bucket per braille dot column and keeps the minimum and the maximum Y of each bucket, so the envelope of the signal — spikes included — always survives:
X = list(range(10000))
Y = [0.0] * 10000
Y[33] = 1000.0 # a narrow spike
_, y_stride = plotilleresample.resample_plot(X, Y)
_, y_minmax = plotilleresample.resample_plot_minmax(X, Y)
1000.0 in y_stride # False: the spike vanished
1000.0 in y_minmax # True: the envelope survives
resample_plot_lttb implements Largest-Triangle-Three-Buckets (Steinarsson, 2013): it always keeps the first and the last point and picks the most shape-representative point of each bucket, giving a single clean line that looks like the original. It keeps one point per bucket, so — unlike min/max — one of two opposing extremes falling in the same bucket can be dropped: shape fidelity instead of envelope guarantee.
resample_plot_minmax_lttb is the hybrid (MinMaxLTTB, Van der Donckt et al., 2023; the plotly-resampler default): on large inputs a minmax pass preselects the per bucket extremes and LTTB runs over those candidates only. Visually close to pure LTTB and faster, with a gap that grows with input size — about 1.6x end to end at 100,000 points, and about 3.4x on the resampling pass alone at 1,000,000 — and the true extremes are always among the candidates.
All four plot resamplers work in sample order — they bucket by index, so X is expected to be already sorted, as in a time series (resample_scatter makes no ordering assumption). They keep at most width * 4 points and resample_scatter keeps at most width * 2 * height, so plotille only receives what the canvas can actually display.
Benchmark
End to end times: building the plot string with plotille alone versus resampling first. Measured with benchmarks/bench.py (canvas 80x40, best of 3) on Python 3.14, Linux, Intel Core i5-1135G7:
| Points | plotille alone | stride + plotille | minmax + plotille | lttb + plotille | mmlttb + plotille |
|---|---|---|---|---|---|
| 10,000 | 202 ms | 23 ms | 22 ms | 27 ms | 24 ms |
| 100,000 | 1.75 s | 39 ms | 52 ms | 90 ms | 56 ms |
Reproduce it from the repository root with:
uv run --group bench benchmarks/bench.py
The resampling-pass figure quoted in Why resample? (pure LTTB vs MinMaxLTTB at 1,000,000 points) has its own script:
uv run benchmarks/bench_resamplers.py
Installation
Install with UV:
uv add plotilleresample
Install with pip:
pip install plotilleresample
plotilleresample has no runtime dependencies — not even plotille: it only reduces sequences. To run the example below, install plotille as well (uv add plotille or pip install plotille).
Usage
import math
import plotille
from plotilleresample import resample_plot_minmax_lttb
r = 100_000
X = list(range(r))
Y = [math.sin(i / 500) * 100 for i in range(r)]
X, Y = resample_plot_minmax_lttb(X, Y, width=80, height=40)
print(plotille.plot(X, Y, width=80, height=40))
The full interactive demo, running every resampler on the same dataset, lives in examples/demo.py.
Acknowledgements
plotilleresample exists to serve plotille by Tammo Ippen, which now lists this project in its README. The min/max strategy grew out of the feedback in plotille#22, back in 2019.
Metadata
Release files for plotilleresample 1.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| plotilleresample-1.0.1.tar.gz | 8.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| plotilleresample-1.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 14.9 kB
Release files / plotilleresample-1.0.1.tar.gz
| Download URL | plotilleresample-1.0.1.tar.gz |
|---|---|
| Size | 8.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b1f2e39a4711e3b470cc4803a516284e9e347de495d47657de1e7f775fbd78c1
|
|
BLAKE2b-256 checksum How to use checksums |
f17e87b903771b5cc0c2408c29535688445ef3c35bc50ddcd2d2fb1183a5721a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.11 {"installer":{"name":"uv","version":"0.12.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / plotilleresample-1.0.1-py3-none-any.whl
| Download URL | plotilleresample-1.0.1-py3-none-any.whl |
|---|---|
| Size | 6.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2f561a3df670ba8b8e24664750cbd930699073aff1fce20978845393b4d0ffb5
|
|
BLAKE2b-256 checksum How to use checksums |
630b6ff4071eda5771678bd5730c81bc00205c60eb6c7bf9d17fa575d5dfc00c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.11 {"installer":{"name":"uv","version":"0.12.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|