Skip to content

Regenerate diagram figures against 2.3.3, and make the generation reproducible - #273

Merged
dimitri-yatsenko merged 2 commits into
mainfrom
docs/reproducible-diagram-figures
Sep 10, 2026
Merged

Regenerate diagram figures against 2.3.3, and make the generation reproducible#273
dimitri-yatsenko merged 2 commits into
mainfrom
docs/reproducible-diagram-figures

Conversation

@dimitri-yatsenko

Copy link
Copy Markdown
Member

Closes #266.

#266 exists to re-verify the diagram figures and the notation spec once the renderer changes ship in a release. 2.3.3 is that release (datajoint-python#1533, #1534, #1544, #1545). Doing it surfaced two reasons the check it relies on could not be trusted, so this PR fixes those first and then regenerates.

What #266 asked for, and what it found

Step 1 — re-verify § Visual Encoding against the released package. Already correct. All five tier rows in reference/specs/diagram.md match _DIAGRAM_THEMES in released 2.3.3 exactly, fill/stroke/text. The renamed-FK amber #C77D3A matches too; its row label was corrected from "Orange line" in #272, which also noted it is deliberately distinct from the Computed tier's brand orange #FF5113.

Step 3 — confirm the collapsed-view prose. Unchanged, as #266 expected. It attributes no meaning to weight or line style on a collapsed edge, which stays true.

Step 2 — regenerate. One real change, and it is the one #266 predicted:

figure change
pipeline-modules-collapsed.svg reference → session edge: dashed → solid
pipeline-modules.svg none
imaging-schema.svg none

That is datajoint-python#1545: a collapsed edge no longer inherits the style of an arbitrary member of its foreign-key bundle, so bundle edges render uniformly. #266 guessed lab → session would be the visible one — right mechanism, wrong edge.

Why the diff is still large

The remaining ~440 lines are serialization, not the renderer. I verified that rather than assuming it: for all three figures the fill set, stroke set, node count, edge count and text labels are identical to the committed versions, and for the two unchanged figures the dasharray count matches as well. The tier palette already matched released 2.3.3, so no color moved.

The two reproducibility bugs this fixes

--check could not be relied on before this. One of the three figures failed against its own committed output about half the time.

1. Node emission order is hash-seeded. dj.Diagram iterates sets of table-name strings on its emission path (diagram.py:1210, :1251-1252), so node and cluster order follows str.__hash__, which Python salts per process. Two identical runs render the same picture and emit it in a different order:

result
two runs, default seed differ (88 lines)
two runs, PYTHONHASHSEED=0 identical
seed 0 vs seed 12345 differ

The script now re-execs itself with PYTHONHASHSEED=0 before importing datajoint, since that variable is only read at interpreter start. Filed upstream as datajoint-python#1551; the block is marked to come out when that lands. The real fix is sorted() at those call sites.

2. pydot was unpinned and its SVG writer changed between 3.x and 4.x — 4.0.1 drops the XML prolog and DOCTYPE, reorders <svg> attributes, drops cluster <title> elements, and emits literal spaces where 3.x emitted &#160;. Nothing visual, everything rewritten. Pinned to 3.0.4. #266 flagged this ("nothing pins pydot") as a known non-signal; it is now a pinned one.

After both, --check is clean and stable across repeated runs.

Also

The module docstring's "one collapsed edge is traversal-order dependent" caveat described pre-#1545 behavior and is replaced with the hash-seed caveat that is actually true now.

Reviewing this

The mechanism and the regeneration are separate commits, so 0eebe6c8 is readable on its own and 389f611c is the generated output.

Regenerated with DataJoint 2.3.3 from PyPI (not master), pydot 3.0.4, graphviz 15.1.0, PostgreSQL 15. To reproduce:

docker compose up -d postgres
createdb docs_diagrams   # or: docker compose exec postgres psql -U postgres -c 'CREATE DATABASE docs_diagrams;'
DJ_HOST=localhost DJ_PORT=5432 DJ_USER=postgres DJ_PASS=tutorial \
  DJ_BACKEND=postgresql DJ_USE_TLS=false DJ_DATABASE_NAME=docs_diagrams \
  python scripts/gen_pipeline_diagrams.py --check

`gen_pipeline_diagrams.py --check` exists to catch renderer drift in CI, but it
could not be trusted: one of the three figures disagreed with its own committed
output about half the time, for reasons unrelated to the renderer.

Two independent causes.

`dj.Diagram` iterates sets of table-name strings on its emission path, so node
and cluster order in the SVG follows `str.__hash__`, which Python salts per
process. Two identical runs render the same picture — same coordinates, colors
and edges — and emit it in a different order. The script now re-execs itself
with `PYTHONHASHSEED=0` before importing datajoint, since that variable is only
read at interpreter start. Filed upstream as datajoint-python#1551; the block
comes out when that lands.

`pydot` was unpinned, and its SVG writer changed between 3.x and 4.x — 4.0.1
drops the XML prolog and DOCTYPE, reorders `<svg>` attributes, drops cluster
`<title>` elements, and emits literal spaces where 3.x emitted `&#160;`. None
of it changes the rendering, all of it rewrites the file. Pinned to 3.0.4.

Also replaces the "one collapsed edge is traversal-order dependent" caveat in
the module docstring. That described pre-#1545 behavior, where a collapsed edge
inherited the style of whichever foreign key in its bundle was visited first;
bundle edges render uniformly as of DataJoint 2.3.3.
One notation change, and it is the one datajoint-docs#266 anticipated: in
`pipeline-modules-collapsed.svg` the `reference -> session` edge goes from
dashed to solid. Before datajoint-python#1545 a collapsed edge took the style of
an arbitrary member of its foreign-key bundle; now every bundle edge renders
uniformly. #266 predicted `lab -> session` would be the visible one — the
mechanism was right, the edge was not.

Everything else is pydot serialization, not renderer drift. Verified rather than
assumed: for all three figures the fill set, stroke set, node count, edge count
and text labels are identical to the committed versions, and for the two
unchanged figures the dasharray count matches too. The tier palette already
matched released 2.3.3, so no colors moved.

Regenerated with DataJoint 2.3.3 from PyPI, pydot 3.0.4 and graphviz 15.1.0.
`--check` is now clean and stable across repeated runs.
@dimitri-yatsenko dimitri-yatsenko added the documentation Improvements or additions to documentation label Sep 9, 2026
@dimitri-yatsenko
dimitri-yatsenko merged commit 3860587 into main Sep 10, 2026
2 checks passed
@dimitri-yatsenko
dimitri-yatsenko deleted the docs/reproducible-diagram-figures branch September 10, 2026 18:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Diagram figures and notation spec: re-verify and regenerate against each DataJoint release

2 participants