Dataface Tasks

Implement BI and editorial numeric notation families

IDGRAPH_LIBRARY-IMPLEMENT_BI_AND_EDITORIAL_NUMERIC_NOTATION_FAMILIES
Statuscompleted
Priorityp2
Milestonem2-internal-adoption-design-partners
Ownerdata-viz-designer-engineer
Initiativem2-semantic-type-behaviors
Completed bydave
Completed2026-03-24

Problem

Dataface currently exposes compact numeric formatting mostly through the Vega-Lite / D3 shorthand path, which is good for BI-style K / M / B output but does not capture the broader product decision now recorded in the docs: Dataface should support both BI notation (K / M / B / T) and editorial notation (k / mn / bn / tr) as coherent surface-fit display families. Without that work, narrative surfaces will either inherit BI formatting that is not the best typographic fit or drift into ad hoc suffix rules that break consistency across charts, KPIs, tooltips, tables, and annotations.

Context

  • Decision and background:
  • ai_notes/considerations/NUMERIC_NOTATION_AND_ABBREVIATION.md
  • docs/docs/guides/chart-design-notes.md (Note 52)
  • tasks/workstreams/graph-library/initiatives/m2-semantic-type-behaviors/decisions.md
  • Existing implementation entry points:
  • dataface/core/render/format_utils.py_format_si(), format_d3(), format_value(), format_kpi_parts()
  • dataface/core/compile/types.pyFormatConfig model
  • dataface/core/render/chart/decisions.py
  • dataface/core/render/chart/presentation.py
  • Callers of the formatting pipeline: kpi.py, table.py, vega_lite_types.py, pipeline.py
  • Existing behavior already assumes BI-style compact notation in multiple places through D3/Vega-Lite format strings such as ,.2s and ~s.
  • The implementation should keep raw numeric values unformatted in the data layer and apply notation at render time.
  • Scientific / SI notation is out of scope for this task except to preserve the architecture boundary that keeps it separate from BI and editorial notation.

Possible Solutions

Add a notation: Literal["bi", "editorial"] | None field to FormatConfig. Default to "bi" when using SI format (s type). Pass the notation through format_d3()_format_si() to select the suffix table.

  • BI suffixes: K, M, B, T (current behavior, default)
  • Editorial suffixes: k, mn, bn, tr

Trade-offs: Minimal change, backwards-compatible, notation choice is explicit in YAML config.

B. Separate preset families (compact-bi, compact-editorial)

Add new preset names like compact-editorial. Simpler but doesn't compose — users who use raw D3 ,.2s specs can't opt into editorial notation.

C. Global config-level notation default

Add chart.notation_family: bi to default_config.yml. Would require threading config through all format calls. Over-engineered for now.

Plan

Use approach A. Steps:

  1. Add notation field to FormatConfig in types.py
  2. Define suffix lookup tables in format_utils.py (BI and Editorial)
  3. Thread notation parameter through format_d3()_format_si()
  4. Update format_value() and format_kpi_parts() to extract and pass notation
  5. Write tests first (TDD), then implement
  6. QA: N/A (no UI — pure formatting logic)

Implementation Progress

  • Added notation: Literal["bi", "editorial"] | None field to FormatConfig in types.py
  • Added NOTATION_SUFFIXES lookup table in format_utils.py mapping family → {threshold: suffix}
  • Refactored _format_si() to use the table-driven lookup instead of hardcoded if/elif
  • Threaded notation through format_d3()_format_si(), format_value(), format_kpi_parts()
  • Added _get_notation() helper to extract notation from FormatConfig/dict inputs
  • 12 new tests covering BI default, explicit BI, editorial suffixes, negatives, below-threshold, FormatConfig/dict threading, KPI parts, backwards compatibility, and non-SI passthrough
  • All 145 existing + new tests pass, ruff + mypy clean

QA Exploration

  • [x] QA exploration completed — N/A, pure formatting logic with no UI surface

Review Feedback

  • [ ] Review cleared