Docs / Build Workflow

Visualization — bar

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: right en 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: line en la series de línea; normalmente con axis: right y chart.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ía format.
  • mapping.series — requerido. Array. Una entry por measure a plotear. Cada entry tiene que declarar un field; 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". line dibuja el measure como línea sobre las mismas categorías (combo chart). Las series line nunca se apilan. No combinable con chart.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 por format; estilizalo con chart.value_label abajo.
  • chart.cross_filter — boolean, default true. Seteá a false para 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á a false cuando 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 de position.
  • 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: 1 para 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:
    emphasis:
      field: category
      value_from_param: highlight_category
      bar_color: "#6c47ff"
    La barra cuyo category iguala al valor de runtime de highlight_category se colorea con bar_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_gap explí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: -30 y max_chars: 14, o cambiá a chart.orientation: horizontal (las barras horizontales no pueden incluir series type: 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: bottom o seteá show: false cuando solo hay una series.
  • Demasiadas categorías explotan el layout. Usá chart.x_axis.visible_window para 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.