Skip to content

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:

$441mn   448   456   464   473   483   493   505   516            Goal
5.5%     6.2   6.4   7.1   7.8   8.5   9.3   11.2  13.4           Goal

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, use aggregate: to resolve — the renderer errors with a pointer at aggregate: if a bare source: is ambiguous.
  • aggregate: always requires source:.
  • 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_table rows). 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: parity culling 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 for position: 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:

  1. style.charts.data_table.* — universal defaults.
  2. style.charts.<chart_type>.data_table.* — per-chart-type override.
  3. 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