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 pandas
et xarray ) proposent une plot
mé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
Figure
classe ( ci- fig
dessous), en utilisant une méthode
subplots
méthode (ou similaire) sur cet objet pour créer un ou plusieurs
Axes
objets ( ci- ax
dessous), puis en appelant des méthodes de dessin sur les Axes ( plot
dans 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 )
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 pyplot
module masque la plupart des
Axes
mé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 )
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
gcf
de et aux Axes courants par gca
. Le pyplot
module 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 )
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 )
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 )
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 subplot
avec 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 )
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 )
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 )
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 x
données y
stockées ensemble, puis implémente une plot
mé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 )
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 plot
mé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 pyplot
pour les deux interfaces. Actuellement, le pyplot
module 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 pyplot
est 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 Axes
mé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 )
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)