#3 - Interface Orientada a Objetos do Matplotlib: Figure e Axes

A diferença entre a interface implícita do pyplot e a interface orientada a objetos do Matplotlib, usando plt.subplots() para criar Figure e Axes.

#3 - Interface Orientada a Objetos do Matplotlib: Figure e Axes

Depois de uma pausa pra aprofundar em Pandas, a série volta ao Matplotlib. Até agora, todo gráfico foi feito chamando funções soltas do pyplotplt.plot(), plt.title(), plt.grid() — cada uma mexendo “no gráfico atual”, meio que por trás dos panos. Essa é a chamada interface implícita, ótima pra gráficos rápidos e scripts curtos. Mas o Matplotlib também oferece uma interface orientada a objetos, onde você guarda e manipula diretamente os objetos Figure e Axes — e é essa interface que dá controle fino quando o gráfico fica mais complexo.

pyplot vs. orientação a objetos

Todo gráfico do Matplotlib é composto por dois objetos principais:

Quando você chama plt.plot() direto, o Matplotlib cria (ou reaproveita) uma Figure e um Axes implicitamente, sem você precisar nomeá-los. Na interface orientada a objetos, você cria esses dois objetos você mesmo, com plt.subplots(), e chama os métodos diretamente neles.

Exemplo 1 - o mesmo gráfico, nas duas interfaces

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)
y = np.sin(x)

# interface implícita (pyplot)
plt.plot(x, y)
plt.title("Onda Senoidal")
plt.xlabel("x")
plt.ylabel("sen(x)")
plt.show()
# interface orientada a objetos
fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(x, y)
ax.set_title("Onda Senoidal")
ax.set_xlabel("x")
ax.set_ylabel("sen(x)")
plt.show()

Os dois trechos produzem exatamente o mesmo gráfico. A diferença é que no segundo, fig e ax são variáveis de verdade — dá pra passá-las adiante, guardá-las, ou voltar a mexer nelas mais tarde, o que fica difícil de controlar só com plt.algumacoisa().

Criando Figure e Axes com subplots()

plt.subplots() é a forma mais comum de criar os dois objetos de uma vez — mesmo quando você só precisa de um único gráfico:

Exemplo 2 - controlando o tamanho da figura

fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(x, y)
plt.show()

O parâmetro figsize recebe uma tupla (largura, altura) em polegadas, e controla o tamanho da Figure inteira — não existe um equivalente direto disso na interface implícita sem passar por plt.figure(figsize=...) antes do plt.plot().

Exemplo 3 - o padrão set_* nos métodos do Axes

Repare que os métodos chamados em ax levam o prefixo set_: ax.set_title(), ax.set_xlabel(), ax.set_ylabel(), em vez de plt.title(), plt.xlabel(), plt.ylabel(). É um padrão consistente em praticamente todo atributo do Axes — inclusive ax.set_xlim() e ax.set_ylim(), pra definir os limites dos eixos manualmente:

fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(x, y)
ax.set_xlim(0, 10)
ax.set_ylim(-1.5, 1.5)
plt.show()

Múltiplos eixos numa mesma figura

plt.subplots() também aceita o número de linhas e colunas da grade, retornando um array de Axes em vez de um único objeto — a mesma ideia do plt.subplot() que você viu no primeiro post da série, só que na interface orientada a objetos.

Exemplo 4 - uma grade 2x2

fig, axs = plt.subplots(2, 2, figsize=(8, 6))

axs[0, 0].plot(x, np.sin(x))
axs[0, 0].set_title("Seno")

axs[0, 1].plot(x, np.cos(x))
axs[0, 1].set_title("Cosseno")

axs[1, 0].plot(x, np.sin(x) * np.cos(x))
axs[1, 0].set_title("Seno × Cosseno")

axs[1, 1].plot(x, -np.sin(x))
axs[1, 1].set_title("Seno invertido")

fig.suptitle("Funções Trigonométricas")
plt.tight_layout()
plt.show()

Isso desenha uma grade de 2 linhas por 2 colunas, com um gráfico diferente em cada posição, acessada como axs[linha, coluna]. fig.suptitle() adiciona um título geral no topo da figura inteira — o equivalente orientado a objetos do plt.suptitle() visto anteriormente — e plt.tight_layout() ajusta automaticamente o espaçamento entre os subgráficos pra evitar que títulos e rótulos se sobreponham.

Nota: quando a grade tem só uma linha ou uma coluna (por exemplo, plt.subplots(1, 3)), o retorno é um array de uma dimensão, acessado como axs[0], axs[1], axs[2] — sem o segundo índice.

Quando usar cada interface

Não existe uma resposta única, mas uma régua prática que costuma funcionar bem:

Vale notar que os dois estilos se misturam sem problema: é comum criar fig, ax = plt.subplots() e ainda assim chamar plt.show() no final, como nos exemplos deste post.

Com Figure e Axes sob controle direto, os próximos posts da série vão explorar recursos que ficam mais naturais nessa interface: legendas, escalas de eixo e anotações.

Fonte adaptada: Matplotlib - Object-Oriented Interface, Matplotlib - Figure Class, Matplotlib - Axes Class