Cuándo usar heatmap
Heatmap es la elección correcta cuando quieres renderizar un measure a través de dos dimensions categóricas o temporales a la vez. Usos comunes: day-of-week vs hour-of-day para patterns de actividad; channel vs region para densidad de revenue; categoría de producto vs mes para estacionalidad.
Usa grid en su lugar cuando la audiencia necesita leer los números reales y una de las dimensions es de alta cardinalidad. Usa scatter cuando las dimensions son continuas en vez de categóricas.
Mapping
mapping.x— requerido. Field del eje-columna (un tick por valor distinto).mapping.y— requerido. Field del eje-fila.mapping.value— requerido. Field numérico que maneja la intensidad de color de cada celda.
mapping:
x: hour_of_day
y: day_of_week
value: order_count
Las extracciones de time-bucket como hour-of-day y day-of-week son funciones de dialecto — calcúlalas como columnas en una source de raw-SQL para que el heatmap consuma fields ya listos (este shape también porta a Postgres/MySQL intercambiando las funciones de extracción):
# models/ec_orders_activity.malloy
##! experimental.parameters
source: ec_orders_activity() is ecommerce.sql("""
SELECT
EXTRACT(HOUR FROM created_at) AS hour_of_day,
FORMAT_TIMESTAMP('%a', created_at) AS day_of_week,
MIN(EXTRACT(DAYOFWEEK FROM created_at)) AS day_order,
COUNT(*) AS order_count
FROM `bigquery-public-data.thelook_ecommerce.orders`
GROUP BY 1, 2
""") extend {
view: by_day_hour is {
select: hour_of_day, day_of_week, order_count, day_order
order_by: day_order asc, hour_of_day asc
}
}
Shortcuts de chart
El bloque chart es tipado y cerrado.
chart.show_cell_labels— boolean. Renderiza el valor de la celda adentro de cada celda. Estiliza los labels conchart.labelabajo.chart.cross_filter_emit—"x"o"y". Heatmap tiene dos ejes categóricos, así que tienes que elegir cuál valor se emite al click. Sin él un click no emite nada.chart.height— altura en pixels del container de la viz.
Color scale
chart.visual_map es un objeto que controla el gradiente de color y la legend opcional de color-scale:
show— boolean. Muestra la legend de color-scale al lado del chart.orient—"horizontal"|"vertical".min,max— piso / techo explícitos. Overridean el rango derivado de datos — útil cuando varios heatmaps en el mismo dashboard necesitan compartir una escala.left/right/top/bottom— número de pixels o string de porcentaje para placear la legend de color-scale.in_range.color— array de strings hex: los stops del gradiente de low a high. Dos stops producen un gradiente simple low-to-high.text_style— estilo de texto para los labels de la color-scale.
chart:
visual_map:
show: true
orient: vertical
in_range:
color: ["#e0f7f4", "#0d9488"]
Labels de celda
chart.label estiliza el label numérico por-celda cuando chart.show_cell_labels está prendido:
position,rotate,color,font_size,font_weight.formatter— template string (sin callbacks). Usa{c}para el valor.distance,align,vertical_align,clip.
Los labels de celda son útiles cuando el heatmap es chico y la audiencia necesita el número exacto; en heatmaps densos los labels se vuelven ruido — dejalos apagados y confía en el tooltip.
Legend & tooltip
chart.legend y chart.tooltip comparten el mismo shape que en bar. Para heatmap el tooltip con trigger: item revela una celda a la vez con ambos valores de eje y el valor de celda.
Ejes
chart.x_axis y chart.y_axis comparten el mismo shape:
name,name_location,name_gap.axis_label.show,axis_label.rotate,axis_label.interval,axis_label.color,axis_label.font_size,axis_label.font_weight,axis_label.formatter,axis_label.max_chars.
format
format.valueoformat[<value_field_name>]— pattern para labels de celda y valores de tooltip.formaten root — fallback.
Comportamiento de cross-filter
- El click emite un valor solo cuando
chart.cross_filter_emitestá seteado a"x"o"y". - El eje elegido se vuelve el field de cross-filter; el label clickeado se vuelve el valor.
- El field clickeado tiene que estar declarado como parámetro en una firma de source del archivo de model propio de esta viz.
- Si el click filtra un dashboard se decide donde se coloca el heatmap:
items[].cross_filteren el dashboard.
Mira Cross-filtering para el mecanismo completo.
Ejemplos trabajados
Actividad por hora y día de semana:
id: orders_by_day_hour
title: Orders by Day and Hour
query: "models/ec_orders.malloy::by_day_hour"
type: heatmap
mapping:
x: hour_of_day
y: day_of_week
value: order_count
chart:
height: 320
show_cell_labels: true
cross_filter_emit: x
visual_map:
show: true
orient: vertical
in_range:
color: ["#e0f7f4", "#0d9488"]
x_axis:
name: Hour
y_axis:
name: Day
format:
order_count: "#,##0"
published: true
Color scale compartida entre múltiples heatmaps (setea min / max explícitos):
chart:
visual_map:
show: true
min: 0
max: 5000
in_range:
color: ["#e0f7f4", "#0d9488"]
Notas de diseño
- Cuando un outlier domina la escala de color, setea
visual_map.maxpara recortarlo — los valores sobre el tope renderizan con el color máximo. - Para labels sobre celdas oscuras, setea un
chart.label.colorcontrastante, o apaga los labels de celda y apoyate en el tooltip. - Un heatmap emite un eje por click (
cross_filter_emit: "x"o"y") — cuando la interacción necesita ambas coordenadas, usa un grid. - El
visual_map.in_range.colorexpuesto es un gradiente low-to-high — para escalas divergentes, codifica la divergencia en el valor mismo (ej. un delta con signo).