Report rendering: serology halo + native multiple_circles + fully-vector single-canvas signature page - #34
Open
drserajames wants to merge 6 commits into
Open
Report rendering: serology halo + native multiple_circles + fully-vector single-canvas signature page#34drserajames wants to merge 6 commits into
drserajames wants to merge 6 commits into
Conversation
Switch the multiple-serum-circles addenda map render from kateri (driven over its unix socket, one session per lab) to the native headless renderer, mirroring ae.report.map_renderer.NativeRenderer. render_pdfs now writes the in-memory styled chart to a short-lived temp .ace and renders each named style from it in one ae_backend.map_draw.export_styled_maps call (chart loaded once) — no kateri process, no socket, Linux-capable. Each style resolves its own on-chart c["R"] named style + c["p"] base plot-spec, including the per-lab square viewport set by build_styles, exactly as kateri's set_style + get_pdf(square=True) did. The recent map-draw serum-circle fill fix means the theoretical circles' translucent (#AARRGGBB) clade-colour fills now render natively. The -names pdflatex overlay step is unchanged (it runs on top of the natively-rendered circles map). Removed the now-dead asyncio import, the ae.utils.kateri dependency and the _kateri_app_bundle helper. Verified on h3-hint-cdc: the three PDFs render with no kateri process, and native vs a same-config kateri render matches at the anti-aliasing floor (~1.5% of pixels at fuzz 30%, dominated by grid-line sub-pixel offset, point-edge AA and title-font differences; map content and translucent circle fills match). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The native renderer stroked point-label text halos with a round line join, but kateri (draw_on_pdf.dart) leaves the PDF-default MITER join in place for its halo stroke pass. Round bevels glyph terminals and under-covers the halo band relative to the golden. Switch text_font's halo stroke to MITER so the label halo matches kateri exactly. Scope limited to text_font (the semantic point-label path); text() and text_rotated() keep their round join to avoid untested impact on the tal-draw / geo-draw halos that share those primitives. Verified against the p2-fidelity harness (serology + by-clade maps): the by-clade fuzz30 residuals are unchanged (no regression); serology strict AA counts drop marginally. The remaining serology-vs-golden residual is a font rendering floor (see investigation notes), not a geometry gap. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eri) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Draw the signature page's tree (left) and per-section antigenic maps (right)
as VECTORS onto ONE shared cairo_pdf_surface — no PNG tiles, no kateri, no
pdfjam/pdflatex.
Shared-context refactor (transparent to the existing file-output path):
- cc/draw/cairo-surface.{hh,cc}: add a borrowed-context CairoPdf constructor
that targets a device sub-rectangle of a caller-supplied cairo_t (translate
+scale+clip); the destructor only restores, never destroys. File-bound
constructor unchanged.
- cc/map-draw/styled-draw.cc: factor the per-map compute+draw behind a surface
factory; export_styled_map(..., output) keeps byte-identical file output,
new export_styled_map_into(..., context, rect) letterboxes the map into a
shared sub-rect.
- cc/tal/draw-tree.cc: same factoring; export_tree_pdf (file, unchanged) +
export_tree_into (shared sub-rect).
Compositor + wiring:
- cc/tal/sig-page.{hh,cc}: SigPageCanvas owns one PDF page and renders the
section maps (chart loaded once) + tree into their computed rects as vectors.
- cc/py/sig-page.cc: ae_backend.tal.SigPageCanvas binding (registered in
module.{cc,hh}); meson links the tal tree renderer + geo continent sources
into ae_backend so the binding can reach both renderers.
- py/ae/tal/signature_page.py: make_section_signature_page_native drives one
SigPageCanvas from the ported auto-width geometry; make_section_signature_page
now defaults to this native vector path (native=False = legacy kateri/pdfjam).
Verified: standalone export_styled_map / tal-draw / geo-draw file output is
pixel-identical to pre-refactor (AE=0 each); a real ~8-section page composes on
one canvas, page size within ~2% of the pdfjam baseline.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The fully-vector signature-page compositor drifted vs the report's signature
pages in text size/weight and page size because two driver-side geometry rules
did not reproduce the LaTeX compose_grid (keepaspectratio) path they port.
1. Tree render size. make_section_signature_page_native rendered the tree at the
panel height in points (round(th)) and placed it 1:1. The tree renderer clamps
fonts/line-widths to ABSOLUTE device bounds, so it does NOT scale linearly with
image_size: rendering at the small panel height makes those clamped glyphs/lines
proportionally larger (bolder tree, drifted label spacing) than the baseline,
which renders at 1000 and optically scales down. Render at the same internal
size the baseline uses (size or tal_size or 1000) and let export_tree_into
letterbox-scale it (vector, lossless); the tree page aspect equals the panel
aspect, so it still fills the panel exactly.
2. Page size. _sig_page_layout used exact fractional mm while compose_grid rounds
the LaTeX paper to whole mm ({:.0f}mm). Round the composed page to whole mm so
the page aspect — hence the scale pdfpages applies embedding the sig page onto
the report's A4 pages — matches the baseline and text lands at the same absolute
size in the assembled report.
Both changes are confined to the Python driver; no cc/ file is touched, so the
standalone export_styled_map / tal-draw / geo-draw file renderers are byte-identical
(AE=0 by construction; module not rebuilt). Verified on bvic-niid (8 sections):
composed page 926.929x572.598 pt = the live compose_grid path exactly; aa-label
glyph height 5.23 pt vs 5.22 pt baseline (0.2%); tree span within 0.2% of the live
LaTeX fit. Doc updated (SIG-PAGE-COMPOSITOR.md §5/§6) incl. the residual uniform
~10 pt minipage[t]/topskip offset (shifts tree+maps together, re-centred by pdfpages
in the A4 report) and the stale-baseline note.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Report-rendering follow-ups: serology halo, multiple_circles native, and a fully-vector single-canvas signature page
Bundles three independent follow-ups on the now-default native map renderer. All build together; the standalone
map-draw/tal-draw/geo-drawfile outputs are verified pixel-identical tomain(content AE=0), so nothing regresses the merged native default.1. Serology label-halo miter join (
cc/draw/cairo-surface.cc)Point-label halos used a round line join; kateri uses the PDF-default miter join. Switched
text_font's halo to miter (scoped totext_font;text()/text_rotated()unchanged). A genuine fidelity alignment; the serology-map residual itself is a font-rasterisation floor (native renders true embedded bold; the harness rasteriser degrades the golden's non-embedded bold) — not a geometry gap.2.
multiple_circlesrenders natively (py/ae/report/multiple_circles.py)The multiple-serum-circles addenda no longer drive kateri:
render_pdfs()writes the styled chart once and renders every style viaae_backend.map_draw.export_styled_maps. No kateri process; the translucent theoretical-circle clade fills now render (via the recent#AARRGGBBfill fix); the-namespdflatex overlay is preserved. Matches kateri at the AA floor (≈1.5–1.6%).3. Fully-vector single-canvas signature page (
cc/tal/sig-page.*,cc/map-draw/,cc/tal/draw-tree.*,cc/draw/cairo-surface.*,py/ae/tal/signature_page.py)Signature pages composed the tree + section maps as separate PDFs stitched with pdfjam, maps rendered by kateri. This renders the tree and every section map as vectors into one shared Cairo PDF surface — no kateri, no pdfjam, no PNG tiles.
CairoPdfconstructor targets a device sub-rectangle of a caller-suppliedcairo_t(translate/scale/clip; borrows, never destroys). Existing file-bound constructor untouched.export_styled_mapand the tal tree render factored so each has a file entry point (byte-identical output) plus an_into(context, rect)entry point.SigPageCanvas(bound asae_backend.tal.SigPageCanvas) owns onecairo_pdf_surfaceand draws maps + tree into their computed rects;signature_page.pydefaults to this native vector path (kateri/pdfjam kept asnative=Falsefallback).Notes