Seaborn com Python: Guia Prático de Gráficos Estatísticos

Cansado de programar?

Conheça a melhor e mais completa formação de Python e Django e sinta-se um programador verdadeiramente competente. Além de Python e Django, você também vai aprender Banco de Dados, SQL, HTML, CSS, Javascript, Bootstrap e muito mais!

Quero aprender Python e Django de Verdade! Quero aprender!
Suporte

Tire suas dúvidas diretamente com o professor

Projetos práticos

Projetos práticos voltados para o mercado de trabalho

Prática profissional

Formação moderna com foco na prática profissional

Resposta rápida

Seaborn é a biblioteca de gráficos estatísticos do Python, construída sobre o Matplotlib. Você passa um DataFrame e o nome das colunas: sns.histplot(data=df, x="coluna"). Ela cuida de cores, legenda e estatísticas (médias, densidade, intervalos de confiança).

1
2
3
4
5
6
import matplotlib.pyplot as plt
import seaborn as sns

gorjetas = sns.load_dataset("tips")      # dataset de exemplo (244 linhas)
sns.scatterplot(data=gorjetas, x="total_bill", y="tip", hue="time")
plt.show()                               # pontos coloridos por almoço/jantar

Resumo em 30 segundos:

  • Distribuição: histplot, kdeplot. Relação: scatterplot, lineplot. Categorias: countplot, barplot, boxplot, violinplot.
  • hue="coluna" colore por categoria e cria a legenda sozinho.
  • displot, relplot e catplot são figure-level: dividem em painéis com col=.
  • Heatmap de correlação: sns.heatmap(df.corr(numeric_only=True), annot=True).
  • Ajustes finos (títulos, eixos, tamanho) continuam sendo feitos com Matplotlib.

Salve salve Pythonista!

Você já sabe criar gráficos com Matplotlib, mas cansou de escrever dez linhas para fazer um boxplot por categoria com legenda decente? É aí que entra o Seaborn: ele entende DataFrames, agrupa os dados por você e calcula as estatísticas que o gráfico precisa, tudo em uma chamada.

Neste guia você vai ver os quatro grupos de gráficos que resolvem quase toda análise exploratória (distribuição, relação, categóricos e heatmap de correlação), a diferença entre funções axes-level e figure-level, e como personalizar e salvar. No final: tabela de decisão, erros comuns e exercícios resolvidos.

Todos os exemplos foram executados com seaborn 0.13.2 (a versão mais recente em setembro de 2026), matplotlib 3.10, pandas 2.3 e Python 3.10. Como os gráficos não aparecem aqui como imagem, cada exemplo traz o código completo e uma descrição do que você vai ver ao executá-lo.

Então… Bora pro post! :rocket:

Vá Direto ao Assunto…

O que é o Seaborn e quando usar

O Seaborn é uma biblioteca de visualização estatística criada por Michael Waskom. Ele não substitui o Matplotlib: usa o Matplotlib por baixo e acrescenta uma camada que conversa com o pandas.

Para um boxplot do valor da conta por dia da semana, no Matplotlib puro você separa os dados de cada dia em listas e configura os rótulos. No Seaborn:

1
sns.boxplot(data=gorjetas, x="day", y="total_bill")

Ele agrupa, ordena as categorias, rotula os eixos e aplica o estilo. Use o Seaborn quando os dados estão num DataFrame e você quer explorar (distribuições, comparação entre grupos, correlações) com estatística embutida. Continue no Matplotlib puro para gráficos muito customizados ou animações. Se precisa revisar a base, veja o post sobre como criar gráficos com Matplotlib, e para a estrutura de dados que o Seaborn consome, o post sobre DataFrames do pandas.

Instalação e primeiro gráfico

Instale num ambiente virtual. O pip traz junto as dependências obrigatórias (numpy, pandas e matplotlib):

1
pip install seaborn

O Seaborn vem com vários datasets de exemplo, carregados com sns.load_dataset(). Neste post vamos usar três: tips (contas e gorjetas de um restaurante), flights (passageiros de avião por mês, de 1949 a 1960) e penguins (medidas de pinguins de três espécies).

1
2
3
4
5
6
7
8
9
10
11
12
import matplotlib.pyplot as plt
import seaborn as sns

sns.set_theme()  # estilo padrão do seaborn (fundo cinza com grade)

gorjetas = sns.load_dataset("tips")
print(gorjetas.head())
print(gorjetas.shape)

ax = sns.scatterplot(data=gorjetas, x="total_bill", y="tip", hue="time")
ax.set(xlabel="Valor da conta (US$)", ylabel="Gorjeta (US$)", title="Conta x gorjeta")
plt.show()

Saída no terminal:

1
2
3
4
5
6
7
   total_bill   tip     sex smoker  day    time  size
0       16.99  1.01  Female     No  Sun  Dinner     2
1       10.34  1.66    Male     No  Sun  Dinner     3
2       21.01  3.50    Male     No  Sun  Dinner     3
3       23.68  3.31    Male     No  Sun  Dinner     2
4       24.59  3.61  Female     No  Sun  Dinner     4
(244, 7)

O que o gráfico mostra: uma nuvem de 244 pontos, com o valor da conta no eixo X (de 3 a 51 dólares) e a gorjeta no eixo Y (de 1 a 10 dólares). A nuvem sobe da esquerda para a direita: contas maiores tendem a ter gorjetas maiores. Os pontos azuis (almoço) se concentram nas contas abaixo de 25 dólares, e os laranja (jantar) se espalham por toda a faixa. A legenda “time” foi criada sozinha pelo hue.

O padrão se repete no post inteiro: data= recebe o DataFrame e x=, y= e hue= recebem nomes de colunas. A função devolve um Axes do Matplotlib, ajustado com ax.set().

Sem internet? O load_dataset() baixa o CSV do repositório seaborn-data no GitHub na primeira vez e guarda em cache em ~/seaborn-data. Se estiver offline, gere um DataFrame parecido no próprio código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np
import pandas as pd
import seaborn as sns

try:
    gorjetas = sns.load_dataset("tips")
except Exception as erro:  # sem internet: gera dados parecidos
    print("Sem acesso ao dataset:", type(erro).__name__)
    rng = np.random.default_rng(42)
    total = rng.uniform(5, 50, 244).round(2)
    gorjetas = pd.DataFrame({
        "total_bill": total,
        "tip": (total * rng.uniform(0.10, 0.20, 244)).round(2),
        "day": rng.choice(["Thur", "Fri", "Sat", "Sun"], 244),
        "time": rng.choice(["Lunch", "Dinner"], 244),
    })
print(gorjetas.shape)

Saída offline (simulada bloqueando a rede):

1
2
Sem acesso ao dataset: URLError
(244, 4)

Com dados próprios, o caminho normal é ler um arquivo com pd.read_csv(), como mostramos no post sobre importar CSV no pandas.

Funções axes-level e figure-level

Antes dos gráficos, um conceito que evita muita dor de cabeça. O Seaborn organiza as funções em três famílias, e cada família tem uma função figure-level e várias axes-level (visão geral na documentação):

Família Figure-level Axes-level
Relação relplot scatterplot, lineplot
Distribuição displot histplot, kdeplot, ecdfplot, rugplot
Categóricos catplot countplot, barplot, boxplot, violinplot, stripplot, swarmplot, pointplot
  • Axes-level desenha num único eixo (Axes) do Matplotlib, aceita ax= para ir num subplot específico e devolve o Axes. Tamanho: plt.subplots(figsize=(largura, altura)).
  • Figure-level cria a figura inteira, divide em painéis com col= e row= e devolve um FacetGrid. Tamanho: height= e aspect=. Não aceita ax=.

Guarde isso: ax.set_title() funciona no retorno de histplot, mas não no de displot. Voltaremos a esse ponto nos erros comuns.

Gráficos de distribuição: histplot, kdeplot e displot

Gráficos de distribuição respondem “como os valores de uma coluna se espalham?”. Comece pelos números:

1
2
3
4
5
6
7
8
9
10
11
12
import matplotlib.pyplot as plt
import seaborn as sns

sns.set_theme(style="whitegrid")
gorjetas = sns.load_dataset("tips")

print(gorjetas["total_bill"].describe().round(2))

ax = sns.histplot(data=gorjetas, x="total_bill", bins=20, kde=True)
ax.set(xlabel="Valor da conta (US$)", ylabel="Quantidade de mesas")
print(len(ax.patches), "barras")
plt.show()

Saída:

1
2
3
4
5
6
7
8
9
10
count    244.00
mean      19.79
std        8.90
min        3.07
25%       13.35
50%       17.80
75%       24.13
max       50.81
Name: total_bill, dtype: float64
20 barras

O que o gráfico mostra: um histograma com 20 barras entre 3 e 51 dólares. A barra mais alta fica perto de 16 dólares (37 mesas) e, a partir daí, as barras vão diminuindo para a direita, formando uma “cauda” longa até 50 dólares. O kde=True desenha por cima uma curva suave de densidade que acompanha esse formato. É uma distribuição assimétrica à direita, e por isso a média (19,79) é maior que a mediana (17,80).

Para comparar a distribuição entre grupos, o kdeplot com hue sobrepõe uma curva por categoria:

1
2
3
4
sns.kdeplot(data=gorjetas, x="total_bill", hue="time", fill=True, common_norm=False)
plt.show()

print(gorjetas.groupby("time", observed=True)["total_bill"].median())

Saída:

1
2
3
4
time
Lunch     15.965
Dinner    18.390
Name: total_bill, dtype: float64

O que o gráfico mostra: duas curvas preenchidas. A do almoço é mais alta e estreita, com pico perto de 14 dólares; a do jantar é mais larga, com pico perto de 17 e cauda mais longa. O common_norm=False dá área 1 a cada curva, para comparar formatos entre grupos de tamanhos diferentes (68 almoços e 176 jantares). A curva começa um pouco abaixo de zero porque a KDE suaviza os dados; cut=0 corta isso.

Para ver os grupos lado a lado em vez de sobrepostos, use a versão figure-level, displot, com col=:

1
2
3
4
g = sns.displot(data=gorjetas, x="total_bill", col="time", bins=15, height=3.5)
g.set_axis_labels("Valor da conta (US$)", "Mesas")
plt.show()
print(type(g).__name__, g.axes.shape)

Saída:

1
FacetGrid (1, 2)

O que o gráfico mostra: dois histogramas lado a lado (“time = Lunch” e “time = Dinner”) com o mesmo eixo Y, deixando evidente que há muito mais jantares.

Está curtindo esse conteúdo? :thumbsup:

Que tal receber 30 dias de conteúdo direto na sua Caixa de Entrada?

Sua assinatura não pôde ser validada.
Você fez sua assinatura com sucesso.

Assine as PyDicas e receba 30 dias do melhor conteúdo Python na sua Caixa de Entrada: direto e sem enrolação!

Gráficos de relação: scatterplot, lineplot e lmplot

Gráficos de relação mostram como duas variáveis numéricas se comportam juntas. O scatterplot você já viu no primeiro exemplo; além de hue, ele aceita style (formato do marcador) e size (tamanho do ponto) para codificar mais colunas.

Com dados em sequência (tempo), use lineplot. Atenção a um comportamento automático: se houver vários valores de Y para o mesmo X, o Seaborn agrega (calcula a média) e desenha uma faixa de intervalo de confiança de 95%:

1
2
3
4
5
6
voos = sns.load_dataset("flights")
print(voos.head(3))
print(voos.groupby("year")["passengers"].sum().iloc[[0, -1]])

sns.lineplot(data=voos, x="year", y="passengers")
plt.show()

Saída:

1
2
3
4
5
6
7
8
   year month  passengers
0  1949   Jan         112
1  1949   Feb         118
2  1949   Mar         132
year
1949    1520
1960    5714
Name: passengers, dtype: int64

O que o gráfico mostra: uma linha subindo de cerca de 127 passageiros (média mensal de 1949: 1520 / 12) para cerca de 476 em 1960, com uma faixa clara em volta, o intervalo de confiança da média dos 12 meses, que alarga com os anos. Para uma linha por mês, passe hue="month"; para tirar a faixa, errorbar=None.

Para ver a tendência com uma reta de regressão, use lmplot (figure-level) ou regplot (axes-level):

1
2
3
4
5
6
7
8
9
import numpy as np

sns.lmplot(data=gorjetas, x="total_bill", y="tip", hue="smoker", height=4)
plt.show()

print(gorjetas[["total_bill", "tip"]].corr().round(2))
for fumante, grupo in gorjetas.groupby("smoker", observed=True):
    inclinacao = np.polyfit(grupo["total_bill"], grupo["tip"], 1)[0]
    print(fumante, round(inclinacao, 3))

Saída:

1
2
3
4
5
            total_bill   tip
total_bill        1.00  0.68
tip               0.68  1.00
Yes 0.07
No 0.137

O que o gráfico mostra: a nuvem de pontos com duas retas, uma azul (fumantes) e uma laranja (não fumantes), cada uma com uma faixa sombreada de incerteza. A reta laranja é mais inclinada: entre não fumantes, a gorjeta cresce cerca de 0,137 dólar por dólar de conta, contra 0,070 entre fumantes (valores calculados com np.polyfit). A correlação geral entre conta e gorjeta é 0,68.

Gráficos categóricos: countplot, barplot, boxplot e violinplot

Quando o eixo X é uma categoria (dia, turno, espécie), você está no território dos gráficos categóricos. A coluna day do dataset é do tipo categórico do pandas, com a ordem ['Thur', 'Fri', 'Sat', 'Sun'], e o Seaborn respeita essa ordem.

countplot conta quantas linhas há em cada categoria:

1
2
3
ax = sns.countplot(data=gorjetas, x="day")
print([int(barra.get_height()) for barra in ax.patches])
plt.show()

Saída: [62, 19, 87, 76]

O que o gráfico mostra: quatro barras, na ordem quinta, sexta, sábado e domingo. Sábado é a mais alta (87 mesas) e sexta a mais baixa (19).

barplot mostra uma estatística (a média, por padrão) de uma coluna numérica por categoria, com uma barra de erro:

1
2
3
ax = sns.barplot(data=gorjetas, x="day", y="total_bill", errorbar="sd")
print([round(float(barra.get_height()), 2) for barra in ax.patches])
plt.show()

Saída: [17.68, 17.15, 20.44, 21.41]

O que o gráfico mostra: a média da conta por dia, crescendo no fim de semana (domingo é o maior, 21,41). O errorbar="sd" desenha uma linha preta vertical no topo de cada barra com mais ou menos um desvio padrão; o padrão seria o intervalo de confiança de 95% (errorbar=("ci", 95)). Para usar a mediana no lugar da média, passe estimator="median".

A média esconde muita coisa. O boxplot mostra a distribuição inteira de cada grupo: mediana, quartis e outliers.

1
2
3
4
sns.boxplot(data=gorjetas, x="day", y="total_bill", hue="smoker")
plt.show()

print(gorjetas.groupby("day", observed=True)["total_bill"].median())

Saída:

1
2
3
4
5
6
day
Thur    16.20
Fri     15.38
Sat     18.24
Sun     19.63
Name: total_bill, dtype: float64

O que o gráfico mostra: duas caixas por dia (azul para fumantes, laranja para não fumantes). A linha no meio é a mediana, as bordas são o 1º e o 3º quartis, os “bigodes” vão até 1,5 vez a altura da caixa e os círculos soltos são outliers (contas de 40 a 50 dólares). No fim de semana, as caixas dos fumantes são bem mais altas: os valores variam mais.

O violinplot tem a mesma sintaxe, mas troca a caixa por uma curva de densidade espelhada, mais larga onde os valores se concentram (você vai usá-lo no exercício 6).

Todas essas funções têm a versão figure-level catplot, com kind="count", "bar", "box", "violin" e outros, que aceita col= para facetas.

Heatmap de correlação com Seaborn

O heatmap é o gráfico mais usado para ver, de uma vez, a correlação entre todas as colunas numéricas de um DataFrame. O fluxo tem duas etapas: calcular a matriz com pandas e desenhar com sns.heatmap.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import matplotlib.pyplot as plt
import seaborn as sns

pinguins = sns.load_dataset("penguins")
medidas = pinguins.select_dtypes("number").rename(columns={
    "bill_length_mm": "bico_comp",
    "bill_depth_mm": "bico_alt",
    "flipper_length_mm": "nadadeira",
    "body_mass_g": "massa",
})
correlacao = medidas.corr()
print(correlacao.round(2))

plt.figure(figsize=(7, 5))
ax = sns.heatmap(correlacao, annot=True, fmt=".2f", cmap="coolwarm",
                 vmin=-1, vmax=1, square=True, linewidths=0.5)
ax.set_title("Correlação entre as medidas dos pinguins")
plt.show()

Saída:

1
2
3
4
5
           bico_comp  bico_alt  nadadeira  massa
bico_comp       1.00     -0.24       0.66   0.60
bico_alt       -0.24      1.00      -0.58  -0.47
nadadeira       0.66     -0.58       1.00   0.87
massa           0.60     -0.47       0.87   1.00

O que o gráfico mostra: uma grade 4 x 4 com o valor de cada correlação na célula. A diagonal (1,00) e o par nadadeira x massa (0,87) ficam vermelho-escuro: pinguins com nadadeira maior tendem a ser mais pesados. A linha da altura do bico fica azulada, porque ela se correlaciona negativamente com as demais.

annot=True com fmt=".2f" escreve os valores; cmap="coolwarm" é um mapa divergente (azul negativo, vermelho positivo); vmin=-1, vmax=1 fixam a escala, senão a cor mais forte seria o menor valor encontrado; e select_dtypes("number") (ou corr(numeric_only=True)) descarta as colunas de texto, que quebrariam o cálculo.

O heatmap também serve para qualquer tabela numérica, não só correlação. Com pivot, os voos viram uma grade mês x ano:

1
2
3
4
5
6
7
voos = sns.load_dataset("flights")
tabela = voos.pivot(index="month", columns="year", values="passengers")
print(tabela.iloc[:3, :4])

plt.figure(figsize=(9, 5))
sns.heatmap(tabela, cmap="YlGnBu")
plt.show()

Saída:

1
2
3
4
5
year   1949  1950  1951  1952
month                        
Jan     112   115   145   171
Feb     118   126   150   180
Mar     132   141   178   193

O que o gráfico mostra: 12 linhas (meses) por 12 colunas (anos), do amarelo-claro (poucos passageiros) ao azul-escuro (muitos). As cores escurecem da esquerda para a direita (crescimento ano a ano), e as linhas de julho e agosto são as mais escuras em cada ano (pico das férias). A célula mais escura é julho de 1960, com 622 passageiros.

Como personalizar e salvar gráficos do Seaborn

O visual global se ajusta com sns.set_theme(), que aceita style ("darkgrid", "whitegrid", "dark", "white", "ticks"), palette (paleta de cores) e context ("paper", "notebook", "talk", "poster", que escala fontes e linhas). Tudo que é detalhe de eixo continua sendo Matplotlib. Veja um painel com dois gráficos axes-level lado a lado e um gráfico figure-level com facetas:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import matplotlib.pyplot as plt
import seaborn as sns

sns.set_theme(style="ticks", palette="deep", context="talk")
gorjetas = sns.load_dataset("tips")

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
sns.histplot(data=gorjetas, x="tip", ax=ax1)
sns.boxplot(data=gorjetas, x="day", y="tip", hue="day", palette="Set2", legend=False, ax=ax2)
ax1.set_title("Distribuição das gorjetas")
ax2.set_title("Gorjeta por dia")
sns.despine()
fig.tight_layout()
fig.savefig("painel.png", dpi=150)

g = sns.relplot(data=gorjetas, x="total_bill", y="tip", col="time", height=4, aspect=1.2)
g.set_axis_labels("Conta (US$)", "Gorjeta (US$)")
g.set_titles("Refeição: {col_name}")
g.figure.suptitle("Conta x gorjeta", y=1.03)
g.savefig("facetas.png", dpi=150)
print([ax.get_title() for ax in g.axes.flat])

Saída:

1
['Refeição: Lunch', 'Refeição: Dinner']

O que os arquivos mostram: painel.png tem o histograma das gorjetas à esquerda e um boxplot por dia à direita, cada caixa com uma cor da paleta Set2, sem as bordas de cima e da direita (despine) e com fontes grandes (context="talk"). facetas.png tem duas dispersões lado a lado com os títulos personalizados. Regras práticas:

  • Em funções axes-level, o tamanho vem do figsize do Matplotlib e o posicionamento do ax=. Salve com plt.savefig() ou fig.savefig().
  • Em funções figure-level, o tamanho vem de height (altura de cada painel, em polegadas) e aspect (largura = height x aspect). Salve com g.savefig().
  • No Seaborn 0.13, palette sem hue está obsoleto. Para colorir cada barra ou caixa, repita a coluna do X no hue e passe legend=False, como no boxplot acima.

Chame plt.savefig() antes de plt.show(): depois que a janela é fechada, a figura é descartada e o arquivo sai em branco.

Todo gráfico bom nasce de dados bem manipulados em Python puro: listas, dicionários, funções e arquivos. Firmar essa base é o que fazemos na Jornada Python, do zero ao avançado:

Qual gráfico do Seaborn usar

Pergunta que você quer responder Tipo de dado Função axes-level Figure-level
Como os valores de uma coluna se distribuem? 1 numérica histplot, kdeplot displot
Duas variáveis numéricas andam juntas? 2 numéricas scatterplot, regplot relplot, lmplot
Como algo evolui no tempo? Tempo + numérica lineplot relplot(kind="line")
Quantos registros há por categoria? 1 categórica countplot catplot(kind="count")
Qual a média de um valor por categoria? Categórica + numérica barplot, pointplot catplot(kind="bar")
Como a distribuição muda entre grupos? Categórica + numérica boxplot, violinplot catplot(kind="box")
Quais colunas estão correlacionadas? Várias numéricas heatmap da corr() pairplot

Painel com subplots do Matplotlib pede axes-level; painéis por categoria com uma linha de código pedem figure-level.

Erros comuns

Estes são os erros e avisos que mais aparecem com Seaborn, com a última linha real da mensagem.

Nome de coluna errado (ValueError)

1
sns.histplot(data=gorjetas, x="Total_Bill")
1
ValueError: Could not interpret value `Total_Bill` for `x`. An entry with this name does not appear in `data`.

Correção: os nomes diferenciam maiúsculas de minúsculas. Confira com print(gorjetas.columns) e use x="total_bill".

Heatmap de correlação com colunas de texto (ValueError)

1
sns.heatmap(gorjetas.corr())
1
ValueError: could not convert string to float: 'No'

Correção: desde o pandas 2.0, corr() não ignora mais colunas de texto sozinho. Use gorjetas.corr(numeric_only=True) ou gorjetas.select_dtypes("number").corr().

Tratar um FacetGrid como Axes (AttributeError)

1
2
g = sns.displot(data=gorjetas, x="total_bill")
g.set_title("Contas")
1
AttributeError: 'FacetGrid' object has no attribute 'set_title'. Did you mean: 'set_titles'?

Correção: funções figure-level devolvem um FacetGrid. Para um título geral, use g.figure.suptitle("Contas"); para o título de cada painel, g.set_titles(...). Se só precisa de um gráfico, troque por ax = sns.histplot(...) e aí ax.set_title() funciona. Pelo mesmo motivo, sns.displot(..., ax=ax) ignora o ax e emite um UserWarning.

load_dataset sem internet ou com nome errado (URLError, ValueError)

1
2
sns.load_dataset("tips")      # sem conexão e sem cache
sns.load_dataset("gorjetas")  # nome que não existe
1
2
urllib.error.URLError: <urlopen error [Errno 111] Connection refused>
ValueError: 'gorjetas' is not one of the example datasets.

Correção: o primeiro erro aparece offline (a mensagem exata varia conforme a falha de rede); use o bloco try/except com DataFrame gerado mostrado acima ou leia um CSV local. O segundo pede um nome válido: sns.get_dataset_names() lista todos (tips, flights, penguins, iris, titanic, diamonds e outros).

Parâmetros obsoletos: palette sem hue e ci (FutureWarning)

1
2
sns.barplot(data=gorjetas, x="day", y="total_bill", palette="viridis")
sns.barplot(data=gorjetas, x="day", y="total_bill", ci=None)
1
2
FutureWarning: Passing `palette` without assigning `hue` is deprecated and will be removed in v0.14.0. Assign the `x` variable to `hue` and set `legend=False` for the same effect.
FutureWarning: The `ci` parameter is deprecated. Use `errorbar=None` for the same effect.

Correção: não é erro ainda, mas vai quebrar na 0.14. Muitos tutoriais antigos usam ci=. Escreva sns.barplot(data=gorjetas, x="day", y="total_bill", hue="day", palette="viridis", legend=False) e errorbar=None (ou errorbar="sd", errorbar=("ci", 95)).

Exercícios resolvidos

Tente resolver cada exercício antes de abrir a solução. Todos os códigos foram executados e as saídas conferidas; em todos, considere import matplotlib.pyplot as plt e import seaborn as sns já feitos e gorjetas = sns.load_dataset("tips") carregado quando o exercício usar o dataset de gorjetas.

Exercício 1. Crie um histograma da coluna tip com 10 barras e o título “Distribuição das gorjetas”. Confirme pelo código quantas barras foram desenhadas.

Ver solução
1
2
3
4
ax = sns.histplot(data=gorjetas, x="tip", bins=10)
ax.set(title="Distribuição das gorjetas", xlabel="Gorjeta (US$)")
print(len(ax.patches), ax.get_title())
plt.show()

Saída: 10 Distribuição das gorjetas

Cada barra do histograma é um retângulo guardado em ax.patches. O gráfico mostra a maior parte das gorjetas entre 2 e 4 dólares, com poucas acima de 6.

Exercício 2. Faça um gráfico de barras com a gorjeta média por dia, sem barra de erro, e imprima a altura de cada barra.

Ver solução
1
2
3
4
ax = sns.barplot(data=gorjetas, x="day", y="tip", errorbar=None)
alturas = [round(float(barra.get_height()), 2) for barra in ax.patches]
print(alturas)
plt.show()

Saída: [2.77, 2.73, 2.99, 3.26]

O barplot calcula a média por categoria (quinta, sexta, sábado, domingo). errorbar=None substitui o antigo ci=None.

Exercício 3. Crie a coluna pct_gorjeta (gorjeta como porcentagem da conta) e compare almoço e jantar com um boxplot. A mediana muda muito?

Ver solução
1
2
3
4
5
6
gorjetas["pct_gorjeta"] = gorjetas["tip"] / gorjetas["total_bill"] * 100

ax = sns.boxplot(data=gorjetas, x="time", y="pct_gorjeta")
ax.set(xlabel="Refeição", ylabel="Gorjeta (% da conta)")
print(gorjetas.groupby("time", observed=True)["pct_gorjeta"].median().round(1))
plt.show()

Saída:

1
2
3
4
time
Lunch     15.4
Dinner    15.5
Name: pct_gorjeta, dtype: float64

Não muda: a mediana fica em torno de 15% nos dois turnos. O jantar tem gorjetas maiores em dólares porque as contas são maiores, não porque as pessoas são mais generosas. Essa é a vantagem de olhar a proporção.

Exercício 4. Com o dataset penguins (removendo linhas com dados faltantes), faça um gráfico de dispersão do comprimento da nadadeira contra a massa, colorido por espécie. Qual espécie é a mais pesada?

Ver solução
1
2
3
4
5
6
pinguins = sns.load_dataset("penguins").dropna()
ax = sns.scatterplot(data=pinguins, x="flipper_length_mm", y="body_mass_g", hue="species")
ax.set(xlabel="Nadadeira (mm)", ylabel="Massa (g)")
print(len(pinguins), ax.get_legend().get_title().get_text())
print(pinguins.groupby("species")["body_mass_g"].mean().round())
plt.show()

Saída:

1
2
3
4
5
6
333 species
species
Adelie       3706.0
Chinstrap    3733.0
Gentoo       5092.0
Name: body_mass_g, dtype: float64

Gentoo, com média de 5092 g. No gráfico, os pontos Gentoo formam um grupo separado no canto superior direito (nadadeiras maiores e mais massa), enquanto Adelie e Chinstrap se misturam na parte de baixo.

Exercício 5. Monte o heatmap de correlação das colunas numéricas do penguins e descubra, pelo código, qual par de colunas diferentes tem a correlação mais forte (em valor absoluto).

Ver solução
1
2
3
4
5
6
7
8
pinguins = sns.load_dataset("penguins")
correlacao = pinguins.corr(numeric_only=True)

pares = correlacao.where(correlacao < 1).stack()
print(pares.abs().idxmax(), round(pares.abs().max(), 2))

sns.heatmap(correlacao, annot=True, fmt=".2f", cmap="coolwarm", vmin=-1, vmax=1)
plt.show()

Saída: ('flipper_length_mm', 'body_mass_g') 0.87

O where(correlacao < 1) esconde a diagonal (sempre 1), o stack() transforma a matriz numa série de pares e o idxmax() devolve o par com maior valor absoluto.

Exercício 6. Sem usar load_dataset, gere um DataFrame com 30 vendas para cada uma de três lojas (Centro com média 120, Shopping com média 150 e Bairro com média 90) e compare as lojas com um violinplot.

Ver solução
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np
import pandas as pd

rng = np.random.default_rng(7)
vendas = pd.DataFrame({
    "loja": np.repeat(["Centro", "Shopping", "Bairro"], 30),
    "valor": np.concatenate([
        rng.normal(120, 15, 30),
        rng.normal(150, 25, 30),
        rng.normal(90, 10, 30),
    ]).round(2),
})

ax = sns.violinplot(data=vendas, x="loja", y="valor", inner="quart")
print(vendas.groupby("loja")["valor"].median().round(1).sort_values())
plt.show()

Saída:

1
2
3
4
5
loja
Bairro       88.0
Centro      116.2
Shopping    150.4
Name: valor, dtype: float64

A semente fixa (default_rng(7)) garante os mesmos números em toda execução. No gráfico, o violino do Shopping é o mais alto e mais esticado (desvio padrão 25), e o do Bairro é o mais baixo e compacto (desvio 10).

Exercício 7 (questão de prova). Qual das funções abaixo é figure-level no Seaborn?

a) histplot
b) scatterplot
c) displot
d) boxplot

Ver solução

Resposta: c. displot cria a figura inteira, aceita col=/row= e devolve um FacetGrid. As outras três são axes-level: desenham num único Axes e aceitam ax=. As figure-level principais são relplot, displot e catplot.

Exercício 8 (questão de prova). Em sns.scatterplot(data=df, x="altura", y="peso", ???="sexo"), qual parâmetro faz os pontos terem cores diferentes para cada valor da coluna sexo, com legenda automática?

a) color
b) hue
c) palette
d) style

Ver solução

Resposta: b. hue mapeia uma coluna para cores. color define uma cor única para todos os pontos, palette escolhe quais cores o hue vai usar (não diz qual coluna colorir) e style muda o formato do marcador, não a cor.

Quer firmar a base de Python por trás da análise de dados, de estruturas de dados a automação de planilhas, com projetos guiados? Conheça o nosso curso de Python completo, a Jornada Python. E, para reforçar a base, veja a nossa lista de exercícios de Python.

Conclusão

Neste guia de Seaborn com Python, você aprendeu:

✅ Distribuição - histplot, kdeplot e displot
✅ Relação - scatterplot, lineplot e lmplot
✅ Categóricos - countplot, barplot, boxplot e violinplot
✅ Heatmap - Correlação com corr(numeric_only=True) e escala de -1 a 1
✅ Axes-level vs figure-level - ax= e figsize de um lado, col=, height e FacetGrid do outro
✅ Personalização - set_theme, paletas e como salvar

O próximo passo é a galeria oficial do Seaborn e a referência da API.

Se ficou com alguma dúvida, fique à vontade para deixar um comentário no box aqui embaixo! Será um prazer te responder! :wink:

Perguntas frequentes

O que é o Seaborn no Python?

Seaborn é uma biblioteca de visualização estatística construída sobre o Matplotlib e integrada ao pandas. Você passa um DataFrame e o nome das colunas, e ela cria histogramas, gráficos de dispersão, boxplots, heatmaps e outros, já com estilo, legenda e agregações estatísticas (médias, intervalos de confiança, densidade). É instalada com pip install seaborn e importada como import seaborn as sns.

Qual a diferença entre Seaborn e Matplotlib?

O Matplotlib é a base: controla cada detalhe do gráfico, mas exige mais código. O Seaborn usa o Matplotlib por baixo e oferece funções de alto nível que entendem DataFrames, agrupam por categoria com hue e calculam estatísticas sozinhas. Na prática, você cria o gráfico com Seaborn e faz ajustes finos (títulos, eixos, tamanho) com Matplotlib.

Como fazer um heatmap de correlação com Seaborn?

Calcule a matriz de correlação com pandas e passe para sns.heatmap: sns.heatmap(df.corr(numeric_only=True), annot=True, fmt='.2f', cmap='coolwarm', vmin=-1, vmax=1). O numeric_only=True ignora colunas de texto (sem ele o pandas 2 gera ValueError), annot=True escreve os valores nas células e vmin/vmax fixam a escala de -1 a 1.

O que faz o parâmetro hue no Seaborn?

O hue recebe o nome de uma coluna e colore os elementos do gráfico de acordo com ela, criando a legenda automaticamente. Por exemplo, sns.scatterplot(data=df, x='total_bill', y='tip', hue='smoker') pinta os pontos de fumantes e não fumantes com cores diferentes. Parâmetros parecidos são style (formato do marcador) e size (tamanho).

Qual a diferença entre histplot e displot?

histplot é uma função axes-level: desenha em um único eixo do Matplotlib e aceita ax= para ser colocada num subplot. displot é figure-level: cria a figura inteira e permite dividir o gráfico em painéis com col= e row=, devolvendo um FacetGrid. O mesmo vale para scatterplot/relplot e boxplot/catplot.

load_dataset do Seaborn precisa de internet?

Sim, na primeira vez. sns.load_dataset('tips') baixa o arquivo CSV do repositório seaborn-data no GitHub e guarda uma cópia em cache (por padrão em ~/seaborn-data). Sem conexão e sem cache, ele gera URLError. Em ambientes offline, carregue seus próprios dados com pd.read_csv ou gere um DataFrame no código.

Como salvar um gráfico do Seaborn em arquivo?

Para funções axes-level (histplot, scatterplot, boxplot), use plt.savefig('grafico.png', dpi=150, bbox_inches='tight') antes de plt.show(). Para funções figure-level (displot, relplot, catplot), use o objeto devolvido: g = sns.relplot(...) e depois g.savefig('grafico.png', dpi=150). O formato é definido pela extensão: png, svg, pdf.

Em uma questão de prova, qual função do Seaborn é figure-level: histplot, scatterplot, displot ou boxplot?

A resposta é displot. As funções figure-level do Seaborn são relplot, displot e catplot (além de lmplot, jointplot e pairplot): elas criam a figura inteira e aceitam col= e row= para facetas. histplot, scatterplot e boxplot são axes-level e desenham em um único eixo.

Começe agora sua Jornada na Programação!

Não deixe para amanhã o sucesso que você pode começar a construir hoje!

#newsletter Olá :wave: Curtiu o artigo? Então faça parte da nossa Newsletter! Privacidade Não se preocupe, respeitamos sua privacidade. Você pode se descadastrar a qualquer momento.