Interfaces de aplicación Matplotlib (API) #

Matplotlib tiene dos interfaces de aplicación principales, o estilos de uso de la biblioteca:

  • Una interfaz explícita de "Ejes" que usa métodos en un objeto Figura o Ejes para crear otros Artistas y construir una visualización paso a paso. Esto también se ha llamado una interfaz "orientada a objetos".

  • Una interfaz "pyplot" implícita que realiza un seguimiento de la última figura y ejes creados, y agrega artistas al objeto que cree que el usuario desea.

Además, varias bibliotecas posteriores (como pandasy xarray ) ofrecen un plotmétodo implementado directamente en sus clases de datos para que los usuarios puedan llamar a data.plot().

La diferencia entre estas interfaces puede ser un poco confusa, en particular dados los fragmentos en la web que usan una u otra, o a veces varias interfaces en el mismo ejemplo. Aquí intentamos señalar cómo las interfaces "pyplot" y downstream se relacionan con la interfaz explícita "Axes" para ayudar a los usuarios a navegar mejor por la biblioteca.

Interfaces nativas de Matplotlib #

La interfaz explícita "Ejes" #

La interfaz "Ejes" es cómo se implementa Matplotlib, y muchas personalizaciones y ajustes terminan realizándose en este nivel.

Esta interfaz funciona instanciando una instancia de una Figureclase ( figabajo), usando un método de subplotsmétodo (o similar) en ese objeto para crear uno o más Axesobjetos ( axabajo), y luego llamando a métodos de dibujo en los Ejes ( ploten este ejemplo):

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 fuente , png )

../../_images/api_interfaces-1.png

Llamamos a esto una interfaz "explícita" porque se hace referencia explícita a cada objeto y se usa para crear el siguiente objeto. Mantener las referencias a los objetos es muy flexible y nos permite personalizar los objetos después de que se crean, pero antes de que se muestren.

La interfaz "pyplot" implícita #

El pyplotmódulo sombrea la mayoría de los Axesmétodos de trazado para dar el equivalente de lo anterior, donde la creación de la figura y los ejes se realiza para el usuario:

import matplotlib.pyplot as plt

plt.plot([1, 2, 3, 4], [0, 0.5, 1, 0.2])

( Código fuente , png )

../../_images/api_interfaces-2.png

Esto puede ser conveniente, especialmente cuando se realizan trabajos interactivos o guiones simples. Se puede recuperar una referencia a la Figura actual utilizando gcfy a los Ejes actuales mediante gca. El pyplotmódulo retiene una lista de Figuras, y cada Figura retiene una lista de Ejes en la figura para el usuario de modo que lo siguiente:

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 fuente , png )

../../_images/api_interfaces-3.png

es 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 fuente , png )

../../_images/api_interfaces-4.png

En la interfaz explícita, esto sería:

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 fuente , png )

../../_images/api_interfaces-5.png

¿Por qué ser explícito? #

¿Qué sucede si tiene que retroceder y operar en un eje antiguo al que no hace referencia plt.gca()? Una forma sencilla es subplotvolver a llamar con los mismos argumentos. Sin embargo, eso rápidamente se vuelve poco elegante. También puede inspeccionar el objeto Figure y obtener su lista de objetos Axes, sin embargo, eso puede ser engañoso (¡las barras de colores también son Axes!). La mejor solución es probablemente guardar un identificador para cada Axe que cree, pero si lo hace, ¿por qué no simplemente crear todos los objetos Axes al principio?

El primer enfoque es llamar de plt.subplotnuevo:

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 fuente , png )

../../_images/api_interfaces-6.png

El segundo es guardar un 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 fuente , png )

../../_images/api_interfaces-7.png

Sin embargo, la forma recomendada sería ser explícito desde el principio:

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 fuente , png )

../../_images/api_interfaces-8.png

Interfaces de "objeto de datos" de biblioteca de terceros #

Algunas bibliotecas de terceros han optado por implementar el trazado de sus objetos de datos, por ejemplo data.plot(), se ve en pandas, xarray y otras bibliotecas de terceros. Con fines ilustrativos, una biblioteca descendente puede implementar un contenedor de datos simple que tiene datos almacenados juntos y luego implementa un xmétodo :yplot

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 fuente , png )

../../_images/api_interfaces-9.png

Por lo tanto, la biblioteca puede ocultar todo lo esencial del usuario y puede hacer una visualización adecuada para el tipo de datos, a menudo con buenas etiquetas, opciones de mapas de colores y otras características convenientes.

Sin embargo, en lo anterior, es posible que no nos haya gustado el título que proporcionó la biblioteca. Afortunadamente, nos devuelven los Ejes del plot()método, y entendiendo la interfaz específica de los Ejes, podemos llamar: para personalizar el título.ax.set_title('My preferred title')

Muchas bibliotecas también permiten que sus métodos acepten un argumento hachaplot opcional . Esto nos permite colocar la visualización en unos Ejes que hemos colocado y quizás personalizados.

Resumen #

En general, es útil comprender la interfaz "Ejes" explícita, ya que es la más flexible y subyace a las otras interfaces. Por lo general, un usuario puede descubrir cómo desplegarse en la interfaz explícita y operar en los objetos subyacentes. Si bien la interfaz explícita puede ser un poco más detallada de configurar, las tramas complicadas a menudo terminarán siendo más simples que intentar usar la interfaz "pyplot" implícita.

Nota

A veces es confuso para las personas que importamos pyplotpara ambas interfaces. Actualmente, el pyplotmódulo implementa la interfaz "pyplot", pero también proporciona métodos de creación de figuras y ejes de nivel superior y, en última instancia, activa la interfaz gráfica de usuario, si se está utilizando una. Por pyplotlo tanto, todavía se necesita independientemente de la interfaz elegida.

Del mismo modo, las interfaces declarativas proporcionadas por las bibliotecas asociadas utilizan los objetos accesibles mediante la interfaz "Ejes" y, a menudo, los aceptan como argumentos o los devuelven desde los métodos. Por lo general, es esencial usar la interfaz explícita de "Ejes" para realizar cualquier personalización de la visualización predeterminada, o para desempaquetar los datos en matrices NumPy y pasarlos directamente a Matplotlib.

Apéndice: interfaz "Ejes" con estructuras de datos #

La mayoría Axesde los métodos permiten el direccionamiento de otra API pasando un objeto de datos al método y especificando los argumentos como cadenas:

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 fuente , png )

../../_images/api_interfaces-10.png

Apéndice: interfaz "pylab" #

Hay otra interfaz que se desaconseja encarecidamente, y es básicamente hacer . Esto permite a los usuarios simplemente llamar . Si bien es conveniente, esto puede generar problemas obvios si el usuario, sin saberlo, nombra una variable con el mismo nombre que un método pyplot.from matplotlib.pyplot import *plot(x, y)