Docs / Build Workflow

Visualizations

What a visualization YAML is for

A visualization file binds one Malloy query to one chart or table. Every transformation belongs in the model query; the visualization YAML is presentation only — chart type, which fields go where, formatting, optional emphasis. For how to shape that Malloy layer (dimensions, measures, views, modular files), see Models.

For the per-type reference (every chart.* property each viz type accepts), see Visualization Types and the page for each type underneath.

Required top-level fields

  • id — workspace-unique identifier. Stable over time: dashboards reference it, so renaming breaks dashboards.
  • title — human-readable title shown in the dashboard.
  • type — viz type discriminator. Must be one of the supported types listed in the viz-types index; anything else is rejected at validation time.
  • query — Malloy query reference, exactly in the format path/to/file.malloy::query_name. The path is from the workspace root; both halves must exist or validation fails.

Other top-level fields

  • mapping — field-role assignments. Shape varies per viz type — see the per-type page.
  • chart — typed config block for ECharts-based types (bar, line, pie, scatter, heatmap, funnel). Closed surface: only the keys listed in the per-type reference are accepted.
  • kpi, grid, matrix — type-specific blocks for the DOM-based types (kpi, grid/table, report_matrix). Use these instead of chart.
  • pagination — for grid and report_matrix.
  • filters — list of user-facing controls. See Filters.
  • format — field-keyed number / date format patterns; field name → pattern string.
  • emphasis — declarative highlight rule (per supported type — see the per-type pages).
  • execution — query execution hints (timeout, concurrency, cache override). Permissive shape today.
  • tags — free-form labels for search.
  • published — boolean. Only true visualizations appear in dashboards.

The query reference format

Every visualization points to a Malloy query with this exact format:

query: "models/ec_revenue.malloy::by_category"

The part before :: is the path to the .malloy file from the workspace root. The part after :: is the view or query name defined inside that file. Both must match exactly.

Local validation (looky validate) checks that the file exists and the reference uses the :: separator. Server-side validation additionally compiles the model and dry-runs the query; if the view name doesn't exist, or the model fails to compile, you get a clear error before push.

Worked examples

Minimal KPI:

id: ec_revenue_kpi
title: Revenue
query: "models/ec_revenue.malloy::kpi"
type: kpi
mapping:
  value: revenue
  delta: revenue_delta_pct
format:
  revenue: "$#,##0a"
  revenue_delta_pct: "#,##0.00%"
published: true

Bar with one series — note mapping.series[] (legacy mapping.y is no longer accepted on bar):

id: ec_revenue_by_category_bar
title: Revenue by Category
query: "models/ec_revenue.malloy::by_category"
type: bar
mapping:
  x: category
  series:
    - field: revenue
      label: Revenue
chart:
  show_value_labels: true
  value_label:
    position: top
format:
  revenue: "$#,##0.00"
published: true

Line with dual axis:

id: ec_revenue_over_time_line
title: Revenue Over Time
query: "models/ec_revenue.malloy::over_time"
type: line
mapping:
  x: order_month
  y: revenue
  y2: order_count
  series_label: Revenue
  series_label_2: Orders
format:
  revenue: "$#,##0"
  order_count: "#,##0"
published: true

For every other shape (grouped bars, percent-stacked, donut pie, scatter, heatmap, funnel, grid with pagination, report_matrix with totals) see the per-type pages under Visualization Types.

Cross-filtering at a glance

Inside a dashboard, clicking a chart can add a "pill" that narrows every other viz on the page. Per-type emit behavior:

  • Emit clicks: bar, line, pie, scatter, funnel, grid, report_matrix, heatmap (the latter requires chart.cross_filter_emit set to "x" or "y").
  • Don't emit but consume pills: kpi (no categorical click target by structure).
  • Per-viz opt-out: chart.cross_filter: false for ECharts-based vizs (bar, line, pie, scatter, heatmap, funnel); grid.cross_filter: false for grid; matrix.cross_filter: false for report_matrix. KPI doesn't emit by structure.

Full mechanism at Cross-filtering.

What validation actually checks (and what it does not)

Validation is two-pass — local then server-side. Per visualization, the checks are:

  • Local: YAML parses; id, title, type, query are present and non-empty; query uses the :: separator; the model file exists; the id is unique across the workspace; the chart block is schema-valid (every property is recognised, values are in their allowed range — error VZ020).
  • Server-side: the underlying Malloy model compiles, sources are reachable, and the query dry-runs against the runtime engine (free on BigQuery, EXPLAIN-only on Postgres in --strict).

Validation does not verify that every field in mapping exists in the query result, that every field in format appears in mapping, or that the chart "looks right". Those issues surface only at render time. Open the visualization detail page after push to catch them.

looky validate
looky list visualizations