Docs / Build Workflow

Visualization — kpi

Cuándo usar kpi

KPI es la elección correcta cuando la respuesta es un solo número — total de revenue, count de orders, tasa de conversión, error budget consumido. Agrega un delta o un valor secundario para mostrar dirección o comparación al lado del headline. KPI es el "headline" típico de un dashboard: no emite clicks (no hay dimension para clickear), pero reacciona a filtros de dashboard y pills de cross-filter como cualquier otra viz — su query subyacente re-corre con los params activos y el número headline se recomputa.

Si necesitas un número por categoría en vez de un solo número, usa bar. Si necesitas un trend en el tiempo, usa line. Si necesitas muchos números en un layout tabular, usa grid.

El identifier de tipo es kpi — no existe un tipo number; la validación lo rechaza.

Mapping

El KPI lee la primera fila del resultado de la query. Los campos de mapping nombran qué columnas de esa fila se vuelven qué elemento visual:

  • mapping.value — requerido. El field cuyo valor es el número headline.
  • mapping.subtitle — field string para una línea de contexto label / período debajo del valor.
  • mapping.delta — field numérico mostrado como indicador de cambio. El signo maneja la flecha up/down; la config de polaridad controla el color.
  • mapping.secondary_value — field numérico para un valor de comparación (ej. "período anterior") cuando no hay delta. Mapea uno u otro: cuando están los dos, el renderer muestra el delta.
  • mapping.secondary_label — caption para secondary_value, escrito como string literal (ej. "Invoices", "Previous quarter"). También acepta un nombre de campo: si el valor coincide con una columna de la fila de resultado, se usa el valor de esa columna como caption. Default a "Previous" cuando se omite.
  • mapping.secondary_plain — field de texto plano mostrado al lado del headline cuando no hay delta ni valor secundario.
  • mapping.comparison — field numérico que maneja el bloque comparison de abajo (lecturas período contra período).
mapping:
  value: revenue
  subtitle: period_label
  delta: revenue_delta_pct

La regla de una fila significa que el lado Malloy de un KPI es una view solo de aggregate:. Producir la columna delta es parte de la query, no de la viz — un shape que funciona compara la ventana con la ventana anterior de igual longitud:

# models/ec_performance.malloy (excerpt)
##! experimental.parameters

source: ec_performance() is ecommerce.sql("""
  WITH windows AS (
    SELECT
      SUM(IF(created_at >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY),
             sale_price, 0)) AS revenue,
      SUM(IF(created_at <  TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
         AND created_at >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 60 DAY),
             sale_price, 0)) AS revenue_prev
    FROM `bigquery-public-data.thelook_ecommerce.order_items`
  )
  SELECT
    revenue,
    'Last 30 days' AS period_label,
    SAFE_DIVIDE(revenue - revenue_prev, revenue_prev) AS revenue_delta_pct
  FROM windows
""") extend {
  view: kpi is { select: * }
}

Bloque kpi

Las opciones específicas de KPI viven bajo el bloque top-level kpi. KPI no tiene un bloque chart.

  • kpi.comparison_label — caption mostrado debajo del delta (ej. "vs. last week"). Cuando se omite, el renderer compone un default tipo "Up vs previous period" desde el signo del delta.
  • kpi.delta_good_when"increase" (default) o "decrease". Setea la polaridad que colorea el delta en verde vs rojo. Usa "decrease" para métricas donde menos es mejor — refunds, error rate, time-to-resolution.

Bloque comparison

El bloque top-level comparison renderiza una lectura período contra período desde el field nombrado en mapping.comparison:

  • comparison.enabled — boolean.
  • comparison.direction"auto" deriva la flecha up/down del signo del valor.
  • comparison.period_label — caption para la comparación (ej. "vs budget to date").
mapping:
  value: attainment_pct
  comparison: attainment_pct
format:
  value: "#,##0.00%"
  comparison: "#,##0.00%"
comparison:
  enabled: true
  direction: auto
  period_label: "vs budget to date"

Nota que las entries de format de arriba son slot-keyed (value, comparison) en vez de field-keyed — las dos formas funcionan, y las keys de slot se leen mejor cuando el mismo field llena dos slots.

format

El format de número es field-keyed. Patterns por field ganan sobre el pattern root.

  • format.value — pattern para el número headline.
  • format.delta — pattern para el indicador delta.
  • format.secondary_value — pattern para el valor de comparación secundario.
  • format en root — fallback cuando falta una entry field-específica.
# headline as abbreviated currency, delta as percent
format:
  revenue: "$#,##0a"
  revenue_delta_pct: "#,##0.00%"

La gramática de patterns completa vive en el overview de viz-types.

Comportamiento de cross-filter

KPI participa en cross-filtering solo como consumer:

  • No emite. Clickear un KPI no agrega un pill — no hay dimension para clickear.
  • Sí reacciona. Los pills seteados en otra parte del dashboard, y cualquier filtro a nivel dashboard, se vuelven parámetros en el próximo run, y la query subyacente del KPI re-corre con ellos. El número headline se recomputa en consecuencia.

Si quieres un "headline que siempre muestre el total dashboard-wide" sin importar los pills, escribe la query Malloy subyacente para que los defaults de su parámetro ignoren los valores de pill (ej. aceptar el parámetro pero no usarlo en el where-clause), o usa dos items KPI separados: uno atado a un model que ignora el parámetro de cross-filter, otro atado a un model que lo respeta.

Ejemplos trabajados

Headline con delta y polaridad de porcentaje favoreciendo decrease (menor error rate es mejor):

id: ec_error_rate_kpi
title: Error Rate
query: "models/ec_quality.malloy::error_rate_kpi"
type: kpi
mapping:
  value: error_rate
  delta: error_rate_delta_pct
  subtitle: period_label
format:
  error_rate: "#,##0.00%"
  error_rate_delta_pct: "#,##0.00%"
kpi:
  comparison_label: "vs previous period"
  delta_good_when: decrease
published: true

Headline con un valor de comparación secundario (sin delta):

id: ec_revenue_vs_prev_kpi
title: Revenue
query: "models/ec_revenue.malloy::current_vs_previous"
type: kpi
mapping:
  value: revenue_current
  secondary_value: revenue_previous
  secondary_label: "Previous quarter"
format:
  revenue_current: "$#,##0a"
  revenue_previous: "$#,##0a"
published: true

Headline con una anotación de texto plano cuando la métrica no tiene una comparación numérica:

id: ec_top_brand_kpi
title: Top Brand
query: "models/ec_revenue.malloy::top_brand"
type: kpi
mapping:
  value: brand_name
  secondary_plain: market_share_label
published: true