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. cumplimiento, conversion rate).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 ZONA
columns: [unidades, ventas]
computed:
- field: cumplimiento
type: percent_delta
numerator: ventas
denominator: presupuesto
overall_totals:
enabled: true
label: TOTAL GENERAL
columns: [unidades, ventas]
Behavior
matrix.behavior controls how sections expand and how the matrix renders for PDF export:
web_mode—"all_open","single_open","expand_all", or empty. How sections behave in the browser when the user clicks a header.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 in at least one model on the dashboard 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 (
tableContext: document) suppresses cell-click wiring entirely — document/PDF rendering has no interactive target. - Disable per viz with
chart.cross_filter: false.
See Cross-filtering for the full mechanism.
Worked example
id: nv_visitador_resumen
title: Resumen por visitador
query: "models/nv_comercial.malloy::resumen_por_visitador"
type: report_matrix
matrix:
group_by: zona
group_key_field: visitador
group_columns: [periodo, unidades, ventas, cumplimiento]
key_columns: [cumplimiento]
trend_columns: [cumplimiento]
group_totals:
enabled: true
label: TOTAL ZONA
columns: [unidades, ventas]
computed:
- field: cumplimiento
type: percent_delta
numerator: ventas
denominator: presupuesto
overall_totals:
enabled: true
label: TOTAL GENERAL
columns: [unidades, ventas]
column_formats:
ventas: currency
presupuesto: currency
cumplimiento: percent
formats:
currency: "$#,##0"
percent: "#,##0.0%"
behavior:
web_mode: single_open
default_open: all
pdf_expand_all: true
published: true
Common pitfalls
- PDF export shows fewer rows than the browser. Set
matrix.behavior.pdf_expand_all: true. Without it, collapsed groups stay collapsed in the printed document. - Auto-summed totals include the wrong columns. List the columns you want summed explicitly in
group_totals.columns/overall_totals.columns; leaving them empty auto-sums all numeric columns, which can include things like ID-style numbers. - Computed total field shows a strange number. Both
numeratoranddenominatormust reference fields present in the rows being summed. Check spelling against the query result. - Sections do not start expanded. Set
matrix.behavior.default_open: "all", or the specific section id you want open on first load. - Click on a cell does nothing. Check that (a) the column name is declared as a parameter in at least one model on the dashboard, (b) the value is non-null, (c) the cell isn't in a totals or trend row (those are non-clickable by design), and (d)
matrix.cross_filterisn't set tofalse. - Cell formats are inconsistent across columns. Use the
matrix.column_formats+matrix.formatsindirection so the same currency / percent pattern applies everywhere it should.