HOWTO · Matplotlib

Comment tracer un cercle dans Matplotlib

Dans Matplotlib, tracez un cercle à l’aide du patch `matplotlib.patches.Circle`, de l’équation du cercle ou d’un marqueur de nuage de points.

Sur cette page

Pour tracer un cercle géométrique dans Matplotlib, utilisez matplotlib.patches.Circle et ajoutez ce patch à un objet Axes. Vous pouvez aussi tracer un cercle à partir de son équation ou utiliser un marqueur de nuage de points pour obtenir rapidement un symbole circulaire. Le patch est généralement le choix le plus direct lorsque le cercle doit avoir un centre et un rayon exprimés en coordonnées de données.

Tracer un cercle avec matplotlib.patches.Circle

matplotlib.patches.Circle crée un patch à partir d’un centre (x, y) et d’un rayon. Ajoutez-le à un objet Axes avec add_patch et définissez un rapport d’aspect égal afin qu’une unité sur l’axe des x ait la même longueur à l’écran qu’une unité sur l’axe des y.

import matplotlib.pyplot as plt
from matplotlib.patches import Circle

fig, ax = plt.subplots()
ax.add_patch(Circle((2, 1), radius=0.75, fill=False, linewidth=2))
ax.set_aspect("equal", adjustable="box")
ax.set_xlim(0, 4)
ax.set_ylim(-1, 3)
ax.set_title("Circle patch")
plt.show()

Résultat du rendu de l’exemple avec le patch Circle : le contour d’un cercle non rempli, centré en (2, 1) avec un rayon de 0,75, sur des axes allant de 0 à 4 et de -1 à 3.

Modifiez le premier argument pour déplacer le centre et radius pour redimensionner le cercle. Définissez fill=True (valeur par défaut) pour le remplir, ou utilisez fill=False pour n’en tracer que le contour. Circle est un Artist ; vous pouvez donc aussi l’ajouter avec ax.add_artist(circle). Si un graphique existe déjà, plt.gcf().gca().add_artist(circle) ajoute le cercle aux axes de la figure courante. Utiliser explicitement un objet Axes est plus clair lorsque la figure contient plusieurs graphiques.

Si vous définissez manuellement les limites des axes, incluez toute l’étendue du cercle : pour un centre (cx, cy) et un rayon r, l’intervalle des x doit couvrir cx - r à cx + r, et celui des y doit couvrir cy - r à cy + r. Des limites qui s’arrêtent à l’intérieur de ces intervalles masquent une partie du patch ou de la courbe tracée à partir d’une équation. Prévoyez une marge suffisante si vous souhaitez aussi que le contour reste bien visible près du cadre.

Tracer un cercle à partir de son équation

Une équation paramétrique décrit les points qui composent un cercle. Pour un centre (cx, cy) et un rayon r, utilisez x = cx + r cos(theta) et y = cy + r sin(theta). Échantillonner les angles de zéro à 2π permet de tracer toute la courbe.

import numpy as np
import matplotlib.pyplot as plt

center_x, center_y = 2, 1
radius = 0.75
theta = np.linspace(0, 2 * np.pi, 200)
x = center_x + radius * np.cos(theta)
y = center_y + radius * np.sin(theta)

fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_aspect("equal", adjustable="box")
ax.set_title("Circle from a parametric equation")
plt.show()

Résultat du rendu de l’exemple paramétrique : une courbe circulaire tracée à partir des angles échantillonnés, centrée en (2, 1) avec un rayon de 0,75.

L’équation du cercle définie par son centre et son rayon, (x - cx)² + (y - cy)² = r², peut aussi être représentée par une courbe de niveau zéro. Soustrayez r**2 au membre de gauche, évaluez le résultat sur une grille maillée, puis tracez la courbe de niveau zéro. Choisissez des limites de grille qui englobent tout le cercle et conservez la même échelle sur les deux axes ; sinon, la courbe affichée peut sembler étirée.

import numpy as np
import matplotlib.pyplot as plt

center_x, center_y = 2, 1
radius = 0.75
x = np.linspace(center_x - radius - 0.25, center_x + radius + 0.25, 100)
y = np.linspace(center_y - radius - 0.25, center_y + radius + 0.25, 100)
X, Y = np.meshgrid(x, y)
values = (X - center_x) ** 2 + (Y - center_y) ** 2 - radius ** 2

fig, ax = plt.subplots()
ax.contour(X, Y, values, levels=[0])
ax.set_aspect("equal", adjustable="box")
ax.set_title("Circle from the center-radius equation")
plt.show()

Résultat du rendu de l’exemple de courbe de niveau : la courbe de niveau zéro de l’équation centre-rayon forme un cercle centré en (2, 1) avec un rayon de 0,75.

Tracer un cercle avec un marqueur de nuage de points

scatter trace un marqueur à chaque point de données fourni. Son argument s définit l’aire du marqueur en points carrés. Cette option convient donc à un symbole circulaire dont la taille visuelle reste liée à l’affichage, plutôt qu’à un cercle géométrique dont le rayon est mesuré en coordonnées de données.

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.scatter([2], [1], s=500, marker="o")
ax.set_xlim(0, 4)
ax.set_ylim(-1, 3)
ax.set_aspect("equal", adjustable="box")
ax.set_title("Circular scatter marker")
plt.show()

Résultat du rendu de l’exemple de nuage de points : un seul marqueur circulaire plein au point (2, 1), dont la taille est définie par l’argument s et non par un rayon en coordonnées de données.

Augmentez ou réduisez s pour modifier l’aire affichée du marqueur. Utilisez un patch Circle lorsque le rayon doit correspondre aux distances sur les axes du graphique ; choisissez un marqueur de nuage de points lorsque vous souhaitez un symbole de taille visuelle constante à un point de données.

Ce comportement, où la taille dépend de l’affichage, est utile pour mettre en évidence des points mesurés, marquer un centre ou placer des symboles sur des graphiques que les lecteurs peuvent agrandir. Le marqueur reste lié aux points typographiques tandis que l’échelle des axes change ; sa taille apparente ne représente donc pas une distance fixe dans les données tracées. Choisissez un patch ou une courbe définie par une équation lorsque le cercle représente un rayon que les lecteurs doivent pouvoir comparer aux autres valeurs des données.

Pourquoi un cercle peut ressembler à une ellipse

Tous les exemples ci-dessus définissent un rapport d’aspect égal avec set_aspect("equal", adjustable="box"). Sans cette ligne, Matplotlib utilise le rapport d’aspect automatique : l’objet Axes remplit son cadre et, comme ce cadre est plus large que haut, une unité sur l’axe des x s’affiche plus longue qu’une unité sur l’axe des y. Le patch reste un cercle en coordonnées de données, mais il ressemble à une ellipse à l’écran. L’exemple ci-dessous utilise le même centre et le même rayon que le premier exemple, sans la ligne qui fixe le rapport d’aspect.

import matplotlib.pyplot as plt
from matplotlib.patches import Circle

fig, ax = plt.subplots()
ax.add_patch(Circle((2, 1), radius=0.75, fill=False, linewidth=2))
ax.set_xlim(0, 4)
ax.set_ylim(-1, 3)
ax.set_title("Circle patch without an equal aspect ratio")
plt.show()

Le même patch Circle sans rapport d’aspect égal : le cercle est étiré en une large ellipse parce que le cadre des axes est plus large que haut.

La correction consiste à ajouter ax.set_aspect("equal", adjustable="box") avant de définir les limites, comme dans les exemples précédents. Les courbes définies par une équation et les courbes de niveau se déforment de la même façon : sans rapport d’aspect égal, chaque méthode de cet article semble étirée. Avec adjustable="box", l’objet Axes peut se réduire pour que les deux axes partagent la même échelle ; c’est le comportement attendu, pas une erreur dans les données.