When to use report_matrix
report_matrix is the right choice when the audience needs a structured report with grouped rows, nested sections, subtotals, and group totals. It is designed for document-mode dashboards and PDF export, while still supporting click-to-filter inside interactive dashboards.
Use grid instead when the rows do not need grouping. Use a chart-style viz when the question is about a single metric across categories rather than a structured tabular report.
Mapping
report_matrix takes its column structure from the query result. There is no required mapping block; the matrix configuration lives under the matrix block instead.
Columns & presentation
These keys control which columns the matrix shows and how each column renders:
matrix.key_columns— array of column names rendered as key cells (bold, polarity-based coloring). Use for the metric column readers should focus on (e.g. attainment %, conversion rate).matrix.cross_filter— boolean, defaulttrue. Set tofalseto opt the matrix out of click emission (see Cross-filter behavior below).matrix.trend_columns— array of column names rendered with a trend icon (up / down / dash) next to the value.matrix.labels— object mapping column name to display label (overrides the raw column name in the header).matrix.column_formats— object mapping column name to a format key.matrix.formats— object mapping format key to a pattern (two-step indirection, likegrid.formats).matrix.column_widths— object mapping column name to a width ("150px","20%", or numeric).matrix.uniform_column_widths— boolean or"auto". When set, all columns share the same auto-fit width.matrix.uniform_column_widths_min_px— integer. Default80.matrix.uniform_column_widths_max_px— integer. Default520.
Summary table
The matrix can render a comparative summary above the detail rows:
matrix.show_summary— boolean. Defaulttrue.matrix.summary_title— string title above the summary.matrix.summary_columns— array of column names included in the summary.
Grouping & sections
Two ways to organise the rows: automatic grouping by a column, or manual sections.
Automatic grouping
matrix.group_by— column name. Group result rows by this field; each group becomes a collapsible section.matrix.group_key_field— column name to render as the first column inside each group section.matrix.group_columns— array of column names rendered inside each group.
Manual sections
matrix:
sections:
- id: revenue
title: Revenue breakdown
columns: [period, units, revenue]
- id: cost
title: Cost breakdown
columns: [period, cogs, opex]
Totals
Totals live in two siblings under matrix: group_totals (one row per group section) and overall_totals (one row across all groups). Both share the same shape:
enabled— boolean.label— string. Default"TOTAL".columns— array of column names to sum. If empty, numeric columns are summed automatically.computed— array of computed field objects rendered alongside the sums. Each item:field— output field name.type—"ratio"or"percent_delta".numerator— field name for the dividend (ratio) or current period (delta).denominator— field name for the divisor (ratio) or baseline (delta).
matrix:
group_totals:
enabled: true
label: TOTAL
columns: [units, revenue]
computed:
- field: attainment_pct
type: percent_delta
numerator: revenue
denominator: budget
overall_totals:
enabled: true
label: GRAND TOTAL
columns: [units, revenue]
Behavior
matrix.behavior controls how sections expand and how the matrix renders for PDF export:
web_mode—"all_open"(every section expandable independently),"single_open"(opening a section closes the others), or"expand_all"(everything open, headers inert). Omit the key for the default accordion behavior.default_open—"all"or a specific section id. Which sections start expanded on first load.pdf_expand_all— boolean. Defaultfalse. Critical for PDF export: without this, collapsed groups disappear from the printed document.
format
Use matrix.column_formats + matrix.formats as the primary formatting path; the root format field is checked as a fallback only.
Cross-filter behavior
- Clicking a body cell whose column is declared as a parameter on a source signature in this viz's own model file emits a pill
{ field: <column name>, value: <cell value> }. - Cells in group totals and overall totals rows are not clickable — they aggregate across multiple key values, so a click would be ambiguous.
- Cells in trend columns (rendered with up/down direction badges) are not clickable — they show direction over a numeric value, not a categorical pick.
- Section headers (auto-grouped via
matrix.group_byor hand-crafted viamatrix.sections) are not clickable in this version. The<details>click is reserved for expand/collapse. - Document-mode dashboards suppress cell-click wiring entirely — document/PDF rendering has no interactive target.
- Disable per viz with
matrix.cross_filter: false.
See Cross-filtering for the full mechanism.
Worked example
A revenue matrix grouped by category with the brands of each category as detail rows. The average ticket in the totals rows is a computed ratio — summing an average would be wrong, so it is re-derived from the summed columns:
id: ec_category_brand_matrix
title: Revenue matrix by category
query: "models/ec_category_brand_matrix.malloy::by_category_brand"
type: report_matrix
matrix:
show_summary: false
group_by: category
group_key_field: brand
group_columns:
- revenue
- order_count
- avg_ticket
- revenue_prev_year
- yoy_delta_pct
key_columns: [revenue, yoy_delta_pct]
trend_columns: [yoy_delta_pct]
group_totals:
enabled: true
label: TOTAL
columns: [revenue, order_count, revenue_prev_year]
computed:
- field: avg_ticket
type: ratio
numerator: revenue
denominator: order_count
overall_totals:
enabled: true
label: GRAND TOTAL
columns: [revenue, order_count, revenue_prev_year]
labels:
brand: Brand
revenue: Revenue
order_count: Orders
avg_ticket: Avg ticket
revenue_prev_year: Revenue LY
yoy_delta_pct: YoY
column_formats:
revenue: currency
avg_ticket: currency
revenue_prev_year: currency
yoy_delta_pct: percent
formats:
currency: "$#,##0"
percent: "#,##0.0%"
behavior:
web_mode: all_open
default_open: all
pdf_expand_all: true
pagination:
page_size: 50
published: true
Design notes
- For PDF export, set
matrix.behavior.pdf_expand_all: trueso every group prints expanded. - List summed columns explicitly in
group_totals.columns/overall_totals.columns— the empty form auto-sums every numeric column, including ID-style numbers. - Computed total fields reference columns present in the summed rows — both
numeratoranddenominator. - Control the first-load state with
matrix.behavior.default_open:"all", or a specific section id. - Use the
matrix.column_formats+matrix.formatsindirection so the same currency / percent pattern applies everywhere it should.