Publish the figures the how-to guides describe - #172
Open
bjlittle wants to merge 14 commits into
Open
Conversation
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>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 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. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 theblock a reader is invited to copy is the block that drew the picture above it.
Eleven figures are published across
howtos/emphasis.rstandhowtos/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 blockdeclares. 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 docsis a clean build, so_build/html/_imagesholds this build'soutput and nothing else — never "matched a baseline once".
:filename-prefix:, not on a per-document counter, soinserting a section does not renumber every image after it.
pruned from the sdist.
The rules are written down in the "Published Figures" section of
docs/src/developer/docs-style.rst, specified indocs/src/developer/specs/2026-08-17-published-figures-design.md, and enforcedby
.github/scripts/check_docs_figures.pyplus the existing snippet gate.Notes for the reviewer
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.
ci-docs, so the count in pixi run docs reproduces two of CI's three documentation gates #171 is now three offour rather than two of three. That issue's question is unchanged.
howtos/logo.rstcarries:nofigs:and says in prose why: undera 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