Minimal call
import random
rng = random.Random(3)
data = {"grp": [], "value": []}
for i, grp in enumerate(["a", "b", "c", "d"]):
data["grp"] += [grp] * 30
data["value"] += [rng.gauss(4 + i, 0.8) for _ in range(30)]
c = pt.chart(data, aes(x="grp", y="value"), ylabel="value")
c.add_strip(size=2.5, alpha=0.6)
Worked example
import plotlet as pt
from plotlet import aes
df = pt.load_dataset("tips")
c = pt.chart(df, aes(x="day", y="total_bill"),
title="bill by day", ylabel="total bill ($)",
data_width=340, data_height=220)
c.xscale("category", order=["Thur", "Fri", "Sat", "Sun"])
c.add_boxplot()
c.add_strip(size=2.5, alpha=0.45)
Docstring
Strip / jitter plot: categorical scatter with deterministic per-point jitter.
No per-render RNG — jitter offsets are derived from a splitmix64 hash of each
point's indices so the SVG is byte-identical across runs.
Long-form only:
c.add_strip(aes(x="cat", y="value"))
c.add_strip(aes(x="cat", y="value", fill="group"), palette={...})
Mapping `aes(fill="col")` dodges sub-strips side-by-side within each cat and
emits one legend entry per group level.
Aesthetics:
fill=<literal> bare literal point color (None = cycle default);
aes(fill="col") → column-driven grouping
color=<literal> point outline (defaults to frame color when used)
palette= maps group levels → fills when fill is mapped in aes
Other styling kwargs:
orientation='v' 'h' for horizontal (cats on y axis)
width=0.8 total dodge-group width as a band fraction
gap=0.1 slot-gap fraction between dodged sub-strips
jitter=0.2 spread within each slot as a slot-width fraction
(points land in ±jitter/2 * slot_w from the slot center)
size=3 point radius in pixels
alpha=0.7 point opacity
linewidth=0 outline stroke width (0 = no outline)
rasterize=None None = auto-raster to one <image> above the point
threshold; True/False forces it on/off