Interfaces d'application Matplotlib (API) #

Matplotlib possède deux interfaces d'application majeures, ou styles d'utilisation de la bibliothèque :

  • Une interface "Axes" explicite qui utilise des méthodes sur un objet Figure ou Axes pour créer d'autres artistes, et construire une visualisation étape par étape. Cela a également été appelé une interface "orientée objet".

  • Une interface "pyplot" implicite qui garde une trace de la dernière figure et des derniers axes créés et ajoute des artistes à l'objet qu'il pense que l'utilisateur veut.

De plus, un certain nombre de bibliothèques en aval (comme pandaset xarray ) proposent une plotméthode implémentée directement sur leurs classes de données afin que les utilisateurs puissent appeler data.plot().

La différence entre ces interfaces peut être un peu déroutante, en particulier compte tenu des extraits sur le Web qui utilisent l'une ou l'autre, ou parfois plusieurs interfaces dans le même exemple. Ici, nous essayons de montrer comment les interfaces "pyplot" et en aval sont liées à l'interface explicite "Axes" pour aider les utilisateurs à mieux naviguer dans la bibliothèque.

Interfaces Matplotlib natives #

L'interface explicite "Axes" #

L'interface "Axes" est la façon dont Matplotlib est implémenté, et de nombreuses personnalisations et ajustements finissent par être effectués à ce niveau.

Cette interface fonctionne en instanciant une instance d'une Figureclasse ( ci- figdessous), en utilisant une méthode subplotsméthode (ou similaire) sur cet objet pour créer un ou plusieurs Axesobjets ( ci- axdessous), puis en appelant des méthodes de dessin sur les Axes ( plotdans cet exemple) :

import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.subplots()
ax.plot([1, 2, 3, 4], [0, 0.5, 1, 0.2])

( Code source , png )

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

Nous appelons cela une interface "explicite" car chaque objet est explicitement référencé et utilisé pour créer l'objet suivant. Garder les références aux objets est très flexible et nous permet de personnaliser les objets après leur création, mais avant qu'ils ne soient affichés.

L'interface implicite "pyplot" #

Le pyplotmodule masque la plupart des Axesméthodes de traçage pour donner l'équivalent de ce qui précède, où la création de la figure et des axes est effectuée pour l'utilisateur :

import matplotlib.pyplot as plt

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

( Code source , png )

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

Cela peut être pratique, en particulier lorsque vous effectuez un travail interactif ou des scripts simples. Une référence à la Figure courante peut être récupérée à l'aide gcfde et aux Axes courants par gca. Le pyplotmodule conserve une liste de Figures, et chaque Figure conserve une liste d'Axes sur la figure pour l'utilisateur afin que ce qui suit :

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])

( Code source , png )

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

est équivalent à:

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])

( Code source , png )

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

Dans l'interface explicite, ce serait :

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])

( Code source , png )

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

Pourquoi être explicite ? #

Que se passe-t-il si vous devez revenir en arrière, et opérer sur un ancien axe qui n'est pas référencé par plt.gca()? Un moyen simple consiste à rappeler subplotavec les mêmes arguments. Cependant, cela devient vite inélégant. Vous pouvez également inspecter l'objet Figure et obtenir sa liste d'objets Axes, cependant, cela peut être trompeur (les barres de couleur sont aussi des Axes !). La meilleure solution est probablement d'enregistrer une poignée pour chaque Axe que vous créez, mais si vous faites cela, pourquoi ne pas simplement créer tous les objets Axes au début ?

La première approche consiste à rappeler plt.subplot:

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')

( Code source , png )

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

La seconde consiste à enregistrer une poignée :

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')

( Code source , png )

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

Cependant, la méthode recommandée serait d'être explicite dès le départ :

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')

( Code source , png )

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

Interfaces "Data-object" de la bibliothèque tierce #

Certaines bibliothèques tierces ont choisi d'implémenter le traçage pour leurs objets de données, par exemple data.plot(), est vu dans pandas, xarray et d'autres bibliothèques tierces. À des fins d'illustration, une bibliothèque en aval peut implémenter un simple conteneur de données contenant des xdonnées ystockées ensemble, puis implémente une plotméthode :

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()

( Code source , png )

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

Ainsi, la bibliothèque peut cacher tous les détails à l'utilisateur et peut créer une visualisation appropriée au type de données, souvent avec de bonnes étiquettes, des choix de palettes de couleurs et d'autres fonctionnalités pratiques.

Dans ce qui précède, cependant, nous n'avons peut-être pas aimé le titre fourni par la bibliothèque. Heureusement, ils nous renvoient les Axes de la plot()méthode, et comprenant l'interface explicite des Axes, nous pourrions appeler : pour personnaliser le titre.ax.set_title('My preferred title')

De nombreuses bibliothèques permettent également à leurs plotméthodes d'accepter un argument optionnel ax . Cela nous permet de placer la visualisation dans un Axe que nous avons placé et peut-être personnalisé.

Résumé #

Dans l'ensemble, il est utile de comprendre l'interface explicite "Axes" car c'est la plus flexible et sous-jacente aux autres interfaces. Un utilisateur peut généralement comprendre comment accéder à l'interface explicite et opérer sur les objets sous-jacents. Bien que l'interface explicite puisse être un peu plus détaillée à configurer, les tracés compliqués seront souvent plus simples que d'essayer d'utiliser l'interface implicite "pyplot".

Noter

Il est parfois déroutant pour les personnes que nous importons pyplotpour les deux interfaces. Actuellement, le pyplotmodule implémente l'interface "pyplot", mais il fournit également des méthodes de création de figures et d'axes de haut niveau, et finalement fait tourner l'interface utilisateur graphique, si elle est utilisée. Donc pyplotest toujours nécessaire quelle que soit l'interface choisie.

De même, les interfaces déclaratives fournies par les bibliothèques partenaires utilisent les objets accessibles par l'interface "Axes", et les acceptent souvent comme arguments ou les renvoient depuis des méthodes. Il est généralement essentiel d'utiliser l'interface explicite "Axes" pour effectuer toute personnalisation de la visualisation par défaut, ou pour décompresser les données dans des tableaux NumPy et passer directement à Matplotlib.

Annexe : Interface "Axes" avec structures de données #

La plupart des Axesméthodes autorisent encore un autre adressage API en passant un objet de données à la méthode et en spécifiant les arguments sous forme de chaînes :

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)

( Code source , png )

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

Annexe : interface "pylab" #

Il y a une autre interface qui est fortement déconseillée, et qui consiste essentiellement à faire . Cela permet aux utilisateurs d'appeler simplement . Bien que pratique, cela peut entraîner des problèmes évidents si l'utilisateur nomme involontairement une variable du même nom qu'une méthode pyplot.from matplotlib.pyplot import *plot(x, y)