Expressive box edges, every backend

A pavement closes its box where values are spread out and opens a gap where they clump onto a value line — identically across all five backends.

Each bin draws its long top and bottom edges only over itself, and only when one or more values fall strictly inside it. Below, every backend renders the same three cases (boxes drawn outline-only, so the gap — a missing stretch of top/bottom edge — reads clearly): iris sepal_width binned into 8, which gaps in the dense middle; the same data with show_box=True to force the complete box; and a spread distribution, which stays closed. Compare a column down the page — every backend opens and closes the box at the same places.

SVG spark

Inline, self-contained SVG — no JavaScript.

pavement sparkline of 150 values2 to 2.5 p0 to p12 7% (10 of 150 values)2.5 to 2.8 p12 to p25 9% (14 of 150 values)2.8 to 2.9 0% (0 of 150 values)2.9 to 3 0% (0 of 150 values)3 to 3.1 0% (0 of 150 values)3.1 to 3.3 p62 to p75 9% (13 of 150 values)3.3 to 3.6 p75 to p88 12% (18 of 150 values)3.6 to 4.4 p88 to p100 9% (14 of 150 values)2 p0 1% (1 of 150 values)2.5 p12 5% (8 of 150 values)2.8 p25 9% (14 of 150 values)2.9 p38 7% (10 of 150 values)3 p50 17% (26 of 150 values)3.1 p62 7% (11 of 150 values)3.3 p75 4% (6 of 150 values)3.6 p88 3% (4 of 150 values)4.4 p100 1% (1 of 150 values)
iris sepal_width, 8 bins — the box gaps in the dense middle, where 2.8–3.1 cm are so common they all sit on bin edges
pavement sparkline of 150 values2 to 2.5 p0 to p12 7% (10 of 150 values)2.5 to 2.8 p12 to p25 9% (14 of 150 values)2.8 to 2.9 0% (0 of 150 values)2.9 to 3 0% (0 of 150 values)3 to 3.1 0% (0 of 150 values)3.1 to 3.3 p62 to p75 9% (13 of 150 values)3.3 to 3.6 p75 to p88 12% (18 of 150 values)3.6 to 4.4 p88 to p100 9% (14 of 150 values)2 p0 1% (1 of 150 values)2.5 p12 5% (8 of 150 values)2.8 p25 9% (14 of 150 values)2.9 p38 7% (10 of 150 values)3 p50 17% (26 of 150 values)3.1 p62 7% (11 of 150 values)3.3 p75 4% (6 of 150 values)3.6 p88 3% (4 of 150 values)4.4 p100 1% (1 of 150 values)
Same data, show_box=True — the complete box, forced
pavement sparkline of 400 values0.2 to 10.8 p0 to p12 12% (49 of 400 values)10.8 to 23.9 p12 to p25 12% (50 of 400 values)23.9 to 34.4 p25 to p38 12% (49 of 400 values)34.4 to 49.1 p38 to p50 12% (49 of 400 values)49.1 to 59.9 p50 to p62 12% (50 of 400 values)59.9 to 75.8 p62 to p75 12% (50 of 400 values)75.8 to 87.4 p75 to p88 12% (50 of 400 values)87.4 to 99.3 p88 to p100 12% (49 of 400 values)0.2 p0 <1% (1 of 400 values)10.8 p12 0% (0 of 400 values)23.9 p25 0% (0 of 400 values)34.4 p38 0% (2 of 400 values)49.1 p50 0% (0 of 400 values)59.9 p62 0% (0 of 400 values)75.8 p75 0% (0 of 400 values)87.4 p88 0% (0 of 400 values)99.3 p100 <1% (1 of 400 values)
A spread distribution, 8 bins — every bin is populated, so the box stays closed end to end

matplotlib plot

Static raster (PNG), for print.

matplotlib pavement
iris sepal_width, 8 bins — the box gaps in the dense middle, where 2.8–3.1 cm are so common they all sit on bin edges
matplotlib pavement
Same data, show_box=True — the complete box, forced
matplotlib pavement
A spread distribution, 8 bins — every bin is populated, so the box stays closed end to end

Plotly plot

Interactive — hover, pan, zoom.

iris sepal_width, 8 bins — the box gaps in the dense middle, where 2.8–3.1 cm are so common they all sit on bin edges
Same data, show_box=True — the complete box, forced
A spread distribution, 8 bins — every bin is populated, so the box stays closed end to end

Bokeh plot

Interactive — hover, pan, zoom.

iris sepal_width, 8 bins — the box gaps in the dense middle, where 2.8–3.1 cm are so common they all sit on bin edges
Same data, show_box=True — the complete box, forced
A spread distribution, 8 bins — every bin is populated, so the box stays closed end to end

HoloViews plot

Backend-agnostic (rendered via Bokeh).

iris sepal_width, 8 bins — the box gaps in the dense middle, where 2.8–3.1 cm are so common they all sit on bin edges
Same data, show_box=True — the complete box, forced
A spread distribution, 8 bins — every bin is populated, so the box stays closed end to end

Drawn straight from pavement.svg, pavement.matplotlib, pavement.plotly, pavement.bokeh, and pavement.holoviews — one shared geometry, one shared rule.

Rugs are borderless by default

SVG spark — the same rule applies on every backend.

A binned pavement always draws the box. A rug (bins=None) drops the box edges by default, so it reads like an ordinary rug plot — the box becomes a visual cue that you are looking at quantile bins, not raw points. show_box=True restores the box on a rug; show_box=False drops it from a binned plot.

pavement sparkline of 15 values1 to 3 p0 to p25 13% (2 of 15 values)3 to 5 p25 to p50 7% (1 of 15 values)5 to 12 p50 to p75 13% (2 of 15 values)12 to 18 p75 to p100 7% (1 of 15 values)1 p0 7% (1 of 15 values)3 p25 20% (3 of 15 values)5 p50 13% (2 of 15 values)12 p75 13% (2 of 15 values)18 p100 7% (1 of 15 values)
Binned (bins=4) — box always on
pavement sparkline of 15 values1 to 2 0% (0 of 15 values)2 to 3 0% (0 of 15 values)3 to 4 0% (0 of 15 values)4 to 5 0% (0 of 15 values)5 to 7 0% (0 of 15 values)7 to 9 0% (0 of 15 values)9 to 12 0% (0 of 15 values)12 to 13 0% (0 of 15 values)13 to 18 0% (0 of 15 values)1 p0 7% (1 of 15 values)2 p7 to p14 13% (2 of 15 values)3 p21 to p36 20% (3 of 15 values)4 p43 7% (1 of 15 values)5 p50 to p57 13% (2 of 15 values)7 p64 7% (1 of 15 values)9 p71 7% (1 of 15 values)12 p79 to p86 13% (2 of 15 values)13 p93 7% (1 of 15 values)18 p100 7% (1 of 15 values)
Rug (bins=None) — borderless by default
pavement sparkline of 15 values1 to 2 0% (0 of 15 values)2 to 3 0% (0 of 15 values)3 to 4 0% (0 of 15 values)4 to 5 0% (0 of 15 values)5 to 7 0% (0 of 15 values)7 to 9 0% (0 of 15 values)9 to 12 0% (0 of 15 values)12 to 13 0% (0 of 15 values)13 to 18 0% (0 of 15 values)1 p0 7% (1 of 15 values)2 p7 to p14 13% (2 of 15 values)3 p21 to p36 20% (3 of 15 values)4 p43 7% (1 of 15 values)5 p50 to p57 13% (2 of 15 values)7 p64 7% (1 of 15 values)9 p71 7% (1 of 15 values)12 p79 to p86 13% (2 of 15 values)13 p93 7% (1 of 15 values)18 p100 7% (1 of 15 values)
Rug + show_box=True — box forced back on
Show code
import pavement.svg as psvg

# A binned pavement always draws its box:
psvg.spark(data, bins=4)

# A rug drops the box edges by default:
psvg.spark(data, bins=None)

# Force the box back on a rug:
psvg.spark(data, bins=None, show_box=True)

# Drop the box from a binned plot:
psvg.spark(data, bins=4, show_box=False)