Chart Data Table (chart.data_table)¶
An optional mini data-grid attached to a chart, with columns
pixel-aligned to the chart's x-axis ticks. The strip position is
controlled by style.charts.data_table.position (top or bottom);
the default is top (strip above the plot, Excel-style). Direct Excel
analogue: "Chart Element → Data Table."
chart: type: bar x: month y: revenue data_table: - source: sample_size format: ",d" label: "n" - aggregate: sum source: revenue format: currency_compact label: "Total"
Each list entry is a row. Columns align to the chart's x-axis ticks.
When label: is omitted on a source or aggregate row, the row stub is derived
from source: (successful_launches renders as Successful Launches).
Missing, non-finite, or invalid cell values render as a regular dash (-), not as
JavaScript sentinel text such as NaN or null.
When format: is omitted on a row that reads the chart's primary measure column,
the strip inherits chart.format so the chart and strip do not show the same
measure with different number formatting.
The unit is stated once, not on every cell¶
When a row's format: is a predefined name that carries a unit — such as
currency_compact or percent — the strip
states that unit on its leftmost cell and leaves the rest bare, so the row
reads as one measurement instead of repeating itself:
The whole row shares one magnitude, chosen from its own values, so cells never
disagree about scale the way per-cell formatting can (993k beside 1.0M).
A row whose values outgrow that magnitude repeats the suffix on every cell;
a currency symbol is still stated once, since repeating it disambiguates
nothing.
Nothing is authored for this — the unit comes from the format: you already
write, and a format naming no unit is untouched. Four shapes keep the older
per-cell spelling, because the leftmost painted cell either cannot be
identified or should not carry the extra glyph:
| Shape | Why |
|---|---|
a raw d3 format literal (e.g. "$.2s") or a style.formats alias |
only engine-predefined format names engage the anchor |
an authored sort: on a category axis |
replaces the data order the leftmost cell is read from |
| a quantitative x axis | continuous, so the leftmost band is not the first row |
| a currency format on a left-oriented y-axis | prefix cannot anchor without disappearing from non-anchor cells |
Orientation determines which side the affix hangs.
For a right-oriented y-axis the affix leads the digits and hangs into the
y-axis gutter. For a left-oriented y-axis, suffix-only formats (SI without a
currency prefix, percent) hang the suffix into the anchor cell's own band so
every other cell's left digit edge stays in one lane. Currency formats (which
carry a leading prefix) revert to per-cell spelling on a left-oriented axis so
the symbol always appears. axis_y.position defaults to auto and resolves
to left whenever a chart draws endpoint labels, which multi-series line, area,
and bar charts do by default.
Entry shapes¶
Two shapes, one of each per list entry:
| Shape | Keys | When to use |
|---|---|---|
| Source row | source: (required), format:, label: |
Read a raw per-x value from a query column. label: defaults from source: when omitted. |
| Aggregate row | aggregate: + source: (both required), format:, label: |
Compute a per-x aggregate across other dimensions (e.g. segment-stacked bars). label: defaults from source: when omitted. |
Supported aggregate operations¶
sum, avg, min, max, median, count, count_distinct. Exact
names — no aliases.
Supported chart types (v1)¶
bar, line, area.
Every other chart type (pie, donut, scatter, kpi, table,
arc, waterfall, etc.) rejects the data_table: block with a
compile error. Layered charts and charts with a multi-field y: list
are also rejected — the attached strip needs a single unambiguous
x-encoding.
Rules¶
source:alone is valid only when the query returns at most one row per x-value. On stacked/grouped charts, useaggregate:to resolve — the renderer errors with a pointer ataggregate:if a baresource:is ambiguous.aggregate:always requiressource:.source:must reference a column present in the chart's query output.- Maximum 40 x-axis ticks (the chart's x-cardinality, not the
number of
data_tablerows). Aggregate or filter in the query before rendering. - Duplicate entries (same
source:+aggregate:combination) reject at compile time. - On dense time-like ordinal axes, strip cells thin to the same visible tick
cadence as the axis. This covers both authored coarser label cadences
(for example monthly bars with quarterly labels) and runtime
labelOverlap: parityculling on narrow bucketed-time bar charts. - Entries render in list order from the row adjacent to the plot outward:
top-to-bottom for
position: bottom, bottom-to-top forposition: top(the default). The row closest to the plot always corresponds to the first entry in the authored list.
Styling¶
Themeable at three tiers, each merging into the next:
style.charts.data_table.*— universal defaults.style.charts.<chart_type>.data_table.*— per-chart-type override.chart.style.data_table.*— per-chart authored override.
Styleable leaves: font, divider, row, label,
padding_top, padding_bottom, position.
Value cells align toward their row labels automatically: a left-side y-axis (labels on the left) left-aligns the values, a right-side axis right-aligns them. There is no separate alignment knob.
position accepts "top" (strip above the plot, default) or
"bottom" (strip below the plot, legacy layout). Override at any
tier to keep below-plot placement:
chart: style: data_table: position: bottom # legacy below-plot layout for this chart
No column-header row exists on data_table. The divider: block
styles a single rule drawn between the plot and the strip —
rule-only, not a header row.
style: charts: data_table: font: size: 11 divider: width: 1 label: align: left position: top # default; set bottom for below-plot legacy layout bar: data_table: font: size: 10 # tighter for dense bar charts