0%
Matplotlib : Créer des Visualisations Professionnelles en Python

Matplotlib : Créer des Visualisations Professionnelles en Python

Guide complet de Matplotlib pour créer courbes, nuages de points, barres et histogrammes en Python avec l'interface orientée objet, subplots et export.

I

InSkillCoach

· min

Matplotlib : Créer des Visualisations Professionnelles en Python

Matplotlib est la bibliothèque de visualisation historique et incontournable de l’écosystème Python. Elle permet de produire tous les types de graphiques classiques (courbes, nuages de points, barres, histogrammes) avec un contrôle total sur chaque élément de la figure, et d’exporter le résultat dans des formats adaptés au web comme à l’impression. Ce guide présente l’anatomie d’une figure, l’interface orientée objet recommandée, les principaux types de graphiques et les techniques de personnalisation qui font la différence entre un graphique brouillon et une visualisation professionnelle.

Anatomie d’une figure : Figure et Axes

Comprendre deux objets suffit à débloquer toute la bibliothèque :

  • La Figure est le conteneur global : la « feuille de papier » qui porte tout le reste (taille, résolution, fond).
  • Les Axes représentent une zone de tracé : un système d’axes avec ses graduations, ses étiquettes et ses courbes. Une figure peut contenir un ou plusieurs Axes.

À l’intérieur d’un Axes, on trouve les axes x et y (xaxis, yaxis), les graduations (ticks), les étiquettes (labels), le titre, la légende et les artistes (lignes, points, barres).

import matplotlib.pyplot as plt
import numpy as np

# Une figure contenant un seul Axes
fig, ax = plt.subplots(figsize=(8, 5))

print(type(fig))   # <class 'matplotlib.figure.Figure'>
print(type(ax))    # <class 'matplotlib.axes._axes.Axes'>

Interface pyplot vs interface orientée objet

Matplotlib propose deux styles d’écriture :

x = np.linspace(0, 2 * np.pi, 100)

# Style pyplot (à la MATLAB) : un état global implicite
plt.plot(x, np.sin(x))
plt.title("Sinus")
plt.xlabel("x")
plt.show()

# Style orienté objet : on manipule explicitement fig et ax
fig, ax = plt.subplots()
ax.plot(x, np.sin(x))
ax.set_title("Sinus")
ax.set_xlabel("x")
plt.show()

Recommandation : adoptez l’interface orientée objet. Le style pyplot est acceptable pour un tracé rapide en une ligne, mais dès qu’une figure contient plusieurs sous-graphiques ou qu’elle est construite dans une fonction, l’état global de pyplot devient source de bugs. L’interface orientée objet rend explicite quel Axes reçoit quelle commande, et c’est le style utilisé dans la documentation officielle moderne. Tous les exemples de ce guide l’utilisent.

Courbes avec plot

x = np.linspace(0, 10, 200)

fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(x, np.sin(x), label="sin(x)", color="tab:blue", linewidth=2)
ax.plot(x, np.cos(x), label="cos(x)", color="tab:orange",
        linestyle="--", linewidth=2)
ax.plot(x[::20], np.sin(x[::20]), "o", color="tab:blue",
        markersize=6, label="points mesurés")

ax.set_title("Fonctions trigonométriques")
ax.set_xlabel("x (radians)")
ax.set_ylabel("Amplitude")
ax.legend()
ax.grid(True, alpha=0.3)
plt.show()

Les styles de ligne courants : "-" (pleine), "--" (tirets), ":" (pointillés), "-." (mixte). Les marqueurs : "o" (rond), "s" (carré), "^" (triangle), "+", "x".

Nuages de points avec scatter

scatter permet de faire varier la taille et la couleur de chaque point, ce qui encode jusqu’à quatre variables sur un même graphique.

rng = np.random.default_rng(42)
x = rng.random(80)
y = 2 * x + rng.normal(0, 0.2, 80)
tailles = rng.integers(20, 200, 80)
couleurs = y - 2 * x                     # écart au modèle

fig, ax = plt.subplots(figsize=(8, 5))
nuage = ax.scatter(x, y, s=tailles, c=couleurs, cmap="viridis",
                   alpha=0.7, edgecolors="black", linewidths=0.5)

fig.colorbar(nuage, ax=ax, label="Résidu")
ax.set_title("Nuage de points avec taille et couleur variables")
ax.set_xlabel("x")
ax.set_ylabel("y")
plt.show()

Diagrammes en barres

langages = ["Python", "SQL", "JavaScript", "Rust"]
popularite = [48, 35, 30, 12]

fig, ax = plt.subplots(figsize=(8, 5))
barres = ax.bar(langages, popularite, color="tab:blue", edgecolor="black")

# Étiqueter chaque barre avec sa valeur
ax.bar_label(barres, fmt="%d %%")

ax.set_title("Popularité des langages (exemple)")
ax.set_ylabel("Part des répondants (%)")
ax.set_ylim(0, 55)
plt.show()

# Barres horizontales : plus lisibles quand les catégories ont des noms longs
fig, ax = plt.subplots(figsize=(8, 4))
ax.barh(langages, popularite, color="tab:green")
ax.set_xlabel("Part des répondants (%)")
plt.show()

Pour des barres groupées, décalez les positions avec un offset numérique :

positions = np.arange(len(langages))
largeur = 0.35
annee_1 = [45, 33, 32, 8]
annee_2 = [48, 35, 30, 12]

fig, ax = plt.subplots(figsize=(8, 5))
ax.bar(positions - largeur / 2, annee_1, largeur, label="2025")
ax.bar(positions + largeur / 2, annee_2, largeur, label="2026")
ax.set_xticks(positions)
ax.set_xticklabels(langages)
ax.legend()
plt.show()

Histogrammes

L’histogramme visualise la distribution d’une variable continue.

rng = np.random.default_rng(0)
donnees = rng.normal(loc=170, scale=8, size=1000)   # tailles simulées

fig, ax = plt.subplots(figsize=(8, 5))
valeurs, bords, patches = ax.hist(donnees, bins=30, color="tab:blue",
                                  edgecolor="white", alpha=0.85)

ax.axvline(donnees.mean(), color="red", linestyle="--",
           label=f"Moyenne = {donnees.mean():.1f} cm")
ax.set_title("Distribution des tailles")
ax.set_xlabel("Taille (cm)")
ax.set_ylabel("Effectif")
ax.legend()
plt.show()

# density=True normalise pour comparer à une densité de probabilité
# bins accepte un entier, une liste de bords, ou "auto"

Camemberts

À utiliser avec parcimonie (au-delà de 5 catégories, préférez des barres horizontales) :

parts = [45, 25, 20, 10]
etiquettes = ["Cloud", "Data", "Web", "Autres"]

fig, ax = plt.subplots(figsize=(6, 6))
ax.pie(parts, labels=etiquettes, autopct="%1.1f%%",
       startangle=90, explode=(0.05, 0, 0, 0),
       colors=["tab:blue", "tab:orange", "tab:green", "tab:gray"])
ax.set_title("Répartition du chiffre d'affaires")
plt.show()
# autopct affiche les pourcentages, explode détache la première part

Subplots et grilles de graphiques

plt.subplots(lignes, colonnes) crée une grille d’Axes en un appel.

x = np.linspace(0, 2 * np.pi, 100)

fig, axes = plt.subplots(2, 2, figsize=(10, 8))
# axes est un tableau NumPy 2D d'objets Axes

axes[0, 0].plot(x, np.sin(x))
axes[0, 0].set_title("sin(x)")

axes[0, 1].plot(x, np.cos(x), color="tab:orange")
axes[0, 1].set_title("cos(x)")

axes[1, 0].plot(x, np.sin(2 * x), color="tab:green")
axes[1, 0].set_title("sin(2x)")

axes[1, 1].plot(x, np.exp(-x) * np.sin(5 * x), color="tab:red")
axes[1, 1].set_title("Oscillation amortie")

fig.suptitle("Grille de quatre graphiques", fontsize=14)
fig.tight_layout()      # ajuste les espacements pour éviter les chevauchements
plt.show()

# Axes partagés : pratique pour comparer des séries
fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=(8, 6))

Pour des mises en page irrégulières (un graphique large en haut, deux petits en bas), explorez fig.add_gridspec ou plt.subplot_mosaic.

Personnalisation : titres, légendes, couleurs, styles

fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(x, np.sin(x), label="signal")

# Titres et étiquettes avec contrôle typographique
ax.set_title("Titre principal", fontsize=14, fontweight="bold")
ax.set_xlabel("Temps (s)", fontsize=11)
ax.set_ylabel("Amplitude (V)", fontsize=11)

# Légende : position et habillage
ax.legend(loc="upper right", frameon=True, shadow=False)

# Limites et graduations
ax.set_xlim(0, 2 * np.pi)
ax.set_xticks([0, np.pi, 2 * np.pi])
ax.set_xticklabels(["0", "π", "2π"])

# Grille discrète
ax.grid(True, linestyle=":", alpha=0.5)

# Supprimer les bordures superflues (style épuré)
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
plt.show()

Les feuilles de style permettent de changer l’apparence globale en une ligne :

print(plt.style.available[:5])
# ['Solarize_Light2', '_classic_test_patch', '_mpl-gallery', '_mpl-gallery-nogrid', 'bmh']

plt.style.use("seaborn-v0_8-whitegrid")   # style sobre adapté aux rapports

# Ou localement, sans modifier l'état global :
with plt.style.context("ggplot"):
    fig, ax = plt.subplots()
    ax.plot(x, np.sin(x))

Pour les couleurs, préférez la palette nommée tab: (tab:blue, tab:orange, …) : elle est conçue pour être distincte et lisible, y compris pour les daltoniens dans une large mesure.

Annotations

x = np.linspace(0, 10, 200)
y = np.exp(-x / 3) * np.sin(2 * x)

fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(x, y)

# Texte simple positionné en coordonnées des données
ax.text(6, 0.4, "Zone amortie", fontsize=11, color="gray")

# Annotation avec flèche vers un point précis
i_max = y.argmax()
ax.annotate(f"Maximum ({x[i_max]:.2f}, {y[i_max]:.2f})",
            xy=(x[i_max], y[i_max]),          # pointe de la flèche
            xytext=(3, 0.8),                  # position du texte
            arrowprops=dict(arrowstyle="->", color="black"))

# Lignes de repère
ax.axhline(0, color="black", linewidth=0.8)
ax.axvline(x[i_max], color="red", linestyle=":", alpha=0.6)
plt.show()

Échelles logarithmiques

Indispensables dès que les données couvrent plusieurs ordres de grandeur.

n = np.logspace(1, 6, 50)          # de 10 à 1 000 000
temps_lineaire = n * 1e-6
temps_quadratique = n ** 2 * 1e-9

fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(n, temps_lineaire, label="O(n)")
ax.plot(n, temps_quadratique, label="O(n²)")

ax.set_xscale("log")
ax.set_yscale("log")
ax.set_xlabel("Taille de l'entrée n")
ax.set_ylabel("Temps (s)")
ax.set_title("Complexités comparées (échelle log-log)")
ax.legend()
ax.grid(True, which="both", alpha=0.3)   # grille sur graduations majeures et mineures
plt.show()

# Raccourcis : ax.semilogy(...), ax.semilogx(...), ax.loglog(...)

Sauvegarde avec savefig

fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(x, np.sin(x))

# PNG haute résolution pour le web ou les slides
fig.savefig("graphique.png", dpi=200, bbox_inches="tight")

# SVG ou PDF : vectoriels, parfaits pour l'impression et les articles
fig.savefig("graphique.svg", bbox_inches="tight")
fig.savefig("graphique.pdf", bbox_inches="tight")

# Fond transparent pour intégration dans des slides
fig.savefig("graphique_transparent.png", dpi=200, transparent=True)

Deux paramètres à retenir : dpi contrôle la résolution des formats bitmap (150 à 300 pour un rendu net), et bbox_inches="tight" supprime les marges blanches excédentaires. Appelez savefig avant plt.show(), car show peut vider la figure dans certains environnements.

Intégration avec Pandas

Les DataFrames exposent une méthode .plot qui délègue à Matplotlib et renvoie un objet Axes, que vous pouvez ensuite personnaliser normalement.

import pandas as pd

df = pd.DataFrame({
    "mois": pd.date_range("2026-01-01", periods=6, freq="MS"),
    "ventes": [120, 135, 150, 145, 170, 190],
    "couts": [100, 110, 118, 120, 130, 140],
}).set_index("mois")

# Le DataFrame trace directement sur un Axes existant
fig, ax = plt.subplots(figsize=(8, 5))
df.plot(ax=ax, marker="o")

ax.set_title("Ventes et coûts mensuels")
ax.set_ylabel("k€")
ax.legend(["Ventes", "Coûts"])
plt.show()

# Autres raccourcis : df.plot.bar(), df.plot.hist(), df.plot.scatter(x=..., y=...)

Un mot sur Seaborn

Seaborn est une surcouche de Matplotlib orientée statistiques : elle produit en une ligne des graphiques qui demanderaient des dizaines de lignes de Matplotlib pur (boîtes à moustaches par catégorie, matrices de corrélation, régressions avec intervalle de confiance).

import seaborn as sns

tips = sns.load_dataset("tips")

fig, ax = plt.subplots(figsize=(8, 5))
sns.boxplot(data=tips, x="day", y="total_bill", hue="sex", ax=ax)
ax.set_title("Distribution des additions par jour")
plt.show()

Seaborn renvoyant des objets Matplotlib, tout ce que vous avez appris dans ce guide (Axes, titres, savefig) reste applicable. En pratique, beaucoup d’analystes utilisent Seaborn pour l’exploration rapide et Matplotlib pur pour les figures finales finement contrôlées.

Bonnes pratiques

  • Utilisez l’interface orientée objet (fig, ax = plt.subplots()) partout : elle est explicite, composable et évite les bugs d’état global.
  • Étiquetez tout : un graphique sans titre, sans unités sur les axes et sans légende est inutilisable en dehors de son contexte de création.
  • Appelez fig.tight_layout() (ou créez la figure avec layout="constrained") pour éviter les chevauchements de textes.
  • Choisissez le bon type de graphique : courbe pour une évolution, barres pour des catégories, histogramme pour une distribution, nuage de points pour une relation.
  • Exportez en vectoriel (SVG, PDF) pour l’impression et les documents, en PNG avec dpi>=150 pour le web.
  • Limitez la charge visuelle : supprimez les bordures inutiles, atténuez la grille avec alpha, réservez les couleurs vives à l’information importante.
  • Fixez la graine aléatoire dans les exemples et démonstrations pour obtenir des figures reproductibles.

Conclusion

Matplotlib repose sur un modèle simple, la Figure contenant des Axes, que l’interface orientée objet permet de manipuler avec précision. Avec les quelques types de graphiques présentés ici (courbes, nuages de points, barres, histogrammes), les subplots et les outils de personnalisation, vous couvrez la quasi-totalité des besoins de visualisation en analyse de données. L’intégration native avec Pandas fluidifie le passage des données au graphique, et Seaborn accélère l’exploration statistique. Pour approfondir, la galerie officielle de Matplotlib est une ressource précieuse : chaque figure y est accompagnée de son code source complet.

InSkillCoach

À propos de InSkillCoach

Expert en formation et technologies

Coach spécialisé dans les technologies avancées et l'IA, porté par GNeurone Inc.

Certifications:

  • AWS Certified Solutions Architect – Professional
  • Certifications Google Cloud
  • Microsoft Certified: DevOps Engineer Expert
  • Certified Kubernetes Administrator (CKA)
  • CompTIA Security+
615
251

Commentaires

Les commentaires sont alimentés par GitHub Discussions

Connectez-vous avec GitHub pour participer à la discussion

Lien copié !