Cuándo usar bar
Bar es la elección correcta cuando la pregunta es "¿cómo se comparan estas categorías?". El eje de categoría lista cosas discretas — productos, regiones, channels, statuses — y el eje de valor mide una o más cantidades numéricas para cada una. El mismo renderer cubre cuatro shapes comunes:
- Single-series — una barra por categoría, un measure. El default.
- Grouped — múltiples barras por categoría, una por measure. Andá por ella cuando los measures están en la misma escala (revenue y refunds, por ejemplo).
- Stacked — barras apiladas una arriba de otra; la altura total es la suma de todos los measures. Usá
chart.stack: normal. - Percent-stacked — cada categoría reescalada a 100%, con las barras mostrando la parte de cada componente. Usá
chart.stack: percent. - Dual-axis — dos measures en escalas distintas compartiendo un chart, uno bindeado a un eje y izquierdo y el otro a uno derecho. Seteá
axis: righten la segunda series. - Combo (bar + line) — barras para un measure más una línea sobre las mismas categorías para otro (por ejemplo un overlay de porcentaje acumulado). Seteá
type: lineen la series de línea; normalmente conaxis: rightychart.y2_axis.
Usá line en su lugar cuando el eje x está ordenado por tiempo y la pregunta es sobre trend. Usá pie cuando hay muy pocas categorías (≤ 6) y la pregunta es puramente sobre composición. Usá grid cuando la audiencia necesita los números reales al lado de los nombres de categoría en vez de una comparación visual.
Mapping
Dos campos de mapping manejan el chart:
mapping.x— requerido. El campo categórico. Cada valor distinto se vuelve un tick en el eje de categoría. Usá un field string para labels limpios; los fields numéricos o de fecha se formatean con el default de la plataforma a menos que overrides víaformat.mapping.series— requerido. Array. Una entry por measure a plotear. Cada entry tiene que declarar unfield; lo demás es opcional.
mapping:
x: category
series:
- field: revenue
Usá una entry para un chart simple, dos o más para grouped o stacked, y el axis: right opcional en una series para ponerla en el eje y secundario.
Opciones por series:
field— requerido. El field numérico del resultado de la query que maneja la altura de barra para esta series.label— string. Se muestra en la legend y el tooltip. Default al nombre del field.label_from_field— string. Trae el label de legend desde un field en los datos en vez de declararlo en YAML.color— color hex para esta series. Default al próximo slot en la paleta de la plataforma.axis—"left"(default) o"right". Right pone la series en el eje y secundario.type—"bar"(default) o"line".linedibuja el measure como línea sobre las mismas categorías (combo chart). Las series line nunca se apilan. No combinable conchart.orientation: horizontal— la validación rechaza esa combinación.
# dos measures en la misma escala (grouped)
series:
- field: revenue
label: Revenue
- field: refunds
label: Refunds
# dos measures en escalas distintas (dual-axis)
series:
- field: revenue
label: Revenue
- field: order_count
label: Orders
axis: right
# un measure con color explícito
series:
- field: revenue
label: Revenue
color: "#6c47ff"
Shortcuts de chart
Keys top-level del bloque chart. El bloque chart es tipado y cerrado — cualquier cosa no listada en esta página se rechaza en tiempo de validación.
chart.orientation—"vertical"(default) o"horizontal". Elegí horizontal cuando los labels de categoría son largos, o cuando la audiencia lee top-to-bottom (rankings, leaderboards).chart.stack—"normal"(sum stacking) o"percent"(reescalar cada categoría a 100% y switchear los labels del eje de valor a porcentajes). Omitirlo para grouped bars.chart.show_value_labels— boolean. Prende el value label para cada series. El contenido del label es el valor de la barra, formateado porformat; estilizalo conchart.value_labelabajo.chart.cross_filter— boolean, defaulttrue. Seteá afalsepara charts que siempre tienen que mostrar la vista sin filtrar (ej. un headline de "total revenue").chart.height— altura en pixels del container de la viz. Seteala explícita cuando el chart necesita más espacio vertical — por ejemplo, una bar horizontal con muchas categorías.
Value labels
chart.value_label es un objeto aplicado a cada series cuando chart.show_value_labels está prendido:
position— placement del label relativo a la barra. Valores comunes:"top","inside","insideTop","insideBottom","outside".rotate— grados, entre -90 y 90. Útil cuando el label es más ancho que la barra.color,font_size,font_weight.formatter— template string (sin callbacks). Útil para agregar un prefix o suffix de unidad (ej."{c}M").distance,align("left"|"center"|"right"),vertical_align("top"|"middle"|"bottom"),clip.
# label compacto dentro de la barra con texto blanco
chart:
show_value_labels: true
value_label:
position: inside
color: "#fff"
font_size: 11
# label arriba de cada barra vertical con formatter de currency
chart:
show_value_labels: true
value_label:
position: top
formatter: "${c}"
distance: 4
# labels rotados para barras estrechas
chart:
show_value_labels: true
value_label:
rotate: -90
position: insideBottom
Legend & tooltip
chart.legend:
show— boolean. Seteá afalsecuando el chart tiene una sola series y la legend es redundante.position— shortcut:"top","bottom","left","right","top-left","top-right","bottom-left","bottom-right".orient—"horizontal"|"vertical". Usalo para overridear el orient derivado deposition.top/bottom/left/right— número de pixels o string de porcentaje para posicionamiento directo.text_style— estilo de texto:color,font_style,font_weight,font_family,font_size,line_height.item_width,item_height,item_gap— tamaños en pixels para los swatches coloreados y gaps.
chart.tooltip:
show— boolean.trigger—"item"(una barra a la vez, default para single-series),"axis"(group-wise; preferido cuando hay múltiples series para que hover las compare), o"none".confine— boolean. Mantiene el tooltip dentro de los bounds del chart.formatter— template string. Usá placeholders como{a}(series),{b}(categoría),{c}(valor).background_color,border_color,border_width.padding— número único o array de 2 a 4 números (top/right/bottom/left).text_style— mismo shape que en la legend.axis_pointer.type—"line"|"shadow"|"none"|"cross". Elección común para bar:"shadow".
Ejes
chart.x_axis, chart.y_axis y chart.y2_axis comparten el mismo shape para bloques de eje de valor (y2_axis configura el eje derecho cuando una series usa axis: right; con un extra en x_axis):
name— título del eje.name_location—"start"|"middle"|"center"|"end".name_gap— pixels entre la línea del eje y el nombre.min,max— límites numéricos del eje. Usáy2_axis.max: 1para fijar una línea de porcentaje acumulado a un dominio 0–100% cuando los valores están en 0–1.axis_label.show— boolean.axis_label.rotate— grados, -90 a 90. Usalo para evitar que nombres largos de categoría se solapen.axis_label.interval— entero ≥ 0 (saltear cada N labels) o"auto".axis_label.color,axis_label.font_size,axis_label.font_weight.axis_label.formatter— template string.axis_label.max_chars— entero ≥ 1. Trunca los labels con una elipsis.x_axis.visible_window— entero ≥ 1. Restringe la cantidad visible de categorías y habilita un range slider horizontal; útil cuando hay muchas categorías.
# nombres largos de categoría con rotación y elipsis
chart:
x_axis:
axis_label:
rotate: -30
max_chars: 14
# eje y nombrado con un formatter de porcentaje
chart:
y_axis:
name: Margin
name_gap: 28
axis_label:
formatter: "{value}%"
# data-zoom slider para muchas categorías
chart:
x_axis:
visible_window: 12
format
El format de número es field-keyed en el top level del YAML de la viz. Los patterns por field ganan sobre el pattern root. Patterns comunes para un bar chart:
format:
revenue: "$#,##0.00" # currency completa
revenue: "$#,##0a" # abreviada: $1.2M, $340K
order_count: "#,##0" # entero con grouping
margin_pct: "#,##0.00%" # porcentaje
El format aplica a value labels, tooltips y axis tick labels de valor. La gramática completa de patterns vive en el overview de viz-types.
Comportamiento de cross-filter
Dentro de un dashboard, clickear una barra agrega un "pill" que estrecha cada otra viz de la página a la categoría clickeada. Mecanismo completo en Cross-filtering. Específicos de bar:
- La categoría de la barra clickeada se vuelve el valor de cross-filter.
- Si los models del dashboard no declaran un parámetro con el nombre del field clickeado, el click se ignora silenciosamente. Para hacer una columna cross-filterable, declará un parámetro para ella en el model que potencia los charts afectados.
- Deshabilitá por viz con
chart.cross_filter: false. Útil para charts "headline" que siempre tienen que mostrar totales. - Para resaltar una barra específica desde un valor externo, usá el bloque top-level
emphasis:
La barra cuyoemphasis: field: category value_from_param: highlight_category bar_color: "#6c47ff"categoryiguala al valor de runtime dehighlight_categoryse colorea conbar_color.
Ejemplos trabajados
Comparación simple:
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:
height: 320
show_value_labels: true
value_label:
position: top
x_axis:
axis_label:
rotate: -30
max_chars: 14
y_axis:
name: Revenue
format:
revenue: "$#,##0.00"
published: true
Grouped (dos measures, misma escala):
id: ec_revenue_vs_refunds_bar
title: Revenue vs Refunds
query: "models/ec_revenue.malloy::revenue_vs_refunds"
type: bar
mapping:
x: category
series:
- field: revenue
label: Revenue
color: "#6c47ff"
- field: refunds
label: Refunds
color: "#fb7185"
chart:
legend:
show: true
position: top
tooltip:
trigger: axis
axis_pointer:
type: shadow
format:
revenue: "$#,##0.00"
refunds: "$#,##0.00"
published: true
Composición percent-stacked:
id: ec_channel_mix_bar
title: Channel Mix per Category
query: "models/ec_revenue.malloy::channel_mix"
type: bar
mapping:
x: category
series:
- field: rev_direct
label: Direct
- field: rev_organic
label: Organic
- field: rev_paid
label: Paid
chart:
stack: percent
show_value_labels: true
value_label:
position: inside
color: "#fff"
legend:
show: true
position: top
format:
rev_direct: "#,##0.0%"
rev_organic: "#,##0.0%"
rev_paid: "#,##0.0%"
published: true
Pareto (barras ordenadas + línea de porcentaje acumulado en el eje derecho). Construí una query Malloy sobre bigquery-public-data.thelook_ecommerce que devuelva el conteo de cada categoría ordenado descendente más una columna de porcentaje acumulado (valores 0–1). Mapeá el conteo como barras y el porcentaje acumulado como series type: line en axis: right:
id: ec_return_reason_pareto
title: Return reasons — Pareto
query: "models/ec_returns.malloy::by_reason_pareto"
type: bar
mapping:
x: return_reason
series:
- field: return_count
label: Returns
- field: cumulative_pct
label: Cumulative %
type: line
axis: right
color: "#6c47ff"
chart:
y2_axis: { max: 1 }
legend: { show: true }
format:
return_count: "#,##0"
cumulative_pct: "#0%"
published: true
Hacé push desde tu workspace con looky push -w <workspace_slug> después de que el modelo y el YAML del viz existan bajo content/visualizations/.
Dual-axis (revenue vs orders):
id: ec_revenue_orders_bar
title: Revenue and Orders
query: "models/ec_revenue.malloy::by_month"
type: bar
mapping:
x: order_month
series:
- field: revenue
label: Revenue
- field: order_count
label: Orders
axis: right
chart:
legend:
show: true
position: top
y_axis:
name: Revenue
format:
revenue: "$#,##0"
order_count: "#,##0"
published: true
Ranking horizontal con muchas categorías:
id: ec_top_brands_bar
title: Top Brands by Revenue
query: "models/ec_revenue.malloy::by_brand_desc"
type: bar
mapping:
x: brand
series:
- field: revenue
label: Revenue
chart:
orientation: horizontal
height: 540
show_value_labels: true
value_label:
position: right
x_axis:
axis_label:
max_chars: 18
y_axis:
visible_window: 25
format:
revenue: "$#,##0a"
published: true
Nota: con orientación horizontal, los nombres largos de categoría viven en el eje y, así que el axis_label del eje y recibe max_chars, y visible_window se mueve a y_axis.
Errores comunes
- El percent stack no suma 100%. Asegurate que cada series en
mapping.series[]represente una parte del mismo todo. Si uno de los measures está en una escala distinta, el chart muestra lo que pediste pero no es significativo como composición. - Los labels de dual-axis chocan. Dos escalas de valor necesitan espacio. O reducí la densidad de datos (menos categorías), seteá
name_gapexplícito en los dos ejes, o partilo en dos charts. - Los labels largos de categoría hacen wrap o se solapan. Agregá
chart.x_axis.axis_label.rotate: -30ymax_chars: 14, o cambiá achart.orientation: horizontal(las barras horizontales no pueden incluir seriestype: line— usá combo charts verticales para overlays tipo Pareto). - Los clicks de cross-filter no tienen efecto. El field clickeado tiene que estar declarado como parámetro en al menos un model usado por el dashboard. Sin eso, los clicks se ignoran silenciosamente.
- Los value labels se clipean en barras chicas. Seteá
chart.value_label.clip: false, o movelo a position"top"/"outside", o reducífont_size. - La legend ocupa demasiado espacio. Usá
position: bottomo seteáshow: falsecuando solo hay una series. - Demasiadas categorías explotan el layout. Usá
chart.x_axis.visible_windowpara habilitar un slider, o ordená y limitá en la query Malloy así el chart muestra el top N. - El color es por series, no por barra individual. Para resaltar una barra específica, usá el bloque top-level
emphasis(mirá arriba) en vez de tratar de colorear una categoría directo.