Gallery¶
python examples/gallery.py builds these nineteen figures and audits each one.
The script exits non-zero if any figure fails, so they are regression tests with
pictures attached rather than decoration.
They exist because demo.py, one panel and three curves, is easy for a gate to
pass, and passing an easy case is the wrong thing for a gate to be good at.
These are the compositions where a check has somewhere to hide. Writing them
found nine defects in the checks themselves, and four in the figures that no
check caught. Both kinds are listed at the end of this page.
Every alt text here is the string the figure itself carries, passed to
describe(fig, ...) before the audit runs, so the alt-text gate reads it.
Shared scales¶
A filled field¶
No axes at all¶
ax.axis("off"). A figure with no data and no visible tick labels is the case most gates were not written against.Three statistical forms¶
Log-log, with a slope triangle¶
Density as the finding¶
Three encodings¶
A band around each curve¶
venue="neurips", placed_frac=0.75 measures the type and stroke floors at the 0.90x it prints at.Counts, and a second unit for them¶
check_dual_axis exists to permit: secondary_yaxis derives its ticks from the left scale, so the two cannot drift apart the way a twinx with hand-set limits silently can.A signed field¶
contour.negative_linestyle defaults to dashed, so a monochrome contour over signed data ships its negative half dashed with nobody having chosen it, and dashing here means unobserved or projected.Marks, then bins¶
A callout that points¶
Two scales for one quantity¶
fig.axes, so ticks the locator placed outside its own view were read as clipped text rather than as ghosts.A survival curve¶
ax.step keeps the points it was handed and draws risers between them, so the drawstyle has to be expanded before any geometry is harvested; read raw, the label and banking rows measure the diagonal chord of each riser instead of the two segments actually drawn.A spike raster¶
eventplot draws an EventCollection, which reports one linewidth where every other collection reports a sequence. The line-weight gate called list() on it and raised TypeError, which _rows turns into a hard fail: a legal figure failing on a defect in the checker.A direction, on the projection it belongs on¶
Predicted against observed¶
Boundaries named along themselves¶
A field with its own significance¶
float() raises on one. The contrast-stack row reads the array rather than the scalar for exactly this figure, counting a ramp across one artist as a single alpha decision; counted per cell it reports sixteen levels of haze and fails a figure that made one choice.Why figures ten to thirteen exist¶
The first seven figures were audited against every gate, and the detail strings
showed which rows had never measured anything. Five had not. No figure drew a
confidence band, a bar, a diverging colormap, a signed contour set, or a
scatter, so those rows returned a passing detail seven times over without once
running the code that decides.
A row that passes by having seen nothing looks exactly like a row that passed. That is the blind spot how the checkers decide names, and this page had been an example of it.
Why the last six exist¶
The same question, asked mechanically rather than by eye. Run under coverage,
the thirteen figures above never reached a rotated label's oriented box, a
LineCollection's widths, a step drawstyle, a polar axes, a per-point alpha
array, or the equal-radii path in the overplotting gate: 281 statements of
check_figure.py that no figure here could speak for.
Each of the six is a form a reader would recognise before it is a branch, which
is the order that matters. A figure drawn to reach a line of code is not
evidence about anything. They took the 281 down to 239, and two of them found
defects in the checker on the way in. main also audits the sheet's own
palette with check_palette, which no figure exercises: that took the second
module from 74% to 82% on the same measurement.
The nine defects in the checks¶
- The readability gate reported a schematic's invisible tick labels.
check_inkcalled every colorbar a saturated panel.- The line-weight gate measured a colorbar's own dividers as hairline strokes.
- A path and its start marker in one hue read as a wrapped color cycle.
- Testing a label's backdrop against its dominant color failed every annotation ever placed on a heatmap.
check_label_attributionpassed labels in the right margin that sat 29px from their own curve and 35px from a neighbour's. A label outside the data is not resolved by proximity to anything._enclosestested a band's outline through the affine part of the transform only, so on a log axis a confidence band stopped being its own curve's band and became its rival.check_line_weightraised TypeError on anEventCollection, which reports one linewidth where every other collection reports a sequence.check_label_attributioncounted a curve's own censoring ticks as a rival series. A companion mark drawn along its curve, in its curve's colour, sits 0px away by construction, so no placement of the label could clear it.
The four defects no check caught¶
- The schematic's feedback arrow ran off the bottom of the canvas.
- The convergence plot's slope triangle sat in the only corner its direct labels could use.
- The survival curves stopped at the last event, leaving their tail censoring ticks floating with no line beneath them.
- The regime diagram's boundary labels were rotated by the slope in the data rather than the slope on the page. On log axes those are different numbers, and both strings came out flat beside a rising curve.
All four were obvious in the PNG and invisible to every check. They are why the procedure has a step that says to render the figure and look at it.
The figure the checker is supposed to fail¶
python skill/scripts/check_figure.py with no arguments builds a deliberately
broken figure and audits it, so the self-test proves the gates can fail rather
than only that they can pass.
python examples/demo.py, with every decision commented against the failure it avoids.