Wire config-driven chart aspect ratio and document layout sizing
Problem
dataface/core/compile/default_config.yml already declares chart.aspect_ratio, but it is not applied in the sizing or render pipeline, so behavior diverges from documented intent. Meanwhile, product CSS (for example apps/playground/static/playground.css) hardcodes aspect-ratio values such as 16 / 9, which violates the policy of keeping tunable behavior in YAML config rather than scattered literals in code. End-user docs (for example docs/docs/boards/sizing.md) state that heights follow “content or chart type aspect ratios,” which is not an accurate description of current implementation for most chart types (they use a fixed default height today). Authors and implementers need one clear story: what drives height for plot charts vs KPI vs tables, and where defaults live.
Context
- Current height policy (compile/sizing):
get_chart_content_heightuses a fixedDEFAULT_CHART_HEIGHTfor most chart types, a fixed KPI height, and data-aware height for tables. It does not compute height fromwidth × aspect_ratiofor standard Vega-Lite charts today. - Layout items:
LayoutItem.aspect_ratioincompiled_types.pyis derived after layout ascalculated_width / calculated_heightfor responsive rendering metadata—not the same as a target aspect ratio from config. - Related design task: discuss-authored-chart-width-height-and-aspect-ratio-controls.md covers author-level YAML overrides and Vega-Lite pass-through. This task focuses on wired defaults from global config and per-chart-type config, plus documentation accuracy. Author overrides can follow in a later task once defaults and layout rules are solid.
Goals
- Single source of truth: All default and per-type target aspect ratios for plot-style charts live under
default_config.yml(and merge with structure/theme overrides per existing config rules). No magic numeric aspect ratios in Python or product CSS for chart chrome unless documented as non-tunable presentation constants. - Per-chart-type defaults: Support a global default (for example
chart.aspect_ratio) and overrides underchart_types.<type>(for example squarer defaults forpie/donut/arcif desired). Types that should not use aspect-based sizing (KPI, table, markdown-heavy content) must be explicitly excluded with a documented policy. - Consistent pipeline: When aspect applies, layout height (or equivalent) for a chart slot should be consistent with the allowed width for that item in its layout context (rows/cols/grid), subject to documented rules for same-row height in
cols, min/max height from config, and interaction withuser_heightwhen set. - Vega-Lite alignment: Rendered spec dimensions should remain consistent with the resolved layout box (avoid reintroducing layout-vs-spec mismatch; see related discuss task).
- End-user documentation: Update
docs/docs/boards/sizing.md(and any linked guides) so they accurately describe width splitting, height rules, aspect defaults, KPI/table behavior, and optional author controls once implemented.
Non-goals (for this task)
- Full chart-level authored
width/height/aspect_ratioin board YAML (tracked by the related discuss task once designed). - Changing mdsvg image fallback aspect defaults unless required for chart layout (separate library surface).
Plan
- [x] Schema: Per-type
aspect_ratioadded underchart_types.<type>indefault_config.yml— matches existing conventions. Globalchart.aspect_ratio: 1.5already existed. - [x] Sizing: Extended
get_chart_content_heightwithwidthkwarg; computeswidth / aspect_ratiofrom config for plot-style charts, clamped tomin_height/max_height. KPI, table, spark_bar excluded via_NON_ASPECT_TYPES. - [x] Render: Audited
spec_builders.py—set_chart_dimensionsalready passes through the layout-resolved width/height to Vega-Lite specs withautosize: fit. No changes needed; aspect-driven heights flow through the existing pipeline. - [x] De-hardcode: Replaced
aspect-ratio: 16 / 9in playground.css with3 / 2matching config.suite.cssaspect-ratio values (1:1 for icons/tiles) are non-tunable presentation constants, documented as such. - [x] Audit: Grepped for aspect literals. Playground example-thumbnail ratios (5/3, 2/3) are gallery layout, not chart config. No other chart-path aspect literals found.
- [x] Tests: 6 new tests in
TestAspectRatioDrivenSizing: global default, KPI exclusion, table exclusion, per-type override, min/max clamping, cols layout integration. - [x] Docs: Rewrote height rule in
sizing.md, added Configuration table pointing todefault_config.ymlkeys.
Implementation Progress
Changes made
-
dataface/core/compile/default_config.yml— Addedaspect_ratiotochart_types:arc,pie,donut→ 1.0 (square);geoshape,map,choropleth→ 1.2 (slightly wide). Globalchart.aspect_ratio: 1.5was already present. -
dataface/core/compile/sizing.py—get_chart_content_heightnow acceptswidthkwarg. For plot-style charts, computesheight = width / aspect_ratiofrom per-type or global config, clamped to[min_height, max_height]. Added_NON_ASPECT_TYPESfrozenset. Caller_get_item_content_heightpasses width through. -
apps/playground/static/playground.css— Changed.chartaspect-ratio from16 / 9to3 / 2to matchchart.aspect_ratio: 1.5. -
docs/docs/boards/sizing.md— Rewrote height rule with accurate aspect-ratio description, KPI/table/spark_bar exceptions, min/max clamping. Added Configuration table. -
tests/core/test_sizing.py— AddedTestAspectRatioDrivenSizingclass with 6 tests.
QA Exploration
- [x] N/A — this task changes backend sizing logic and CSS defaults. The sizing pipeline is covered by unit tests. Visual QA of rendered output is out of scope for this config-wiring task (no new UI surfaces).
Review Feedback
- [ ] Review cleared