Add CSS-first styling and selectable PNG engines - #45
Merged
Conversation
Alek99
force-pushed
the
feat/css-first-customizability
branch
from
July 14, 2026 21:43
6fdd045 to
404ce4e
Compare
Alek99
marked this pull request as ready for review
July 14, 2026 22:31
Merging this PR will degrade performance by 85.49%
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing Footnotes
|
FarhanAliRaza
pushed a commit
that referenced
this pull request
Jul 15, 2026
Two regressions from #37 kept CI red on main and every open PR: Hexbin (benchmarks/test_codspeed_kernels.py::test_first_payload_hexbin_core_2d): _emit_hexbin expanded every cell into six fan triangles across seven f32 columns (168 B/cell — 3.17 MB at gridsize=128, 2x the raw input; #45 had loosened the benchmark bound to accept it). Hexagons all share one geometry, so ship centers plus one color value per cell (12 B/cell, 227 KB) and expand locally in each renderer: instanced triangles in the WebGL client (_buildHexbinMark), one polygon per cell in SVG, vectorized triangles in the raster exporter. Headless-Chromium readback is pixel-identical to the old wire shape. The benchmark bound is restored to grid-bounded centers. Perf guardrail (tests/pyplot/test_perf_guardrail.py, 10k case): pyplot's fixed per-build cost had grown to ~2x the declarative baseline locally. Removed per-build revalidation and O(n) temporaries: - styles.compile_axis_style / compile_mark_style and _validate.style_mapping now memoize per exact input dict — the same few rc-derived chrome dicts were re-parsed through the native CSS grammar on every build. - The rc chrome snapshot (_load_rc_chrome) is cached per (RcParams.version, dpi); RcParams now versions its mutations. - plot() gap/path detection drops an astype copy + diff + compare for the native is_sorted kernel and skips the isfinite mask entirely for clean data via a sum probe (non-finite anywhere poisons the sum). Local ratio at 10k: 2.03x -> ~1.6x; 100k: 1.26x. Full suite, ruff, ty, render smoke pass; hexbin WebGL/SVG/PNG verified.
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 changed
fill,stroke,stroke-width, independent fill/stroke/whole-mark opacity, gradients, dashes, and border radiuspxnormalization, separate tick/tick-label paint, and grid dash/opacity supportmark_stylestate schema so Reflex remains responsible for reactive state and eventsEngine.defaultandEngine.chromiumfor PNG export, with native export as the fast default and automatic installed-browser discovery for browser/CSS fidelitycustom_css=for Chromium single and batch PNG export; native export rejects browser-only author stylesheetsvar(--accent)in native SVG/PNGFacetChart.to_png()forwardingglto aFacetGridsignature that previously did not accept itWhy
XY should accept familiar CSS vocabulary that Reflex users and LLMs already understand instead of introducing an XY-specific styling language or duplicating Reflex conditions, event handling, and application state.
PNG export has a simple tradeoff: a millisecond-scale native default for normal use, plus an explicit Chromium engine when browser CSS, fonts, and WebGL fidelity matter.
User impact
For mark
style={...}, usestrokeon line-like marks andfillon filled marks. The legacycolor=argument remains supported, butcoloris not a CSS paint alias insidestyle.Axis
style={...}now rejects unknown keys and invalid colors, directions, opacities, or lengths when the axis is created. Pixel properties accept numbers or values such as"3px".Migration
MarkStyle/mark_style(...)are removed; interaction styling stays in Reflex state, conditions, events, and ordinary CSS.Engine.default(native). UseEngine.chromiumfor the installed-browser path.XY_BROWSER.custom_css=is Chromium-only for PNG export.Review follow-ups addressed
colorbar(show=False)clears generated colorbar optionsstroke_perimeter=Falseis strictly validated as a booleanValidation
ruff check .ruff format --check .ty checkscripts/check_public_api.pyKnown baseline CI noise
The remaining red checks were reproduced unchanged on current
mainand are not caused by this PR:tests/pyplot/test_perf_guardrail.py::test_pyplot_build_tracks_declarative[10000-60-1.6]test_first_payload_hexbin_core_2dpayload assertion