# Gráficos que respondem à pergunta

Escolher barras, linhas, histogramas e dispersão, com eixos, unidades e comparação correta.

Página: https://resumos.rgo.pt/cadeiras/ct-iadp/graficos/

Um gráfico deve tornar uma comparação mais fácil de ler. Antes de desenhar, identifica a variável do eixo horizontal, a medida do eixo vertical e a operação que produziu os pontos.

## Escolher o gráfico

| Pergunta | Gráfico | O que observar |
| --- | --- | --- |
| Que cidade vendeu mais? | Barras | Altura por categoria |
| Como evoluiu a faturação diária? | Linha | Ordem temporal e intervalos |
| Como se distribuem as quantidades? | Histograma | Frequência dentro de intervalos |
| Quantidade e total estão relacionados? | Dispersão | Um ponto por observação |
| Como varia a quantidade por cidade? | Caixa de bigodes | Mediana e dispersão, conforme a convenção |

Num gráfico de barras, cada barra representa uma categoria. Num histograma, cada barra representa um intervalo de valores. Mudar os intervalos pode mudar a impressão da distribuição, por isso indica como os escolheste.

## Figura e eixos

Matplotlib separa a figura, `Figure`, dos eixos, `Axes`. Usa `fig, ax = plt.subplots()` e chama métodos em `ax` para deixar claro em que gráfico estás a trabalhar.

```python
import pandas as pd
import matplotlib.pyplot as plt

vendas = pd.DataFrame({"cidade": ["Porto", "Porto", "Braga", "Braga"], "quantidade": [2, 3, 5, 4]})
totais = vendas.groupby("cidade")["quantidade"].sum().sort_index()
print(totais.to_dict())
fig, ax = plt.subplots(figsize=(5, 3))
barras = ax.bar(totais.index, totais.values)
ax.bar_label(barras)
ax.set_ylabel("Unidades vendidas")
ax.set_xlabel("Cidade")
ax.set_title("Total de unidades por cidade")
ax.set_ylim(0, 10)
fig.tight_layout()
plt.show()
```

A tabela imprime Braga 9 e Porto 5. Braga vendeu quatro unidades a mais. Não são nove vendas: estamos a somar quantidades, não a contar linhas.

![Barras horizontais com origem em zero: Porto vende cinco unidades e Braga nove. A barra de Braga é 1,8 vezes a de Porto.](https://resumos.rgo.pt/cadeiras/ct-iadp/graficos/figura-1.svg)

O gráfico usa o zero como origem para que as alturas sejam proporcionais às quantidades. Um eixo que começa em 4 exageraria a diferença visual. Os rótulos nas barras permitem conferir o valor sem estimar a altura.

## Linhas e intervalos

Ordena as datas antes de desenhar uma linha. Uma linha liga pontos e sugere uma evolução entre eles; não transformes categorias sem ordem numa curva.

```
fig, ax = plt.subplots()
ax.plot(datas, totais, marker="o")
ax.set_ylabel("Faturação diária, euros")
fig.autofmt_xdate()
```

Se faltam dias, decide se a linha deve interromper-se ou se existe uma regra que permite estimar. Um dia sem observação não é automaticamente um dia com zero vendas.

## Histograma e dispersão

```
ax.hist(quantidades, bins=[0, 2, 4, 6, 8])
ax.set_xlabel("Unidades por venda")
ax.set_ylabel("Número de vendas")
```

Os intervalos contam observações. Confere as convenções dos limites: em histogramas NumPy/Matplotlib, os intervalos são normalmente fechados à esquerda e abertos à direita, com o último a incluir também o extremo direito.

`ax.scatter(quantidades, totais)` põe um ponto por venda. Uma associação entre duas variáveis não prova uma causa. Se total é quantidade vezes preço, parte da associação vem da própria definição.

## Vários gráficos e exportação

`fig, axes = plt.subplots(1, 2)` cria dois eixos. Indica os rótulos e conserva escalas comparáveis quando pedes ao leitor que compare alturas. Uma legenda identifica séries, não substitui unidades nos eixos.

`fig.savefig("vendas.png", dpi=150, bbox_inches="tight")` guarda a figura localmente. Usa SVG para gráficos vetoriais quando esse formato é adequado ao destino. Guarda ou mostra a figura depois de definir rótulos e layout; `plt.close(fig)` liberta a figura quando já não é necessária.

## Gráficos de pandas

Uma Series ou DataFrame tem métodos `.plot` que usam normalmente Matplotlib. Para a Series `totais`, `totais.plot.bar()` desenha uma barra por cidade. `df.plot(x="data", y="total")` escolhe as colunas dos dois eixos. O objeto devolvido é um `Axes`, que podes usar para rótulos e unidades.

| Método | Resultado | Condição de leitura |
| --- | --- | --- |
| `.plot.bar()` | Barras verticais por categoria | Confere se são valores brutos ou agregados |
| `.plot.bar(stacked=True)` | Barras empilhadas | Cada segmento acrescenta ao total da categoria |
| `.plot.barh()` | Barras horizontais | Útil com nomes compridos |
| `.plot.area()` | Áreas, normalmente empilhadas | Indica se cada série é componente de um total |
| `.plot.box()` | Caixa de bigodes por coluna | Compara quartis e dispersão |
| `.plot.hexbin(x="x", y="y", gridsize=25)` | Contagem de pontos por hexágono | A cor precisa de uma escala de contagens |
| `.plot.pie()` | Frações de um total | Usa valores não negativos e um total positivo |
| `.plot.kde()` | Densidade estimada | Exige SciPy e depende do alisamento |

Num gráfico empilhado, o topo da última série representa a soma das componentes. Para comparar uma componente entre categorias, a posição sem origem comum pode dificultar a leitura; barras lado a lado podem ser mais adequadas.

Na caixa de bigodes habitual de Matplotlib, a caixa vai do primeiro ao terceiro quartil e a linha interior marca a mediana. Os bigodes alcançam observações dentro de 1,5 vezes a amplitude interquartil para além da caixa. Pontos exteriores são observações fora desses limites, não necessariamente erros. Confere a convenção do exercício.

Uma estimativa KDE desenha uma densidade suave a partir das observações. A altura não é uma contagem e a probabilidade corresponde a uma área sob a curva. A escolha da largura de banda muda o alisamento. Com poucas observações, não interpretes cada pico como um grupo real.

## Acumular e desenhar uma janela móvel

`cumsum()` substitui cada posição pela soma até essa posição. Se os valores forem 2, 3 e 4, o resultado acumulado é 2, 5 e 9. Nos exemplos com valores aleatórios dos notebooks, isto transforma incrementos numa trajetória acumulada. Não são vendas medidas.

Uma semente torna a sequência aleatória reproduzível no mesmo gerador. `rng = np.random.default_rng(123456)` cria um gerador explícito; os seus resultados não precisam de coincidir com os de `np.random.seed`, que usa outra interface. Uma distribuição uniforme de `random` e uma normal de `standard_normal` também representam hipóteses diferentes.

```
media_movel = valores.rolling(20).mean()
desvio_movel = valores.rolling(20).std()
ax.plot(valores.index, valores)
ax.plot(media_movel.index, media_movel)
ax.fill_between(
    valores.index,
    media_movel - 2 * desvio_movel,
    media_movel + 2 * desvio_movel,
    alpha=0.2,
)
```

Com a janela inteira exigida por defeito, os primeiros 19 resultados da média de 20 observações ficam em falta. A banda entre média e dois desvios de cada lado descreve dispersão local; não é automaticamente um intervalo de confiança para a média nem uma previsão garantida.

## Exercícios

Escolher uma distribuição

Queres mostrar como se distribuem quantidades por venda em intervalos numéricos. Que gráfico responde diretamente ao pedido?

Primeira pista

A unidade de análise é cada venda.

Mais uma pista

O eixo horizontal deve representar intervalos da quantidade.

Ver solução

Escolhe um histograma e indica os limites dos intervalos. O eixo vertical conta vendas, não unidades vendidas.

*   **Histograma.** Conta observações em intervalos de valores da quantidade.
*   **Linha por cidade.** Sugere uma ordem entre categorias e não mostra a distribuição em intervalos.
*   **Barras da faturação por cidade.** Responde a uma comparação de totais por categoria, outra pergunta.

#### Erros frequentes

Confundir uma barra por categoria com uma barra por intervalo numérico.

[Voltar à explicação](https://resumos.rgo.pt/cadeiras/ct-iadp/graficos/#escolher-o-gr%C3%A1fico)

Justificar a escala

Braga vendeu 9 unidades e Porto 5. Explica por que começar o eixo de barras em 4 muda a comparação visual.

Primeira pista

A altura da barra depende do ponto onde começa.

Mais uma pista

Com origem 4, as alturas visíveis são 9 - 4 e 5 - 4.

Ver solução

As alturas seriam 5 e 1, sugerindo uma razão de cinco para um. Os valores reais têm razão 9/5 = 1,8. Usa zero para conservar a proporção das alturas.

Confere a tua resposta:

*   Indiquei que as alturas passam a representar 5 e 1 unidades acima da origem escolhida.
*   Expliquei que isso exagera a razão visual entre os valores.
*   Conservei rótulos, unidades e zero na origem para a comparação de alturas.

#### Erros frequentes

Concluir que o rótulo numérico por si só elimina a distorção visual.

[Voltar à explicação](https://resumos.rgo.pt/cadeiras/ct-iadp/graficos/#figura-e-eixos)
