# Chart Selection — Árvore de Decisão (FT Visual Vocabulary → Horus)

## Conteúdo

- Regras inegociáveis (herdadas)
- Tabela de decisão
- Categorias em detalhe
- Guia rápido: widget por pergunta

Qual gráfico usar? A resposta sempre começa pela **relação que existe nos dados**, não
pela preferência estética. Este guia mapeia as 9 categorias do Financial Times Visual
Vocabulary — mais 3 casos especiais de alto uso — para os widgets reais do Horus BI.

Se um widget não existe nesta lista como scaffold, ele não existe na plataforma.

---

## Regras inegociáveis (herdadas)

Estas regras não são opcionais. Qualquer design que as viole estará errado mesmo que
visualmente pareça aceitável.

- **Agregação segue a aditividade da métrica, nunca o hábito.** Razão (ticket
  médio, margem %, conversão) nunca é `:AVG` nem `:SUM`: recompõe dos
  componentes e divide depois de agregar. Semi-aditiva (saldo, estoque) usa
  `:LAST`/`:AVG` no tempo e `:SUM` nas demais dimensões. A regra completa, com
  checklist, está em [`aditividade.md`](aditividade.md), e a classe de cada
  métrica vem do campo `aditividade:` da ficha. Errar aqui produz número errado
  com cara de certo, que é pior que gráfico feio.
- **Comparação com referência nunca é linha × linha.** Meta, orçamento, ano
  anterior: barra preenchida para o realizado e linha para a referência, ou
  bullet quando a comparação é por categoria. Duas linhas leem como duas séries
  independentes em vez de medido contra alvo.
- **Escala de cor: decida a família antes da paleta.** Categórica para
  categoria, sequencial para magnitude, divergente **só** quando existe um ponto
  médio com significado **e** o dado cai dos dois lados dele. Divergente em dado
  de um lado só (receita num choropleth RdBu) faz o valor baixo parecer
  negativo. Data e rank em cor são rampa, nunca categoria. Árvore em
  [`design-tokens.md`](design-tokens.md) §2.0.
- **Total nunca convive com seus componentes.** Uma categoria `Total`/`Todos`/
  `Consolidado` dentro de um empilhado, agrupado ou canal de cor soma junto com
  as partes e dobra o gráfico em silêncio: cada valor aparece duas vezes e o
  eixo só fica "maior". Total é widget separado, rodapé de `Table`, ou nível pai
  de `Matrix`. Se a fonte já traz essa linha, filtre no `dataSource`.
- **Dimensão cíclica ordena pelo ciclo, não pelo alfabeto.** Mês, dia da semana,
  hora e trimestre em texto precisam de ordenação explícita, senão `Abril` vem
  antes de `Janeiro` e a série vira ruído. A ordem vem do campo
  `ordem_canonica:` da ficha da dimensão.
- **Barra com baseline zero (obrigatório).** O eixo Y de qualquer barra começa em 0.
  Cortar o eixo infla diferenças visuais e engana — é erro de integridade, não de gosto.
- **Linha pode ter baseline não-zero.** Gráficos de linha exibem tendência relativa;
  o zero absoluto é irrelevante quando a variação importa mais que o valor absoluto.
  Ajustar o mínimo do eixo para ampliar o sinal é legítimo aqui; a chave que
  faz isso vem de `lumo scaffold widget.Barline`, não deste arquivo.
- **Donut até 4 partes, e sempre donut.** Com 5 ou mais fatias o olho perde a
  comparação angular: troque por barra horizontal ordenada. Pizza sólida
  (`innerSize: 0`) não se usa; o furo é padrão da casa. Mesmo limite que a
  `lumo-mockup` aplica na pré-venda, para a peça aprovada e a entregue não
  divergirem.
- **Temporal = linha, nunca barra.** Séries cronológicas (semana, mês, ano) pertencem
  ao Barline com `globalType: line` ou `area`. Barras em eixo temporal comparam período
  a período mas escondem a forma da tendência — use apenas quando a comparação pontual é
  o ponto, não a tendência.
- **Choropleth = taxas; símbolo proporcional = totais.** No Map, choropleth (fill color)
  codifica grandezas relativas (taxa por 100 mil, percentual de conversão). Valores
  absolutos (contagem de clientes, soma de receita) pertencem ao símbolo proporcional
  (bubble) — senão regiões grandes parecem maiores por área geográfica, não por dado.

---

## Tabela de decisão

| Relação nos dados | Widget Horus | Config essencial |
|---|---|---|
| **Magnitude** — comparar valores de categorias | `Barline` (`globalType: bar`) | Baseline zero obrigatório; horizontal + `orderColumns`/`orderColumnsDir` quando ranking é o ponto |
| **Change over time** — tendência temporal | `Barline` (`globalType: line` ou `area`) | Eixo X cronológico; `area` com gradiente para 1 série; não use barra em eixo temporal |
| **Part-to-whole** — partes de um todo | `Pie` (`chartType: donut`) até 4 partes; `Barline` horizontal ordenado a partir de 5 | Sempre donut, nunca pizza sólida; rótulos de % dentro da fatia |
| **Ranking** — ordem de grandeza | `Barline` horizontal | `orderColumns` + `orderColumnsDir: DESC`; `showDataLabels: true`; baseline zero |
| **Distribution** — frequência por faixa | `Barline` (histograma de bins) ou `Punchcard` | Punchcard para padrão dia × hora; barras para bins de valor contínuo |
| **Correlation** — relação entre duas variáveis | `Punchcard` ou `Svelte` (scatter via Highcharts) | Terceira variável codificada em tamanho de bolha no scatter; Punchcard para padrão cruzado |
| **Deviation** — desvio vs referência ou meta | `Barline` combo: barra (realizado) + linha (meta) | Nunca linha × linha; cor divergente verde/vermelho via `axisColoringExpression`; paleta em `design-tokens.md` §2 |
| **Spatial** — distribuição geográfica | `Map` | Choropleth (fill) = taxas e rates; símbolo proporcional (bubble) = totais e somas absolutas; `colorScale` em ramp sequencial |
| **Flow** — transferência entre nós | `Svelte` (sankey ou chord via Highcharts) | Nativo Horus não cobre flow; implementar como Svelte widget com Highcharts `sankey` ou `dependencywheel` |
| **Single metric** — 1 número com contexto | `Kpi` | `variation` + `sparkline`; `numberFormat: reduced` (K/M/B); cor semântica em `numberColor` |
| **Lookup / detalhe** — linhas de dados | `Table` ou `Matrix` | Table: `fields` com colunas; Matrix: `rows`, `columns`, `values` para tabela dinâmica |
| **Forecast** — projeção com incerteza | `Forecast` | Banda de confiança (CI) visível; distinguir histórico de projeção por estilo de linha |

---

## Categorias em detalhe

### Magnitude — `Barline` (`globalType: bar`)

Use quando a pergunta é "quanto cada categoria tem?" com comparação lado a lado.
Baseline zero é obrigatório — cortar o eixo torna diferenças pequeníssimas parecerem
enormes e distorce a leitura.

```yaml
visual:
  globalType: "bar"
  showDataLabels: true         # quando há poucas barras e o valor exato importa
```

Baseline zero é obrigatório em barra (ver "Regras inegociáveis"). **Confira em
`lumo scaffold widget.Barline` como declarar o mínimo do eixo neste widget** em
vez de copiar de memória: o scaffold é a fonte de verdade da forma de campo.

Para rankings, vire na horizontal e ordene descendente — o olho percorre de cima para
baixo e o maior fica no topo:

```yaml
visual:
  globalType: "bar"
  orientation: "horizontal"
  orderColumns: ["<receita_col>:SUM"]
  orderColumnsDir: ["DESC"]
```

Quando há muitas categorias (> 12), prefira `orientation: "horizontal"` mesmo sem
ranking — labels na horizontal não se sobrepõem.

### Change over time — `Barline` (`globalType: line` / `area`)

Use quando a pergunta é "como evoluiu ao longo do tempo?"

- 1 série: prefira `area` com gradiente vertical (claro no fundo, cor sólida no topo).
  Transmite volume e tendência simultaneamente.
- 2–4 séries: `line`; cada linha em cor distinta da paleta Okabe-Ito (ver
  `design-tokens.md` §1).
- Mais que 4 séries: agrupe as menores em "Outros" antes de colocar no gráfico.

```yaml
visual:
  globalType: "area"
  xAxis:
    type: "datetime"           # garante ordenação cronológica correta
```

Nunca use `globalType: bar` quando o eixo X é uma sequência temporal — a forma da
curva é o dado principal, não a altura de cada barra individual.
(Exceção estética: colunas mensais à la "Total Sales por Month" dos overviews
executivos são aceitáveis quando a comparação mês a mês é o ponto.)

**Em dashboard executivo, série temporal NUNCA leva data label por ponto** —
`showDataLabels: false` + `showDataScale: true`. A leitura executiva é a forma da
curva; o valor exato mora no tooltip. Label em cada ponto é a reclamação nº 1 de
poluição visual de clientes (recipe completa em `widget-recipes.md § 4b`).

### Part-to-whole — `Pie` / `Barline` empilhado

**Até 4 partes:** Pie com `chartType: donut`. O buraco central acomoda o total ou o
rótulo principal, tornando o donut mais informativo que a pizza sólida.

```yaml
visual:
  chartType: "donut"
  showDataLabels: true         # percentual dentro de cada fatia
```

**5 ou mais partes:** Barline horizontal ordenado, ou empilhado (`stacked: true`) quando o todo importa. Mais de 4 fatias de pizza
tornam a comparação angular impossível — as barras empilhadas permitem comparar o todo
e cada parte pelo comprimento.

```yaml
visual:
  globalType: "bar"
  stackedBar: true             # 100% empilhado: stackedBarRelative
                               # área: stackedArea / stackedAreaRelative
```

### Ranking — `Barline` horizontal

Quando a questão é posição relativa ("quem vende mais?", "qual loja lidera?"), barras
horizontais com rótulos alinhados à esquerda são a forma mais clara. Combine com
`showDataLabels` para que o valor numérico apareça ao lado de cada barra — elimina a
necessidade de o usuário mapear ao eixo X.

### Distribution — `Barline` (histograma) / `Punchcard`

**Histograma de valor contínuo:** `Barline` com bins pré-calculados na query (faixa
de idade, faixa de ticket). Cada barra é uma faixa, a altura é a contagem — baseline
zero obrigatório.

**Padrão dia × hora:** `Punchcard`. Exibe a intensidade numa grade bidimensional
(coluna = hora do dia, linha = dia da semana). Ideal para identificar picos de uso,
volumes de venda por horário, distribuição de atendimentos.

```yaml
kind: widget
type: Punchcard
visual:
  colorScale:
    min: "#dbeafe"
    max: "#1e40af"
```

### Correlation — `Punchcard` / `Svelte` (scatter)

**Correlação em grade (padrão cruzado):** `Punchcard` — duas dimensões categóricas
cruzadas com intensidade de cor no centro.

**Scatter plot (variável contínua × contínua):** `Svelte` widget com Highcharts
`chart.type: 'scatter'`. O Horus não tem um widget nativo de scatter — use Svelte.
Para 3 variáveis, codifique a terceira no tamanho dos marcadores (bubble chart).

```yaml
kind: widget
type: Svelte
# componente Svelte implementa Highcharts scatter/bubble
```

### Deviation — `Barline` com cor divergente

Use quando a pergunta é "quanto estamos acima ou abaixo de uma referência?"
Configure `axisColoringExpression` para verde acima da meta e vermelho abaixo.
A paleta divergente canônica é RdBu — ver `design-tokens.md` §2 para os tokens exatos.

```yaml
visual:
  globalType: "bar"
  axisColoringType: "byExpression"
  axisColoringExpression: "if(value >= meta) return '#22c55e'; return '#ef4444';"
```

Desvio em barras divergentes (barras que crescem para cima e para baixo a partir do
zero) é outra opção quando a referência é zero ou a média — nesse caso o baseline zero
coincide com o ponto médio da divergência.

### Spatial — `Map`

**Choropleth (fill color):** intensidade da cor representa uma taxa, proporção ou
índice — algo onde regiões grandes não devem ter vantagem só por tamanho geográfico.
Exemplos: taxa de conversão por estado, índice de inadimplência por município.

**Símbolo proporcional (bubble):** tamanho do círculo representa um total absoluto.
Exemplos: soma de receita por cidade, volume de pedidos por praça.

```yaml
visual:
  colorScale:
    min: "#dbeafe"     # baixo
    max: "#1e40af"     # alto
```

Para paleta de choropleth, use sequencial (Blues, Greens, Viridis) — detalhes em
`design-tokens.md` §2.

### Flow — `Svelte` (sankey / chord)

O Horus não tem widget nativo de flow. Implemente via `Svelte` com Highcharts
`sankey` (fluxo linear de origem → destino) ou `dependencywheel` (chord, para fluxos
bidirecionais e circulares). Encode volume no espessura do fluxo.

### Single metric — `Kpi`

Use para o número mais importante do dashboard — o que todo mundo vê primeiro.
Combine sempre com `variation` (comparação ao período anterior) e `sparkline` (linha
de tendência embutida). Formato `reduced` (K/M/B) é obrigatório para volumes grandes.

```yaml
kind: widget
type: Kpi
visual:
  numberSize: 30
  titleSize: 16
  numberFormat:
    format: "reduced"
  numberColor:
    expression: "if(value>=0,'#22c55e','#ef4444')"
```

Ver `design-tokens.md` §3 para os tokens de cor semântica do Kpi.

### Lookup / detalhe — `Table` / `Matrix`

**Table:** lista de linhas com colunas configuradas via `fields`. Use quando o usuário
precisa encontrar um registro específico, exportar dados, ou ler valores exatos que um
gráfico não mostra com precisão suficiente.

**Matrix:** tabela dinâmica com `rows`, `columns` e `values`. Use quando há dois eixos
de dimensão e a interseção é o dado (ex.: produto × mês → receita).

Tabelas e matrizes não substituem gráficos — elas complementam. Coloque-as abaixo da
linha de KPIs e gráficos principais, como detalhe acionável.

### Forecast — `Forecast`

Use quando os dados históricos alimentam uma projeção futura. A banda de confiança
(CI) deve ser sempre visível — esconder a incerteza é enganoso. Diferencie
visualmente o histórico (linha sólida) da projeção (linha tracejada ou área sombreada).

```yaml
kind: widget
type: Forecast
visual:
  showConfidenceInterval: true
```

---

## Guia rápido: widget por pergunta

| A pergunta é… | Widget |
|---|---|
| Qual categoria tem mais? | `Barline` bar vertical |
| Qual a ordem? Quem lidera? | `Barline` bar horizontal + sort |
| Como evoluiu no tempo? | `Barline` line ou area |
| Qual a fatia de cada parte? | `Pie` donut (≤4) ou `Barline` horizontal/stacked (5+) |
| Como se distribui a frequência? | `Barline` histograma ou `Punchcard` |
| Há padrão por hora/dia da semana? | `Punchcard` |
| Há correlação entre X e Y? | `Svelte` scatter ou `Punchcard` |
| Quanto desviamos da meta? | `Barline` com cor divergente |
| Onde está no mapa (taxa)? | `Map` choropleth |
| Onde está no mapa (total)? | `Map` símbolo proporcional |
| Como flui de A para B? | `Svelte` sankey |
| Qual o número principal? | `Kpi` |
| Preciso ver os registros | `Table` ou `Matrix` |
| Qual a projeção futura? | `Forecast` |
