Interfaces de aplicativo Matplotlib (APIs) #
O Matplotlib tem duas interfaces de aplicativo principais ou estilos de uso da biblioteca:
Uma interface "Axes" explícita que usa métodos em um objeto Figure ou Axes para criar outros artistas e construir uma visualização passo a passo. Isso também foi chamado de interface "orientada a objetos".
Uma interface "pyplot" implícita que rastreia a última Figura e Eixos criados e adiciona Artistas ao objeto que acha que o usuário deseja.
Além disso, várias bibliotecas downstream (como pandas
e xarray ) oferecem um plot
método implementado diretamente em suas classes de dados para que os usuários possam chamar data.plot()
.
A diferença entre essas interfaces pode ser um pouco confusa, principalmente devido a trechos na web que usam uma ou outra ou, às vezes, várias interfaces no mesmo exemplo. Aqui, tentamos apontar como as interfaces "pyplot" e downstream se relacionam com a interface "Axes" explícita para ajudar os usuários a navegar melhor na biblioteca.
Interfaces nativas do Matplotlib #
A interface "Axes" explícita #
A interface "Axes" é como o Matplotlib é implementado, e muitas customizações e ajustes finos acabam sendo feitos neste nível.
Essa interface funciona instanciando uma instância de uma
Figure
classe ( fig
abaixo), usando um método de
subplots
método (ou similar) nesse objeto para criar um ou mais
Axes
objetos ( ax
abaixo) e, em seguida, chamando métodos de desenho nos eixos ( plot
neste exemplo):
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.subplots()
ax.plot([1, 2, 3, 4], [0, 0.5, 1, 0.2])
( Código fonte , png )
Chamamos isso de interface "explícita" porque cada objeto é referenciado explicitamente e usado para criar o próximo objeto. Manter referências aos objetos é muito flexível e nos permite personalizar os objetos depois de criados, mas antes de serem exibidos.
A interface "pyplot" implícita #
O pyplot
módulo sombreia a maioria dos
Axes
métodos de plotagem para fornecer o equivalente ao anterior, onde a criação da Figura e dos Eixos é feita pelo usuário:
import matplotlib.pyplot as plt
plt.plot([1, 2, 3, 4], [0, 0.5, 1, 0.2])
( Código fonte , png )
Isso pode ser conveniente, principalmente ao fazer um trabalho interativo ou scripts simples. Uma referência à figura atual pode ser recuperada usando
gcf
e aos eixos atuais por gca
. O pyplot
módulo retém uma lista de Figuras e cada Figura retém uma lista de Eixos na figura para o usuário, de modo que o seguinte:
import matplotlib.pyplot as plt
plt.subplot(1, 2, 1)
plt.plot([1, 2, 3], [0, 0.5, 0.2])
plt.subplot(1, 2, 2)
plt.plot([3, 2, 1], [0, 0.5, 0.2])
( Código fonte , png )
é equivalente a:
import matplotlib.pyplot as plt
plt.subplot(1, 2, 1)
ax = plt.gca()
ax.plot([1, 2, 3], [0, 0.5, 0.2])
plt.subplot(1, 2, 2)
ax = plt.gca()
ax.plot([3, 2, 1], [0, 0.5, 0.2])
( Código fonte , png )
Na interface explícita, isso seria:
import matplotlib.pyplot as plt
fig, axs = plt.subplots(1, 2)
axs[0].plot([1, 2, 3], [0, 0.5, 0.2])
axs[1].plot([3, 2, 1], [0, 0.5, 0.2])
( Código fonte , png )
Por que ser explícito? #
O que acontece se você tiver que retroceder e operar em um eixo antigo que não é referenciado por plt.gca()
? Uma maneira simples é chamar subplot
novamente com os mesmos argumentos. No entanto, isso rapidamente se torna deselegante. Você também pode inspecionar o objeto Figure e obter sua lista de objetos Axes, no entanto, isso pode ser enganoso (barras de cores também são Axes!). A melhor solução é provavelmente salvar um identificador para cada Axes que você criar, mas se você fizer isso, por que não simplesmente criar todos os objetos Axes no início?
A primeira abordagem é chamar plt.subplot
novamente:
import matplotlib.pyplot as plt
plt.subplot(1, 2, 1)
plt.plot([1, 2, 3], [0, 0.5, 0.2])
plt.subplot(1, 2, 2)
plt.plot([3, 2, 1], [0, 0.5, 0.2])
plt.suptitle('Implicit Interface: re-call subplot')
for i in range(1, 3):
plt.subplot(1, 2, i)
plt.xlabel('Boo')
( Código fonte , png )
A segunda é salvar um identificador:
import matplotlib.pyplot as plt
axs = []
ax = plt.subplot(1, 2, 1)
axs += [ax]
plt.plot([1, 2, 3], [0, 0.5, 0.2])
ax = plt.subplot(1, 2, 2)
axs += [ax]
plt.plot([3, 2, 1], [0, 0.5, 0.2])
plt.suptitle('Implicit Interface: save handles')
for i in range(2):
plt.sca(axs[i])
plt.xlabel('Boo')
( Código fonte , png )
No entanto, a maneira recomendada seria ser explícito desde o início:
import matplotlib.pyplot as plt
fig, axs = plt.subplots(1, 2)
axs[0].plot([1, 2, 3], [0, 0.5, 0.2])
axs[1].plot([3, 2, 1], [0, 0.5, 0.2])
fig.suptitle('Explicit Interface')
for i in range(2):
axs[i].set_xlabel('Boo')
( Código fonte , png )
Interfaces de "objeto de dados" da biblioteca de terceiros #
Algumas bibliotecas de terceiros optaram por implementar plotagem para seus objetos de dados, por exemplo data.plot()
, é visto em pandas
, xarray e outras bibliotecas de terceiros. Para fins ilustrativos, uma biblioteca downstream pode implementar um contêiner de dados simples que possui dados armazenados juntos e, em seguida, implementa um x
método :y
plot
import matplotlib.pyplot as plt
# supplied by downstream library:
class DataContainer:
def __init__(self, x, y):
"""
Proper docstring here!
"""
self._x = x
self._y = y
def plot(self, ax=None, **kwargs):
if ax is None:
ax = plt.gca()
ax.plot(self._x, self._y, **kwargs)
ax.set_title('Plotted from DataClass!')
return ax
# what the user usually calls:
data = DataContainer([0, 1, 2, 3], [0, 0.2, 0.5, 0.3])
data.plot()
( Código fonte , png )
Assim, a biblioteca pode ocultar todos os detalhes do usuário e pode fazer uma visualização apropriada para o tipo de dados, geralmente com bons rótulos, opções de mapas de cores e outros recursos convenientes.
Acima, no entanto, podemos não ter gostado do título fornecido pela biblioteca. Felizmente, eles nos devolvem os Axes do plot()
método e, entendendo a interface Axes explícita, poderíamos chamar:
para personalizar o título.ax.set_title('My preferred title')
Muitas bibliotecas também permitem que seus plot
métodos aceitem um
argumento ax opcional. Isso nos permite colocar a visualização em um Axes que colocamos e talvez personalizamos.
Resumo #
No geral, é útil entender a interface "Axes" explícita, pois é a mais flexível e subjacente às outras interfaces. Um usuário geralmente pode descobrir como descer para a interface explícita e operar nos objetos subjacentes. Embora a interface explícita possa ser um pouco mais detalhada para configurar, gráficos complicados geralmente acabam mais simples do que tentar usar a interface "pyplot" implícita.
Observação
Às vezes é confuso para as pessoas que importamos pyplot
para ambas as interfaces. Atualmente, o pyplot
módulo implementa a interface "pyplot", mas também fornece métodos de criação de figuras e eixos de nível superior e, por fim, ativa a interface gráfica do usuário, se uma estiver sendo usada. Portanto pyplot
, ainda é necessário, independentemente da interface escolhida.
Da mesma forma, as interfaces declarativas fornecidas pelas bibliotecas parceiras usam os objetos acessíveis pela interface "Axes" e geralmente os aceitam como argumentos ou os repassam dos métodos. Geralmente é essencial usar a interface "Axes" explícita para executar qualquer personalização da visualização padrão ou descompactar os dados em arrays NumPy e passar diretamente para o Matplotlib.
Apêndice: Interface "Axes" com estruturas de dados #
A maioria dos Axes
métodos permite ainda outro endereçamento de API passando um
objeto de dados para o método e especificando os argumentos como strings:
import matplotlib.pyplot as plt
data = {'xdat': [0, 1, 2, 3], 'ydat': [0, 0.2, 0.4, 0.1]}
fig, ax = plt.subplots(figsize=(2, 2))
ax.plot('xdat', 'ydat', data=data)
( Código fonte , png )
Apêndice: interface "pylab" #
Há uma outra interface que é altamente desencorajada, que é basicamente fazer . Isso permite que os usuários simplesmente chamem . Embora conveniente, isso pode levar a problemas óbvios se o usuário involuntariamente nomear uma variável com o mesmo nome de um método pyplot.from matplotlib.pyplot import *
plot(x, y)