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.
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 plotilleresample-1.0.tar.gz.
File metadata
- Download URL: plotilleresample-1.0.tar.gz
- Upload date:
- Size: 7.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
19c336aa168ec725d10b3d6e22e88a9d8ac6b4baff67b42be646dcde0dda583c
|
|
| MD5 |
bed8a2a04a4b37809b7c5e229c9f5d97
|
|
| BLAKE2b-256 |
4aa781a70c9955e6a6c45fe09a16732c4ee1bae7d20c3d51ea6b73d47a8c1d6c
|
File details
Details for the file plotilleresample-1.0-py3-none-any.whl.
File metadata
- Download URL: plotilleresample-1.0-py3-none-any.whl
- Upload date:
- Size: 6.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fb867b16509fc660485050bd3a9e544dcaede8650255093820efb03569c38959
|
|
| MD5 |
a68d68206eaa8f09a60a5958a3740555
|
|
| BLAKE2b-256 |
3cb270bacada518ed421ac89af16da057758fddd9204968bfdd3e9ffd302db01
|