Skip to content

Publish the figures the how-to guides describe - #172

Open
bjlittle wants to merge 14 commits into
mainfrom
docs-published-figures
Open

Publish the figures the how-to guides describe#172
bjlittle wants to merge 14 commits into
mainfrom
docs-published-figures

Conversation

@bjlittle

Copy link
Copy Markdown
Owner

What this does

Neither how-to guide showed a picture of what it teaches. Both now publish the
figures their own snippets produce, rendered from those snippets by the
documentation build rather than described in prose.

Every python block on a page that publishes figures is a .. plot::, so the
block a reader is invited to copy is the block that drew the picture above it.
Eleven figures are published across howtos/emphasis.rst and howtos/logo.rst.

How they are kept from breaking

Each published image is compared against an approved baseline in
docs/baseline/ on every documentation build, keyed on the name its block
declares. A change in what a snippet draws fails the build rather than reaching
the published page unnoticed. Re-approve an intended change with
pixi run docs-figures, which reports the RMS of every image it updates.

Three properties make that gate trustworthy rather than decorative:

  • pixi run docs is a clean build, so _build/html/_images holds this build's
    output and nothing else — never "matched a baseline once".
  • The gate is keyed on :filename-prefix:, not on a per-document counter, so
    inserting a section does not renumber every image after it.
  • It runs in the one environment that builds the figures, and the baselines are
    pruned from the sdist.

The rules are written down in the "Published Figures" section of
docs/src/developer/docs-style.rst, specified in
docs/src/developer/specs/2026-08-17-published-figures-design.md, and enforced
by .github/scripts/check_docs_figures.py plus the existing snippet gate.

Notes for the reviewer

  • Look at the figures, not only at the diff. A gate compares an image to its
    baseline; nothing here can tell you the baseline shows what the paragraph
    above it claims. Two figures on this branch were blessed from a wrong render
    and caught only by eye.
  • This adds a fourth gate to ci-docs, so the count in pixi run docs reproduces two of CI's three documentation gates #171 is now three of
    four rather than two of three. That issue's question is unchanged.
  • One block in howtos/logo.rst carries :nofigs: and says in prose why: under
    a dark matplotlib style the inline isopleth labels sit in pale boxes chosen
    against a white canvas, so they cover the diagram they label. The logo itself
    is correct there; the figure around it is not.

🤖 Generated with Claude Code

bjlittle and others added 13 commits August 17, 2026 21:35
The two how-to guides that teach a visual API — "Emphasise a Reference
Isopleth" and "Add the tephpy Logo" — show no picture, and nothing in
the project renders a figure from source. The plan that wrote the
emphasis guide deferred the decision, correctly, because adding a Sphinx
extension is a documentation-wide choice rather than a step in a feature.

This is that decision: `matplotlib.sphinxext.plot_directive`, a page
shape that keeps each guide a session rather than a catalogue, and two
gates — the docs spec §3.9 snippet gate learns the directive, and a new
docs-side gate compares what the build published against a baseline.

Records why converting `howtos/configuration.rst` is not on the table:
`plot_directive` executes every block in the Sphinx process, and that
page's `tephpy.config.save()` would write into the home directory of
whoever ran the build.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds the extension and its settings per plots spec §3.1, §3.3 and §4. No
page carries a `.. plot::` yet, so the build renders no new figures — the
correct outcome for this step. Verified with `pixi run --frozen docs`
(build succeeded, no warnings, both existing gates green) and a throwaway
`.. plot:: :nofigs:` probe (reverted before this commit) confirming
`plot_working_directory` redirects a snippet's file writes to
`docs/_build/plot-scratch/` rather than the checked-out source tree.

`plot_rcparams` carries the figure size only, not plots spec §4's full
recipe: rendering the logo how-to's figure-anchored placement section both
ways shows that `add_logo(fig, ...)`'s `AnnotationBbox` is invisible to
matplotlib's tight-bbox measurement and is cropped away entirely under
`savefig.bbox: "tight"`, while an axes-anchored logo survives. That
section is exactly what a later task converts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Extend tests/test_docs_snippets.py to recognise `.. plot::` alongside the
existing code-block spellings (plots spec §3.4), and add the page-shape
checks of plots spec §3.2: a page publishes figures or it does not, the
first block resets the session, later blocks continue it, every figure
is named and named once, and no plot renders from a file.

Convert docs/src/howtos/emphasis.rst to publish its figures, replacing the
bare tephpy.config assignment with tephpy.config.context (plots spec §3.3)
so the demonstration cannot leak into a page built afterwards.
Convert docs/src/howtos/logo.rst to matplotlib.sphinxext.plot_directive per
plots spec §3.2: five sections publish a named figure, and three blocks --
the dark-background variant, the transparent savefig, and the removal --
carry :nofigs: because their pictures are unwanted for reasons of their own,
not because they are untested.

Extend PUBLISHES_FIGURES in tests/test_docs_snippets.py so the same
page-shape checks that already govern the emphasis how-to apply here too.

Split the dark-background rationale so the published page carries only what
a how-to reader needs: that the block renders no picture because the inline
isopleth labels are unreadable on a dark canvas. The maintainer-facing detail
-- the specific constants, the source path, and the instruction not to drop
:nofigs: without publishing the fix's acceptance-test figure -- moves into a
reStructuredText comment at the point of use, where it never renders.
Names `docs-check-figures` as its own CI step, after the link check and
before the network-reaching steps, so the figure gate reaches `ci-docs`
by being named rather than merely depended upon by the local `docs` task.
Extends the workflow's own task-name gate to match, and prunes
`docs/baseline` from the sdist alongside the scripts that exercise it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`plot_apply_rcparams` was described as staying at its default, when
matplotlib's own default is `False`: it is a seventh changed default, not
one that held steady, and the spec is rewritten so deleting it on the
spec's own authority would no longer read as a no-op.

The companion-changes list also attributed a sentence to spec §8.6 that
lives only in this document's own §1, and mischaracterised it as having
stopped being true when it is already past tense and still is. Reworded
so the attribution is right.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
docutils lowercases directive option names, so ':Filename-Prefix:' is a
real declaration and not a typo, yet DECLARATION and the case-sensitive
CANDIDATE both missed it: the figure was published, unpinned, and never
reported. CANDIDATE gains re.IGNORECASE -- wide detector, narrow
validator -- so the variant now surfaces as a reported near miss instead
of silence. DECLARATION stays case-sensitive; widening it would accept
the variant rather than report it.

MALFORMED's advice is extended from two shapes to three, and MISSING's
advice gains the second cause of a declared-but-unbuilt figure: a block
that leaves two figures open publishes '<prefix>_00.png' and
'<prefix>_01.png' and never the bare name.

Add a test proving the case-variant is reported; reverting the
re.IGNORECASE addition and re-running the suite fails only that test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
logo-restyled's point is logo.set_zorder(0) -- "behind the isopleths
rather than over them" -- but at alpha=0.6 in the default loc="lower
left" the logo sat under the densest isopleth labelling and was barely
discernible, so the effect the section exists to show was not legible.

Same defect class the branch's last commit fixed for
logo-size-and-form, and the same fix: loc="upper left" is legible
ground already proven there. Re-blessed with 'pixi run docs-figures';
only docs/baseline/logo-restyled.png changed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`loc="upper left"` moved the logo out of the tangle it was buried in, but
at the default size the wordmark was still barely discernible against the
isopleths it sits behind, so the section's one point — `set_zorder(0)`
putting the logo under the lines rather than over them — was not visible
in its own picture.

`size="large"` is what makes it visible. The overlap is the point here and
is not something to place the logo clear of: the isotherm and isobar
labels crossing the wordmark are exactly what a reader has to see to know
the logo is behind them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions github-actions Bot added type: documentation Auto-labelled for doc/* and docs/* branches type: ci Continuous integration type: testing Auto-labelled labels Aug 19, 2026
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.83%. Comparing base (9348608) to head (8b84093).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #172   +/-   ##
=======================================
  Coverage   97.83%   97.83%           
=======================================
  Files          20       20           
  Lines        2497     2497           
  Branches      351      351           
=======================================
  Hits         2443     2443           
  Misses         29       29           
  Partials       25       25           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: ci Continuous integration type: documentation Auto-labelled for doc/* and docs/* branches type: testing Auto-labelled

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants