Matplotlib Subplots: Criar Figuras Multipanel com plt.subplots()
Updated on
Figuras de painel único raramente são suficientes para análises reais. Você precisa comparar distribuições lado a lado, mostrar um gráfico de dispersão junto com seus resíduos, ou apresentar quatro métricas em um layout de dashboard. Sem subplots, você criaria figuras separadas que perdem sua relação visual quando apresentadas juntas.
A função plt.subplots() do Matplotlib cria figuras multipanel com eixos compartilhados, dimensionamento consistente e layouts flexíveis. Este guia cobre tudo, desde grades básicas até layouts assimétricos avançados.
Subplots Básicos
Linha Única
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
axes[0].plot(x, np.sin(x))
axes[0].set_title('Seno')
axes[1].plot(x, np.cos(x), color='orange')
axes[1].set_title('Cosseno')
axes[2].plot(x, np.tan(x), color='green')
axes[2].set_ylim(-5, 5)
axes[2].set_title('Tangente')
plt.tight_layout()
plt.show()Layout em Grade
import matplotlib.pyplot as plt
import numpy as np
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
x = np.linspace(0, 10, 100)
axes[0, 0].plot(x, x, 'b-')
axes[0, 0].set_title('Linear')
axes[0, 1].plot(x, x**2, 'r-')
axes[0, 1].set_title('Quadrático')
axes[1, 0].plot(x, np.sqrt(x), 'g-')
axes[1, 0].set_title('Raiz Quadrada')
axes[1, 1].plot(x, np.log(x + 1), 'm-')
axes[1, 1].set_title('Logarítmico')
plt.tight_layout()
plt.show()Eixos Compartilhados
Compartilhar eixos garante escalas consistentes para comparação:
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(2, 1.5, 1000)
# Compartilhar eixo X
fig, axes = plt.subplots(2, 1, figsize=(8, 6), sharex=True)
axes[0].hist(data1, bins=30, color='steelblue', alpha=0.7)
axes[0].set_ylabel('Contagem')
axes[0].set_title('Distribuição A')
axes[1].hist(data2, bins=30, color='coral', alpha=0.7)
axes[1].set_ylabel('Contagem')
axes[1].set_xlabel('Valor')
axes[1].set_title('Distribuição B')
plt.tight_layout()
plt.show()import matplotlib.pyplot as plt
import numpy as np
# Compartilhar ambos os eixos X e Y
fig, axes = plt.subplots(2, 3, figsize=(12, 8), sharex=True, sharey=True)
for i, ax in enumerate(axes.flat):
data = np.random.randn(100)
ax.hist(data, bins=20, color=f'C{i}', alpha=0.7)
ax.set_title(f'Amostra {i+1}')
plt.tight_layout()
plt.show()Controle de Espaçamento e Layout
tight_layout()
Ajusta automaticamente o espaçamento para evitar sobreposição:
import matplotlib.pyplot as plt
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
# ... adicionar gráficos ...
plt.tight_layout() # Auto-corrigir espaçamento
plt.show()subplots_adjust()
Controle manual do espaçamento:
import matplotlib.pyplot as plt
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
plt.subplots_adjust(
left=0.1, # Margem esquerda
right=0.95, # Margem direita
top=0.92, # Margem superior
bottom=0.08, # Margem inferior
wspace=0.3, # Espaço horizontal entre subplots
hspace=0.4, # Espaço vertical entre subplots
)
plt.show()Adicionar um Super Título
import matplotlib.pyplot as plt
import numpy as np
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
fig.suptitle('Funções Trigonométricas', fontsize=16, fontweight='bold')
x = np.linspace(0, 2 * np.pi, 100)
for ax, func, name in zip(axes, [np.sin, np.cos, np.tan], ['sin', 'cos', 'tan']):
ax.plot(x, func(x))
ax.set_title(name)
plt.tight_layout()
plt.show()GridSpec para Layouts Assimétricos
Quando você precisa de painéis de diferentes tamanhos, use GridSpec:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
fig = plt.figure(figsize=(12, 8))
gs = gridspec.GridSpec(2, 3, figure=fig)
# Grande painel esquerdo (abrange 2 linhas)
ax1 = fig.add_subplot(gs[:, 0])
ax1.plot(np.random.randn(100).cumsum())
ax1.set_title('Série Temporal (2 linhas)')
# Painéis superiores direitos
ax2 = fig.add_subplot(gs[0, 1])
ax2.bar(['A', 'B', 'C'], [3, 7, 5])
ax2.set_title('Gráfico de Barras')
ax3 = fig.add_subplot(gs[0, 2])
ax3.scatter(np.random.randn(50), np.random.randn(50))
ax3.set_title('Dispersão')
# Painel inferior largo (abrange 2 colunas)
ax4 = fig.add_subplot(gs[1, 1:])
ax4.hist(np.random.randn(500), bins=30, color='coral')
ax4.set_title('Histograma (2 colunas)')
plt.tight_layout()
plt.show()subplot2grid para Layout Baseado em Posição
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(12, 8))
# (linhas, cols), (linha_início, col_início), rowspan, colspan
ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=2)
ax2 = plt.subplot2grid((3, 3), (0, 2), rowspan=2)
ax3 = plt.subplot2grid((3, 3), (1, 0))
ax4 = plt.subplot2grid((3, 3), (1, 1))
ax5 = plt.subplot2grid((3, 3), (2, 0), colspan=3)
ax1.set_title('Topo Largo')
ax2.set_title('Direita Alto')
ax3.set_title('Meio Esquerda')
ax4.set_title('Meio Centro')
ax5.set_title('Inferior Largura Total')
plt.tight_layout()
plt.show()Iterando Sobre Subplots
import matplotlib.pyplot as plt
import numpy as np
# Achatar array de axes para fácil iteração
fig, axes = plt.subplots(2, 3, figsize=(12, 8))
datasets = [np.random.randn(100) for _ in range(6)]
colors = ['#e74c3c', '#3498db', '#2ecc71', '#f39c12', '#9b59b6', '#1abc9c']
for ax, data, color, i in zip(axes.flat, datasets, colors, range(6)):
ax.hist(data, bins=20, color=color, alpha=0.7)
ax.set_title(f'Conjunto de Dados {i+1}')
ax.set_xlabel('Valor')
ax.set_ylabel('Contagem')
plt.tight_layout()
plt.show()Remover Subplots Vazios
Quando você tem menos gráficos que posições na grade:
import matplotlib.pyplot as plt
import numpy as np
fig, axes = plt.subplots(2, 3, figsize=(12, 8))
data_count = 5 # Apenas 5 conjuntos de dados para 6 espaços
for i, ax in enumerate(axes.flat):
if i < data_count:
ax.plot(np.random.randn(50).cumsum())
ax.set_title(f'Gráfico {i+1}')
else:
ax.set_visible(False) # Ocultar subplot vazio
plt.tight_layout()
plt.show()Exploração Interativa Multipanel
Para exploração visual rápida onde você quer comparar diferentes visões do mesmo conjunto de dados interativamente, PyGWalker (opens in a new tab) permite criar dashboards arrastando e soltando colunas no Jupyter -- sem necessidade de código de subplots:
import pandas as pd
import pygwalker as pyg
df = pd.read_csv('your_data.csv')
walker = pyg.walk(df)FAQ
Como criar subplots no Matplotlib?
Use fig, axes = plt.subplots(linhas, colunas) para criar uma figura com uma grade de subplots. Acesse eixos individuais com axes[linha, coluna] para grades ou axes[i] para linhas/colunas únicas. Sempre chame plt.tight_layout() no final para evitar sobreposição de rótulos.
Como compartilhar eixos entre subplots?
Passe sharex=True ou sharey=True para plt.subplots(). Por exemplo, fig, axes = plt.subplots(2, 1, sharex=True) faz ambos os subplots compartilharem a mesma escala do eixo x. Isso é útil para comparar distribuições ou séries temporais.
Como criar subplots de tamanhos diferentes?
Use matplotlib.gridspec.GridSpec para layouts assimétricos. Crie uma grade e use notação de fatia para abranger múltiplas células: ax = fig.add_subplot(gs[0, :2]) cria um subplot abrangendo as duas primeiras colunas da primeira linha.
Como ajustar o espaçamento entre subplots?
Chame plt.tight_layout() para espaçamento automático. Para controle manual, use plt.subplots_adjust(wspace=0.3, hspace=0.4) onde wspace é o espaçamento horizontal e hspace é o espaçamento vertical.
Como adicionar um título acima de todos os subplots?
Use fig.suptitle('Meu Título', fontsize=16) para adicionar um super-título acima de todos os subplots. Pode ser necessário ajustar a margem superior com plt.subplots_adjust(top=0.92) ou chamar plt.tight_layout() para evitar sobreposição.
Conclusão
O plt.subplots() do Matplotlib é a base para figuras multipanel. Use-o com (linhas, colunas) para grades regulares, sharex/sharey para escalas consistentes, tight_layout() para espaçamento automático e GridSpec para layouts assimétricos. Para iteração rápida, achate o array de axes com axes.flat e percorra. Esses padrões cobrem a grande maioria das necessidades de visualização multipanel.