plotlet v0.6.2

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.

← Color & themes