Rappel : les programmes commencent par :
import numpy as np
import matplotlib.pyplot as plt
Nous avons déjà vu un premier tracé élémentaire : "Découverte de Python et de Jupyter > Premier tracé graphique" ; nous en présentons un autre plus loin : "Statistiques > Fréquence, histogramme".
Nous allons approfondir le sujet.
Concepts de base.
Exemple.
Considérons un tracé un peu plus avancé : il consiste en deux graphiques représentant les graphes des fonctions cosinus et sinus. Voici deux manières de le réaliser :
x = np.linspace(0, 2*np.pi, 50)
ycos = np.cos(x)
ysin = np.sin(x)
fig, liste_axes = plt.subplots(2, 1, constrained_layout=True)
fig.suptitle("Fonctions trigonométriques")
liste_axes[0].plot(x, ycos)
liste_axes[0].set_title("cosinus")
liste_axes[0].set_xlabel("x")
liste_axes[0].set_ylabel("y")
liste_axes[1].plot(x, ysin)
liste_axes[1].set_title("sinus", pad = 5)
liste_axes[1].set_xlabel("x")
liste_axes[1].set_ylabel("y")
plt.savefig("fonctions_trigo_pyplot.svg", format="svg")
Ou bien
x = np.linspace(0, 2*np.pi, 50)
ycos = np.cos(x)
ysin = np.sin(x)
plt.subplots(constrained_layout=True)
plt.suptitle("Fonctions trigonométriques")
plt.subplot(2, 1, 1)
plt.plot(x, ycos)
plt.title("cosinus")
plt.xlabel("x")
plt.ylabel("y")
plt.subplot(2, 1, 2)
plt.plot(x, ysin)
plt.title("sinus", pad = 5)
plt.xlabel("x")
plt.ylabel("y")
Analyse.
Première manière.
La création de deux graphiques se fait avec la commande codice_1 à laquelle on indique le fait qu'il y a 2 lignes et 1 colonne ; le paramètre codice_2 permet d'avoir une meilleure mise en page. Cette commande retourne deux identifiants : codice_3, l'identifiant de la figure, et codice_4, les identifiants des deux sous-figures.
La méthode codice_5 permet de créer un titre général. Pour chaque sous-figure (classe , que l'on pourrait traduire par « système d'axes »), on utilise les méthodes codice_6pour tracer une courbe, codice_7 pour lui donner un nom et les méthodes codice_8 et codice_9 pour les titres des axes.
La fonction codice_10 permet d'enregistrer la figure dans un fichier, ici au format SVG.
Au lieu d'utiliser une matrice codice_11, on peut aussi utiliser un n-uplet :
fig, (axes0, axes1) = plt.subplots(2, 1, constrained_layout=True)
axes0.plot(x, ycos)
axes1.plot(x, ysin)
L'image est constituée de plusieurs objets. Il y en a de deux types :
La codice_12 est un grand contenant, c'est lui qui contient tout le dessin ; on parle parfois de « toile » "()". Les codice_13 sont les différentes sous-figures ; il y en a ici 2. Les codice_17 (« axe » en français) — à ne pas confondre avec le terme codice_18 précédent — sont au nombre de deux par codice_18 : l'axe de "x" (codice_20) et l'axe des "y" (codice_21).
Seconde manière.
Chaque graphique est créé par la fonction codice_22. Les paramètres sont trois nombres : le nombre de lignes du tableau de figures, le nombre de colonnes de ce tableau, et le numéro de la cellule au sein du tableau en suivant le sens de lecture latin (de gauche à droite et de haut en bas). La création des graphiques est précédée de deux fonctions : codice_23 qui impose une répartition harmonieuse des graphiques, et codice_24 qui permet d'écrire un titre général.
Pour chaque graphique, on a les fonctions :
Styles de codage « pyplot » et « OO ».
On voit qu'il y a aussi deux styles de codage, deux manières de rédiger. La première est la manière « pyplot » : la figure est décrite comme un automate fini "()", elle ne peut avoir qu'un nombre fini d'états et les fonctions font des transitions entre deux états. On utilise aussi l'expression « à la manière de Matlab ». On utilise des fonctions de l'espace de nom codice_29, ici : codice_30, codice_10 et dans les exemples précédents, codice_32, <code>plt.hist()</code lang="python">, codice_27, codice_28, codice_26, codice_36 et codice_37.
La seconde manière est la manière « orientée objet » (OO) : comme nous avons défini des objets (la codice_12, les codice_18), nous pouvons utiliser des méthodes spécifiques à ces classes. C'est ainsi que nous avons les méthodes codice_40, codice_41, codice_42, codice_8 et codice_9.
Dans la manière OO, il faut donc connaître les identifiants des objets pour pouvoir utiliser leurs méthodes. La manière la plus simple est de créer explicitement les objets et d'assigner leur identifiant à des variables à cette occasion, par exemple :
fig, sysAxes = plt.subplots(1, 1)
courbe = sysAxes.plot(x, y)
ou bien
fig = plt.figure()
sysAxes = fig.add_subplot(1, 1, 1)
courbe = sysAxes.plot(x, y)
ou encore
fig = plt.figure()
sysAxes = plt.axes()
courbe = sysAxes.plot(x, y)
L'autre manière consiste à laisser pyplot tout créer tout seul, puis à récupérer les identifiants :
plt.plot(x, y)
fig = plt.gcf() # get current figure
sysAxes = plt.gca() # get current axes
courbe = sysAxes.lines[0]
ou bien
plt.plot(x, y)
fig = plt.gcf() # get current figure
sysAxes = fig.axes[0]
courbe = sysAxes.lines[0]
Mise en forme d'une courbe.
Considérons une courbe unique. Nous pouvons changer l'apparence de la courbe en passant des paramètres lors de sa création. La première manière consiste à utiliser une chaîne de caractères comprenant :
Par exemple :
plt.plot(x, y, "r--") # trait discontinu rouge
axes0 = plt.axes()
axes0.plot(x, y, "go") # cercles verts
Notez la différence entre codice_54 qui affiche à la fois un marqueur point et un trait continu, et codice_55 qui crée un trait mixte.
Méthodes avancées
Il est possible de passer les paramètres de manière plus explicite :
plt.plot(x, y, color="b", linestyle="dashed", marker="o")
L'attribut codice_56 peut être spécifié de plusieurs manières :
L'attribut codice_79 peut être indiqué par des caractères comme précédemment ; on peut également utiliser les noms : codice_80 (discontinu), codice_81 (mixte), codice_82 (pointillés), codice_83 (continu) ou bien codice_84 ou une chaîne vide (pas de tracé).
On peut ajouter d'autres attributs, en particulier
Avec le style de codage orienté objet, cela donne :
courbe = plt.plot(x, y)
courbe[0].set_linestyle("--")
courbe, = plt.plot(x, y)
courbe.set_linestyle("--")
plt.plot(x, y)
axes = plt.gca()
courbe = axes.lines[0]
courbe.set_linestyle("--")
Les principales méthodes des objets Line2D sont : codice_98, codice_99, codice_100, codice_101, codice_102 et tous les codice_103 (codice_104, codice_105codice_106, codice_107). 
Annotations.
Nous parlons ici le fait de placer des annotations sur une figure et non pas la notion d'annotation en programmation.
Il est possible de placer du texte avec la commande codice_108 où ("x", "y") sont les coordonnées, dans le repère du tracé, où l'on veut placer le texte, et "chaine" est une chaîne de caractères. On peut modifier l'orientation de ce texte avec le paramètre codice_109 exprimé en degrés, par exemple :
plt.text(0, 0, "origine", rotation=90)
Par ailleurs, la classe codice_13 dispose d'une méthode codice_111. Dans sa forme la plus simple, on indique une chaîne correspondant à l'étiquette et un doublet (2-uplet) ou une liste indiquant les coordonnées où placer l'étiquette. Par exemple :
x = np.linspace(0, 2*np.pi, 50)
ycos = np.cos(x)
courbe = plt.plot(x, ycos)
fig = plt.gcf() # get current figure
sysAxes = plt.gca() # get current axes
ymin = ycos.min() # trouve la veleur minimale de ycos
imin = ycos.argmin() # trouve l'indice correspondant au minimum
xmin = x[imin]
sysAxes.annotate("min", (xmin, ymin))
Telle quelle, l'étiquette empiète sur la courbe. On peut placer l'étiquette à des coordonnées particulières avec l'attribut codice_112 cet attribut reçoit un doublet ou une liste de coordonnées ("x", "y"). 
Par ailleurs, on peut relier l'étiquette au point visé avec l'attribut codice_113 ("", propriétés de la flèche). Cet attribut reçoit un dictionnaire de propriétés, codice_114 ou bien codice_115. Par exemple, pour avoir simplement un trait, ce dictionnaire contient codice_116 et pour une flèche, codice_117.
Par exemple, avec l'exemple précédent :
sysAxes.annotate("min", (xmin, ymin), xytext=(xmin+0.5, ymin+0.5), arrowprops=dict(arrowstyle="->"))
sysAxes.annotate("min", (xmin, ymin), xytext=(xmin+0.5, ymin+0.5), arrowprops={"arrowstyle":"-"})
Autres exemples de tracés 2D.
Par exemple avec :
x = np.linspace(0, 2*np.pi, 20)
y = np.sin(x)
fig, listeAxes = plt.subplots(3, 1, constrained_layout=True)
listeAxes[0].step(x, y)
listeAxes[1].bar(x, y, width = 0.03)
listeAxes[2].quiver(x[:-1], y[:-1], np.diff(x), np.diff(y), scale_units="xy", scale=1, angles="xy", width=0.02)
Gestion des échelles.
Pour fixer les valeurs extrêmes des axes, on utilise les commandes codice_118 et codice_119.
Pour avoir une échelle logarithmique, respectivement en "x" et en "y", on utilise les commandes codice_120 et codice_121. Ces fonctions peuvent recevoir les paramètres suivants :
On peut superposer une grille avec la commande codice_126.
S'il y a trop de graduations sur un axe, on peut réduire le nombre de graduations avec :
from matplotlib.ticker import NullFormatter
plt.gca().yaxis.set_minor_formatter(NullFormatter())
On peut imposer le fait d'avoir les mêmes échelles en "x" ou en "y" avec les mots-clefs codice_127 et codice_128. Par exemple :
fig = plt.figure()
ax1 = fig.add_subplot(2, 1, 1)
ax2 = fig.add_subplot(2, 1, 2, sharex=ax1)
ou bien
fig, axs = plt.subplots(2,1, sharex=True)
Si l'on veut que l'échelle en "x" soit la même que l'échelle en "y", on peut utiliser la méthode codice_129 des objets codice_130, par exemple
plt.gca().set_aspect("equal", adjustable="box")
Si l'on veut que le graphique soit carré, on utilise le mot-clef codice_131 de l'objet codice_17 :
plt.axis("square")
Plusieurs courbes sur un même système d'axes.
Pour mettre plusieurs courbes sur un même système d'axes, on peut soit les créer les unes après les autres :
plt.plot(x1, y1)
plt.plot(x2, y2)
Soit les mettre dans la même commande :
plt.plot(x1, y1, x2, y2)
Matplotlib définit lui-même des couleurs différentes. On peut bien évidemment forcer le style des courbes. On peut également ajouter une étiquette "()" qui sera ensuite affichée dans la légende :
plt.plot(x1, y1, "k", label="courbe 1")
plt.plot(x2, y2, "b", label="courbe 1")
plt.legend()
courbes = plt.plot(x1, y1, "k", x2, y2, "b")
courbes[0].set_label("courbe 1")
courbes[1].set_label("courbe 2")
plt.legend()
courbes = plt.plot(x1, y1, x2, y2)
courbes[0].set(color="k", label="courbe 1")
courbes[1].set(color="b", label="courbe 2")
plt.legend()
On peut choisir l'emplacement de la légende avec le paramètre codice_133 qui peut prendre les valeurs codice_134, codice_135, codice_136, codice_137… la valeur est composée de deux adjectifs :
Par exemple :
plt.legend(loc="upper right")
Tracé polaire.
Un tracé polaire s'obtient avec la commande codice_144, par exemple :
theta = np.linspace(0, 2*np.pi, 20) # angle
r = 1 + 0.2*np.random.randn(20) # rayon
plt.polar(theta, r) # courbe polaire
Voici un exemple avec deux courbes superposées et une mise en forme des graduations et de la légende :
import numpy as np
import matplotlib.pyplot as plt
angles = 2*np.pi*np.linspace(0, 1, 9) # huitièmes de cercle
radDeg = 180/np.pi # conversion radians → degrés
etoile = np.array([1, 0.2, 1, 0.2, 1, 0.2, 1, 0.2, 1]) # Tracé de l'étoile
vents = np.array([2.85, 3.34, 5.2, 4.025, 4.9, 9.63, 7.5, 2.35, 2.85]) # Fréquence (unité arbitraire)
vents = vents/vents.max() # normalisation
courbes = plt.polar(angles, etoile, angles, vents) # tracé
axes = plt.gca()
courbes[0].set(color="gray")
courbes[1].set(color="b", label="Fréquence des vents")
plt.legend(bbox_to_anchor=(1.45, 1.05), loc="upper right") # affichage à l'extérieur du tracé
axes.set_rticks([0.2, 0.4, 0.6, 0.8, 1]) # graduations radiales
axes.set_thetagrids(angles=radDeg*angles[0:-1], labels=("E", "NE", "N", "NO", "O", "SO", "S", "SE")) # graduations angulaires
plt.title("Rose des vents")
plt.savefig("rose_des_vents.svg", format="svg")
plt.show()
Cartes de valeurs et de vecteurs.
Lorsque l'on a une surface dans un espace à trois dimensions, de type "z" = ƒ("x"&htinsp;, "y" ), on peut afficher les données sur la forme d'une carte :
La fonction codice_148 permet d'afficher l'échelle de couleurs.
Par exemple :
x = np.linspace(0, 2*np.pi, 20)
y = x.copy()
X, Y = np.meshgrid(x, y)
Z = np.sin(X)*np.sin(Y)
fig, liste_axes = plt.subplots(2, 2, constrained_layout=True)
im1 = liste_axes[0, 0].contour(X, Y, Z)
fig.colorbar(im1, ax=liste_axes[0, 0])
im2 = liste_axes[0, 1].contourf(X, Y, Z)
fig.colorbar(im2, ax=liste_axes[0, 1])
im3 = liste_axes[1, 0].pcolormesh(X, Y, Z)
fig.colorbar(im3, ax=liste_axes[1, 0])
On peut choisir d'autres échelles de couleur "()" avec le paramètre codice_149 :
im3 = liste_axes[1, 0].pcolormesh(X, Y, Z, cmap="Greens")
Les échelles de couleur disponibles sont données à la page :
On peut aussi faire une carte d'un champ de vecteurs avec la commande codice_150 vue précédemment :
base = np.arange(10)
x, y = np.meshgrid(base, base)
ux = -0.1*y
uy = 0.1*x
plt.quiver(x, y, ux, uy, scale_units="xy", scale = 1, angles="xy")
Surfaces 3D.
Il est également possible de tracer des surfaces 3D. Il faut pour cela charger codice_151 du module codice_152 ; cela donne accès au paramètre codice_153 lorsque l'on définit le système d'axes. Par exemple :
from mpl_toolkits.mplot3d import Axes3D # permet d'utiliser l'attribut projection="3d"
x = np.linspace(0, 2*np.pi, 20)
y = x.copy()
X, Y = np.meshgrid(x, y)
Z = np.sin(X)*np.sin(Y)
plt.figure()
ax = plt.axes(projection="3d")
ax.contour(X, Y, Z, zdir="z", offset=-1) # projection sur le plan z = -1
ax.plot_surface(X, Y, Z, alpha=0.8)
On peut changer l'angle de vue du système d'axes avec les paramètres codice_154 (élévation) etcodice_155 (azimut). Par exemple
ax = plt.axes(projection="3d", elev = 10, azim = 90)
Mise en forme de la figure.
La figure dispose de paramètres de mise en forme :
Par exemple :
M = np.random.randn(50)
fig = plt.figure(figsize = [10, 6])
plt.plot(M)
Dessins.
Les dessins portent le nom de « pièces » "()". Les fonctions pour les créer se trouvent dans le module codice_166. Ces fonctions permettent de "créer" les pièces mais pour les "dessiner" (c'est-à-dire les mettre sur la « toile »), il faut utiliser la méthode codice_167.
Par exemple :
from matplotlib.patches import Circle, Polygon
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1]) # système d'axes occupant toute la figure
ax.set_xlim(0, 2) # axes gradués de 0 à 2
ax.set_ylim(0, 2)
cercle = Circle((0.25, 0.25), 0.1) # cercle de centre (0,25 ; 0,25) et de rayon 0,1
polygone = Polygon(1.5, 1.5], [2, 1.5], [1.75, 2) # polygone à trois sommets (triangle)
ax.add_patch(cercle)
ax.add_patch(polygone)
Le dessin des pièces une par une est un processus assez long. Il est intéressant de créer une collection et de dessiner cette collection d'un seul tenant. On a pour cela recours au module codice_168. Le code devient donc : 
from matplotlib.patches import Circle, Polygon
from matplotlib.collections import PatchCollection
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1])
ax.set_xlim(0, 2)
ax.set_ylim(0, 2)
cercle = Circle((0.25, 0.25), 0.1)
polygone = Polygon(1.5, 1.5], [2, 1.5], [1.75, 2)
coll = PatchCollection((cercle, polygone))
ax.add_collection(coll)
Il est possible de dessiner des chemins "()".
On a pour cela recours au module codice_169. Par exemple : 
from matplotlib.patches import PathPatch
from matplotlib.path import Path
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1])
ax.set_xlim(0, 2)
ax.set_ylim(0, 2)
chemin = Path(0.25, 0.5], [0.25, 1.5], [0.75, 1.5,
 [Path.MOVETO, Path.CURVE3, Path.CURVE3])
pieceChemin = PathPatch(chemin)
ax.add_patch(pieceChemin)
Ici, nous disons à la « plume » de se rendre "()" au point de coordonnées (0,25 ; 0,25), puis de tracer une courbe de Bézier quadratique "()" jusqu'au point (0,75 ; 1,5) avec comme point de contrôle intermédiaire (0,25 ; 1,5).
Transformation des objets graphiques.
Il est possible de faire subir des transformations linéaires aux objets graphiques. On utilise pour cela le module codice_170 (au pluriel) et l'attribut codice_171 (au singulier) des commandes pyplot.
Par exemple, pour tourner un objet de 90° :
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.transforms as transforms
donnees = np.random.randn(20) # points au hasard
base = plt.gca().transData # base de la transformation
rotation = transforms.Affine2D().rotate_deg(90) # rotation de 90°
plt.plot(donnees, transform = rotation + base)
La transformation codice_172 a normalement pour argument une matrice 3 × 3 classique en géométrie. Lorsque l'on est en deux dimensions, cette matrice a la forme
Les méthodes d'codice_173 permettent de générer automatiquement cette matrice. Par exemple, codice_174 (angle θ en radians ; on utilise codice_175 pour des angles en degrés) crée la matrice de rotation
On peut donner directement la matrice M (de type codice_176 avec codice_177. On peut indiquer les valeurs sous la forme d'une liste avec codice_178 (notez l'ordre des paramètres). 
Les couches de codice_179.
Pour bien comprendre la documentation du module codice_179, il faut comprendre sa structure en couches. Cela n'est pas indispensable pour l'utilisation élémentaire du module, mais connaître ce vocabulaire devient important pour une utilisation avancée.
Le module codice_179 est organisé en trois couches :
Il faut distinguer le tracé "()", qui consiste à traduire les données en objets à tracer en utilisant les artistes, et la publication "()" qui consiste à afficher les tracés à l'écran ou à les écrire dans un fichier. La publication est le rôle de la « face cachée » "()".
Cette structure en trois couches facilite la tâche de l'utilisateur : vous n'avez à vous concentrer qu'aux données et au type et style de tracé (en manipulant les artistes), la face cachée s'occupe de gérer la partie logicielle et matérielle (différence de système d'exploitation, de carte graphique, de format de fichier). La face cachée est donc une couche « abstraite », que l'utilisateur ne voit quasiment jamais.
Dans les cas les plus simples, l'utilisation d'un artiste provoque aussi sa publication : si l'on fait un codice_182, la courbe s'affiche à l'écran. Mais dans certains cas, il faut indiquer à Python de publier le graphique ; par exemple, s'il y a des opérations de tracé longues à faire, on a intérêt à tout afficher à la fin, une fois toutes les opérations faites. C'est la raison d'être des fonctions et méthodes codice_183 ou codice_184.
On distingue ainsi deux types d'artistes : les contenants et les primitives. Nous avons ainsi l'organisation suivante :
Notes et références.
Éléments de programmation < ↑ > Manipulation de matrices