7. Reproducibility & AI tooling
Byte-identical output, figures as data, and an SVG your scripts and AI assistants can read. Every snippet on this page is executed on every build — the figures are its output.
Why the bytes match
Text is drawn as paths from a bundled font, so nothing depends on what’s installed on the machine. There is no global state — themes, defaults, everything is per-chart — and no interactivity, ever. The result: the same script produces the same SVG, byte for byte, on macOS, Linux and Windows. Figures can live in version control and break loudly when they change — plotlet’s own test suite is 270+ committed baseline SVGs compared byte-wise on every CI run.
df = {"x": [1, 2, 3, 4], "y": [2, 4, 3, 5]}
c = pt.chart(df, aes(x="x", y="y"), title="render me twice")
c.add_line()
assert c.to_svg() == c.to_svg() # trivially true here —
# the real claim is across machines, and CI enforces it
Figures as data
The journal serializes to JSON: archive it next to
a paper, ship it to a colleague, rebuild it years later — the SVG
matches byte for byte. The assert below runs on every
build of this page.
df = {"x": [1, 2, 3, 4], "y": [2, 4, 3, 5]}
c1 = pt.chart(df, aes(x="x", y="y"), title="original")
c1.add_line()
payload = pt.to_json(c1) # the journal, as JSON
c = pt.from_json(payload) # rebuilt anywhere, any machine
assert c.to_svg() == c1.to_svg() # byte-identical
What your AI assistant sees
The SVG is self-describing: every artist group
carries data-plotlet-* attributes — plot type,
mapped columns, row counts, data ranges — so an AI assistant (or
any script) can read what a figure shows from the file itself, no
pixels involved. For layout questions (“why does the legend
overlap the title?”), c.regions() returns every
chrome box as structured data. Below: the chart, a fragment of its own
SVG, and the first rows of its region report. Full schema in
docs/AI_ATTRS.md.
tips = pt.load_dataset("tips")
c = pt.chart(tips, aes(x="total_bill", y="tip"), title="tips",
data_width=300, data_height=200)
c.add_scatter(size=2.5, alpha=0.6)
from the SVG itself
<svg
data-plotlet-version="0.6.2"
data-plotlet-schema="2"
data-plotlet-kind="layout"
…>
<g
data-plotlet-type="scatter"
data-plotlet-index="0"
data-plotlet-color="#1f77b4"
data-plotlet-n="244"
data-plotlet-x-min="3.07"
data-plotlet-x-max="50.81"
data-plotlet-y-min="1"
data-plotlet-y-max="10"
data-plotlet-marker="o"
…>c.regions()
{'kind': 'rect', 'bbox': (30.0, 33.0, 300.0, 200), 'name': 'panel', 'meta': {}}
{'kind': 'segment', 'bbox': (30.0, 32.5, 300.0, 1.0), 'name': 'spine', 'meta': {'width': 1.0}}
{'kind': 'segment', 'bbox': (30.0, 232.5, 300.0, 1.0), 'name': 'spine', 'meta': {'width': 1.0}}
{'kind': 'segment', 'bbox': (29.5, 33.0, 1.0, 200), 'name': 'spine', 'meta': {'width': 1.0}}
{'kind': 'segment', 'bbox': (329.5, 33.0, 1.0, 200), 'name': 'spine', 'meta': {'width': 1.0}}
…Discoverable by construction
The registry is queryable at runtime —
pt.artist_table() lists every installed artist with its
capabilities, and help(c.add_scatter) forwards the
artist’s docstring through the recorder. AI-oriented onboarding
guides ship inside the package
(skills/)
— pt.skill() prints the users guide for tools that
generate plotlet code on your behalf.
names = sorted({row["name"] for row in pt.artist_table()
if row["origin"] == "core"})
assert len(names) == 43
# help(c.add_scatter) -> the scatter artist's full docstring
Make it yours
A plot type is a single registered function —
no classes to subclass. pt.add_artist plus a draw function
gets a new mark onto every chart, with the draw.* helpers
emitting the SVG. The ~45 artists in
plotlet-extensions
are each one file built exactly this way — read
docs/EXTENDING.md
and copy one.