Matplotlib: Criando Visualizações Profissionais em Python
Guia completo do Matplotlib para criar gráficos de linhas, dispersão, barras e histogramas em Python com a interface orientada a objetos, subplots e exportação.
InSkillCoach
Matplotlib : Créer des Visualisations Professionnelles en Python
O Matplotlib é a biblioteca de visualização histórica e indispensável do ecossistema Python. Ela permite produzir todos os tipos de gráficos clássicos (linhas, dispersão, barras, histogramas) com controle total sobre cada elemento da figura, e exportar o resultado em formatos adequados tanto para a web quanto para impressão. Este guia apresenta a anatomia de uma figura, a interface orientada a objetos recomendada, os principais tipos de gráficos e as técnicas de personalização que fazem a diferença entre um gráfico rascunho e uma visualização profissional.
Anatomia de uma figura: Figure e Axes
Entender dois objetos basta para desbloquear toda a biblioteca:
- A Figure é o contêiner global: a “folha de papel” que sustenta todo o resto (tamanho, resolução, fundo).
- Os Axes representam uma área de plotagem: um sistema de eixos com suas graduações, seus rótulos e suas curvas. Uma figura pode conter um ou vários Axes.
Dentro de um Axes, encontramos os eixos x e y (xaxis, yaxis), as graduações (ticks), os rótulos (labels), o título, a legenda e os artistas (linhas, pontos, barras).
import matplotlib.pyplot as plt
import numpy as np
# Uma figura contendo um único Axes
fig, ax = plt.subplots(figsize=(8, 5))
print(type(fig)) # <class 'matplotlib.figure.Figure'>
print(type(ax)) # <class 'matplotlib.axes._axes.Axes'>
Interface pyplot vs interface orientada a objetos
O Matplotlib oferece dois estilos de escrita:
x = np.linspace(0, 2 * np.pi, 100)
# Estilo pyplot (à la MATLAB): um estado global implícito
plt.plot(x, np.sin(x))
plt.title("Sinus")
plt.xlabel("x")
plt.show()
# Estilo orientado a objetos: manipulamos explicitamente fig e ax
fig, ax = plt.subplots()
ax.plot(x, np.sin(x))
ax.set_title("Sinus")
ax.set_xlabel("x")
plt.show()
Recomendação: adote a interface orientada a objetos. O estilo pyplot é aceitável para um gráfico rápido em uma linha, mas assim que uma figura contém vários subgráficos ou é construída dentro de uma função, o estado global do pyplot se torna fonte de bugs. A interface orientada a objetos deixa explícito qual Axes recebe qual comando, e é o estilo usado na documentação oficial moderna. Todos os exemplos deste guia a utilizam.
Gráficos de linhas com plot
x = np.linspace(0, 10, 200)
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(x, np.sin(x), label="sin(x)", color="tab:blue", linewidth=2)
ax.plot(x, np.cos(x), label="cos(x)", color="tab:orange",
linestyle="--", linewidth=2)
ax.plot(x[::20], np.sin(x[::20]), "o", color="tab:blue",
markersize=6, label="points mesurés")
ax.set_title("Fonctions trigonométriques")
ax.set_xlabel("x (radians)")
ax.set_ylabel("Amplitude")
ax.legend()
ax.grid(True, alpha=0.3)
plt.show()
Os estilos de linha mais comuns: "-" (contínua), "--" (tracejada), ":" (pontilhada), "-." (mista). Os marcadores: "o" (círculo), "s" (quadrado), "^" (triângulo), "+", "x".
Gráficos de dispersão com scatter
O scatter permite variar o tamanho e a cor de cada ponto, o que codifica até quatro variáveis em um mesmo gráfico.
rng = np.random.default_rng(42)
x = rng.random(80)
y = 2 * x + rng.normal(0, 0.2, 80)
tailles = rng.integers(20, 200, 80)
couleurs = y - 2 * x # écart au modèle
fig, ax = plt.subplots(figsize=(8, 5))
nuage = ax.scatter(x, y, s=tailles, c=couleurs, cmap="viridis",
alpha=0.7, edgecolors="black", linewidths=0.5)
fig.colorbar(nuage, ax=ax, label="Résidu")
ax.set_title("Nuage de points avec taille et couleur variables")
ax.set_xlabel("x")
ax.set_ylabel("y")
plt.show()
Gráficos de barras
langages = ["Python", "SQL", "JavaScript", "Rust"]
popularite = [48, 35, 30, 12]
fig, ax = plt.subplots(figsize=(8, 5))
barres = ax.bar(langages, popularite, color="tab:blue", edgecolor="black")
# Rotular cada barra com seu valor
ax.bar_label(barres, fmt="%d %%")
ax.set_title("Popularité des langages (exemple)")
ax.set_ylabel("Part des répondants (%)")
ax.set_ylim(0, 55)
plt.show()
# Barras horizontais: mais legíveis quando as categorias têm nomes longos
fig, ax = plt.subplots(figsize=(8, 4))
ax.barh(langages, popularite, color="tab:green")
ax.set_xlabel("Part des répondants (%)")
plt.show()
Para barras agrupadas, desloque as posições com um offset numérico:
positions = np.arange(len(langages))
largeur = 0.35
annee_1 = [45, 33, 32, 8]
annee_2 = [48, 35, 30, 12]
fig, ax = plt.subplots(figsize=(8, 5))
ax.bar(positions - largeur / 2, annee_1, largeur, label="2025")
ax.bar(positions + largeur / 2, annee_2, largeur, label="2026")
ax.set_xticks(positions)
ax.set_xticklabels(langages)
ax.legend()
plt.show()
Histogramas
O histograma visualiza a distribuição de uma variável contínua.
rng = np.random.default_rng(0)
donnees = rng.normal(loc=170, scale=8, size=1000) # alturas simuladas
fig, ax = plt.subplots(figsize=(8, 5))
valeurs, bords, patches = ax.hist(donnees, bins=30, color="tab:blue",
edgecolor="white", alpha=0.85)
ax.axvline(donnees.mean(), color="red", linestyle="--",
label=f"Moyenne = {donnees.mean():.1f} cm")
ax.set_title("Distribution des tailles")
ax.set_xlabel("Taille (cm)")
ax.set_ylabel("Effectif")
ax.legend()
plt.show()
# density=True normaliza para comparar com uma densidade de probabilidade
# bins aceita um inteiro, uma lista de bordas, ou "auto"
Gráficos de pizza
Use com moderação (acima de 5 categorias, prefira barras horizontais):
parts = [45, 25, 20, 10]
etiquettes = ["Cloud", "Data", "Web", "Autres"]
fig, ax = plt.subplots(figsize=(6, 6))
ax.pie(parts, labels=etiquettes, autopct="%1.1f%%",
startangle=90, explode=(0.05, 0, 0, 0),
colors=["tab:blue", "tab:orange", "tab:green", "tab:gray"])
ax.set_title("Répartition du chiffre d'affaires")
plt.show()
# autopct exibe as porcentagens, explode destaca a primeira fatia
Subplots e grades de gráficos
plt.subplots(linhas, colunas) cria uma grade de Axes em uma única chamada.
x = np.linspace(0, 2 * np.pi, 100)
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
# axes é um array NumPy 2D de objetos Axes
axes[0, 0].plot(x, np.sin(x))
axes[0, 0].set_title("sin(x)")
axes[0, 1].plot(x, np.cos(x), color="tab:orange")
axes[0, 1].set_title("cos(x)")
axes[1, 0].plot(x, np.sin(2 * x), color="tab:green")
axes[1, 0].set_title("sin(2x)")
axes[1, 1].plot(x, np.exp(-x) * np.sin(5 * x), color="tab:red")
axes[1, 1].set_title("Oscillation amortie")
fig.suptitle("Grille de quatre graphiques", fontsize=14)
fig.tight_layout() # ajusta os espaçamentos para evitar sobreposições
plt.show()
# Eixos compartilhados: prático para comparar séries
fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=(8, 6))
Para layouts irregulares (um gráfico largo no topo, dois pequenos embaixo), explore fig.add_gridspec ou plt.subplot_mosaic.
Personalização: títulos, legendas, cores, estilos
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(x, np.sin(x), label="signal")
# Títulos e rótulos com controle tipográfico
ax.set_title("Titre principal", fontsize=14, fontweight="bold")
ax.set_xlabel("Temps (s)", fontsize=11)
ax.set_ylabel("Amplitude (V)", fontsize=11)
# Legenda: posição e aparência
ax.legend(loc="upper right", frameon=True, shadow=False)
# Limites e graduações
ax.set_xlim(0, 2 * np.pi)
ax.set_xticks([0, np.pi, 2 * np.pi])
ax.set_xticklabels(["0", "π", "2π"])
# Grade discreta
ax.grid(True, linestyle=":", alpha=0.5)
# Remover bordas supérfluas (estilo limpo)
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
plt.show()
As folhas de estilo permitem mudar a aparência global em uma linha:
print(plt.style.available[:5])
# ['Solarize_Light2', '_classic_test_patch', '_mpl-gallery', '_mpl-gallery-nogrid', 'bmh']
plt.style.use("seaborn-v0_8-whitegrid") # estilo sóbrio adequado para relatórios
# Ou localmente, sem modificar o estado global:
with plt.style.context("ggplot"):
fig, ax = plt.subplots()
ax.plot(x, np.sin(x))
Para as cores, prefira a paleta nomeada tab: (tab:blue, tab:orange, …): ela foi concebida para ser distinta e legível, inclusive, em grande medida, para pessoas daltônicas.
Anotações
x = np.linspace(0, 10, 200)
y = np.exp(-x / 3) * np.sin(2 * x)
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(x, y)
# Texto simples posicionado em coordenadas dos dados
ax.text(6, 0.4, "Zone amortie", fontsize=11, color="gray")
# Anotação com seta apontando para um ponto específico
i_max = y.argmax()
ax.annotate(f"Maximum ({x[i_max]:.2f}, {y[i_max]:.2f})",
xy=(x[i_max], y[i_max]), # ponta da seta
xytext=(3, 0.8), # posição do texto
arrowprops=dict(arrowstyle="->", color="black"))
# Linhas de referência
ax.axhline(0, color="black", linewidth=0.8)
ax.axvline(x[i_max], color="red", linestyle=":", alpha=0.6)
plt.show()
Escalas logarítmicas
Indispensáveis quando os dados cobrem várias ordens de grandeza.
n = np.logspace(1, 6, 50) # de 10 a 1.000.000
temps_lineaire = n * 1e-6
temps_quadratique = n ** 2 * 1e-9
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(n, temps_lineaire, label="O(n)")
ax.plot(n, temps_quadratique, label="O(n²)")
ax.set_xscale("log")
ax.set_yscale("log")
ax.set_xlabel("Taille de l'entrée n")
ax.set_ylabel("Temps (s)")
ax.set_title("Complexités comparées (échelle log-log)")
ax.legend()
ax.grid(True, which="both", alpha=0.3) # grade nas graduações principais e secundárias
plt.show()
# Atalhos: ax.semilogy(...), ax.semilogx(...), ax.loglog(...)
Salvando com savefig
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(x, np.sin(x))
# PNG em alta resolução para web ou slides
fig.savefig("graphique.png", dpi=200, bbox_inches="tight")
# SVG ou PDF: vetoriais, perfeitos para impressão e artigos
fig.savefig("graphique.svg", bbox_inches="tight")
fig.savefig("graphique.pdf", bbox_inches="tight")
# Fundo transparente para integração em slides
fig.savefig("graphique_transparent.png", dpi=200, transparent=True)
Dois parâmetros a lembrar: dpi controla a resolução dos formatos bitmap (150 a 300 para uma renderização nítida), e bbox_inches="tight" remove as margens brancas excedentes. Chame savefig antes de plt.show(), pois show pode esvaziar a figura em certos ambientes.
Integração com Pandas
Os DataFrames expõem um método .plot que delega ao Matplotlib e retorna um objeto Axes, que você pode então personalizar normalmente.
import pandas as pd
df = pd.DataFrame({
"mois": pd.date_range("2026-01-01", periods=6, freq="MS"),
"ventes": [120, 135, 150, 145, 170, 190],
"couts": [100, 110, 118, 120, 130, 140],
}).set_index("mois")
# O DataFrame plota diretamente em um Axes existente
fig, ax = plt.subplots(figsize=(8, 5))
df.plot(ax=ax, marker="o")
ax.set_title("Ventes et coûts mensuels")
ax.set_ylabel("k€")
ax.legend(["Ventes", "Coûts"])
plt.show()
# Outros atalhos: df.plot.bar(), df.plot.hist(), df.plot.scatter(x=..., y=...)
Uma palavra sobre o Seaborn
O Seaborn é uma camada sobre o Matplotlib voltada para estatística: ele produz em uma linha gráficos que exigiriam dezenas de linhas de Matplotlib puro (boxplots por categoria, matrizes de correlação, regressões com intervalo de confiança).
import seaborn as sns
tips = sns.load_dataset("tips")
fig, ax = plt.subplots(figsize=(8, 5))
sns.boxplot(data=tips, x="day", y="total_bill", hue="sex", ax=ax)
ax.set_title("Distribution des additions par jour")
plt.show()
Como o Seaborn retorna objetos Matplotlib, tudo o que você aprendeu neste guia (Axes, títulos, savefig) continua aplicável. Na prática, muitos analistas usam o Seaborn para exploração rápida e o Matplotlib puro para figuras finais com controle refinado.
Boas práticas
- Use a interface orientada a objetos (
fig, ax = plt.subplots()) em todo lugar: ela é explícita, composável e evita bugs de estado global. - Rotule tudo: um gráfico sem título, sem unidades nos eixos e sem legenda é inutilizável fora do contexto em que foi criado.
- Chame
fig.tight_layout()(ou crie a figura comlayout="constrained") para evitar sobreposição de textos. - Escolha o tipo de gráfico adequado: linha para uma evolução, barras para categorias, histograma para uma distribuição, dispersão para uma relação.
- Exporte em formato vetorial (SVG, PDF) para impressão e documentos, e em PNG com
dpi>=150para a web. - Limite a carga visual: remova bordas desnecessárias, atenue a grade com
alpha, reserve cores vivas para a informação importante. - Fixe a semente aleatória em exemplos e demonstrações para obter figuras reproduzíveis.
Conclusão
O Matplotlib se baseia em um modelo simples, a Figure contendo Axes, que a interface orientada a objetos permite manipular com precisão. Com os poucos tipos de gráficos apresentados aqui (linhas, dispersão, barras, histogramas), os subplots e as ferramentas de personalização, você cobre praticamente todas as necessidades de visualização em análise de dados. A integração nativa com o Pandas facilita a passagem dos dados ao gráfico, e o Seaborn acelera a exploração estatística. Para se aprofundar, a galeria oficial do Matplotlib é um recurso valioso: cada figura vem acompanhada de seu código-fonte completo.
Sobre InSkillCoach
Especialista em treinamento e tecnologias
Coach especializado em tecnologias avançadas e IA, apoiado pela GNeurone Inc.
Certificações:
- AWS Certified Solutions Architect – Professional
- Certificações Google Cloud
- Microsoft Certified: DevOps Engineer Expert
- Certified Kubernetes Administrator (CKA)
- CompTIA Security+
Comentários
Os comentários são alimentados pelo GitHub Discussions
Conecte-se com o GitHub para participar da discussão