Matplotlib : lire un comportement sur une courbe
Ce que ce chapitre apporte 6 points
- Comprendre qu'un tracé est une ligne brisée passant par un nombre fini de points calculés.
- Respecter la règle du graphique technique : titre, axes nommés, unités, grille.
- Distinguer par le style ce qui est mesuré de ce qui est calculé.
- Superposer des courbes, les légender, et séparer les unités incompatibles en sous-graphiques.
- Tracer des données lues dans un fichier, et enregistrer la figure pour un rapport.
- Montrer la répartition d'une série par un histogramme, une boîte à moustaches ou un violon, et choisir entre les trois.
En ingénierie, un résultat numérique isolé, « vitesse = 12,4 m/s », dit rarement ce qu'il faut savoir. Ce qui compte est l'évolution : le planeur descend-il de plus en plus vite, le moteur se stabilise-t-il, la température finit-elle par plafonner ?
C'est le rôle de Matplotlib, l'outil standard en Python pour transformer des listes de nombres en courbes lisibles. Ce chapitre vise moins la variété des commandes que la production de graphiques scientifiquement valides : ceux qui portent leurs unités, distinguent une mesure d'un modèle, et ne mentent pas par leur découpage.
Les figures s'affichent dans la page. NumPy, Matplotlib et SciPy sont installés dans l'éditeur du navigateur : l'image apparaît sous le code après exécution. Ces exemples fonctionnent à l'identique sur une machine.
Ce qu'un tracé est réellement
Un ordinateur ne sait pas dessiner une courbe. Il sait calculer la fonction en un nombre fini de points, puis relier ces points par des segments de droite. Ce que l'écran montre n'est donc jamais la courbe : c'est une ligne brisée qui lui ressemble plus ou moins.
C'est ce que fait np.linspace(debut, fin, n) : il fabrique les n abscisses où le calcul aura lieu. Le choix de n n'est pas un détail d'affichage, c'est le degré de fidélité du dessin.
| t | f |
|---|---|
| 0 | 0 |
| 0,63 | 0,5891 |
| 1,26 | 0,9521 |
| 1,89 | 0,9495 |
| 2,52 | 0,5823 |
| 3,15 | -0,0084 |
| 3,78 | -0,5959 |
| 4,41 | -0,9546 |
| 5,04 | -0,9468 |
| 5,67 | -0,5755 |
| 6,3 | 0,0168 |
| 6,93 | 0,6026 |
| 7,56 | 0,9571 |
| 8,19 | 0,9441 |
| 8,82 | 0,5686 |
| 9,45 | -0,0252 |
| 10,08 | -0,6093 |
| 10,71 | -0,9595 |
| 11,34 | -0,9413 |
| 11,97 | -0,5616 |
| 12,6 | 0,0336 |
écart maximal entre la ligne brisée et la courbe 0,4409
La règle pratique qui en découle : quand une courbe présente des angles inattendus, des sommets aplatis ou une allure trop anguleuse, la première chose à augmenter est le nombre de points, pas la taille de l'image.
Une sinusoïde tracée avec trop peu de points ressemble à quoi ?
Un premier tracé
Trois gestes suffisent : fabriquer les abscisses, calculer les ordonnées, tracer.
Les marqueurs o rendent visible ce que la section précédente décrivait : entre deux ronds, il n'y a aucun calcul, seulement un segment.
L'anatomie d'un graphique d'ingénieur
Le graphique ci-dessus est mathématiquement juste et techniquement inutilisable dans un rapport. Il est muet : rien ne dit si compte des secondes ou des kilomètres, ni si est une température ou une vitesse. Un nombre sans unité n'a aucune valeur physique.
Quatre éléments sont exigibles :
| Élément | Commande | Ce qu'il évite |
|---|---|---|
| Nom et unité de l'axe horizontal | plt.xlabel("Temps (s)") | une abscisse indéchiffrable |
| Nom et unité de l'axe vertical | plt.ylabel("Vitesse (m/s)") | une ordonnée indéchiffrable |
| Titre décrivant le phénomène | plt.title(...) | une figure qui dépend du texte autour |
| Grille | plt.grid(True) | un dessin dont on ne peut lire aucune valeur |
La grille mérite un mot : elle transforme une image en instrument de lecture. Sans elle, personne ne peut dire ce que vaut la vitesse à s, et la figure ne sert plus qu'à montrer une allure.
Modèle ou mesures : ligne ou points ?
Comparer une théorie à des relevés est l'usage le plus fréquent de Matplotlib en sciences. Deux natures de données se rencontrent alors, et le style les distingue :
- Des mesures : des valeurs isolées, entachées d'incertitude, connues seulement là où le capteur a relevé. Elles se tracent en marqueurs non reliés.
- Un modèle : une fonction définie partout. Il se trace en ligne continue.
Relier des points de mesure par des segments affirme quelque chose de faux : que le phénomène a suivi une droite entre deux relevés, alors que rien n'a été observé dans cet intervalle.
1.Un graphique d'ingénieur doit toujours porter quoi, sans exception ?
2.Mesures expérimentales et modèle théorique sur le même graphique : comment les distinguer ?
Dire l'incertitude : les barres d'erreur
Une mesure sans incertitude est une mesure incomplète. plt.errorbar ajoute à chaque point la barre qui représente sa dispersion, et la figure cesse de prétendre à une précision qu'elle n'a pas.
L'argument fmt='o' impose les marqueurs seuls, et capsize dessine les petits traits horizontaux au bout des barres. Un modèle qui traverse toutes les barres est compatible avec l'expérience ; un modèle qui passe systématiquement au-dessus ne l'est pas, et aucun coefficient de corrélation ne le dira aussi clairement.
Comparer plusieurs courbes
Tant que plt.show() n'est pas appelé, Matplotlib dessine sur la même figure. Plusieurs plt.plot s'y empilent donc, et c'est le label de chacun que plt.legend() va chercher.
L'appel à plt.axis('equal') n'est pas cosmétique. Une trajectoire dessinée avec des échelles différentes en et en donne une impression d'angle fausse, et c'est sur cette impression que le lecteur se fera un avis.
Dans un script lancé sur une machine, plt.show() placé avant plt.plot() produit quoi ?
show() ne vide rienplt.show() n'y interrompt donc rien et ne remet pas la figure à zéro : un tracé placé après lui s'ajoute à la même image, au lieu de se perdre.Garder malgré tout l'ordre habituel,
show() en dernier : c'est celui qui reste juste partout, et le code d'un chapitre doit pouvoir être recopié dans un fichier sans se comporter autrement.
Plusieurs tracés côte à côte
Des mètres et des mètres par seconde ne partagent pas un axe vertical : superposées, la grandeur aux petites valeurs devient une ligne plate. plt.subplots découpe alors la feuille en zones distinctes.
La syntaxe change : le travail ne se fait plus sur plt mais sur chaque zone, appelée un axe, et les commandes prennent le préfixe set_ (plt.title devient ax.set_title).
À quoi servent les sous-graphiques ?
Quand les valeurs s'étalent sur plusieurs décades
Une grandeur qui passe de 0,001 à 10 000 est illisible en échelle linéaire : tout ce qui est petit s'écrase sur l'axe. L'échelle logarithmique corrige cela, et transforme au passage toute loi de puissance en droite, dont la pente donne l'exposant.
which="both" affiche aussi la grille intermédiaire, celle des 2, 3, 5 entre deux puissances de dix, sans laquelle une lecture précise redevient impossible.
Tracer ce qui vient d'un fichier
Les données réelles ne sont pas fabriquées par linspace : elles arrivent dans un fichier. Le chapitre sur les fichiers donne la lecture, et il ne reste qu'à en faire deux listes.
Le style 'o-' se justifie ici, alors qu'il était déconseillé plus haut : les relevés sont assez rapprochés et assez peu bruités pour que le trait aide à suivre la chronologie sans rien affirmer de faux entre deux points.
Annoter ce qui compte
Une figure de rapport doit désigner ce qu'elle démontre. Trois commandes y suffisent :
xy est le point désigné, xytext l'endroit où se pose le texte. Une annotation bien placée remplace souvent un paragraphe de commentaire.
Enregistrer la figure
Une capture d'écran d'un graphique est floue à l'impression. plt.savefig produit un fichier propre, et doit être appelé avant plt.show() : sur une machine, la fenêtre refermée emporte la figure, et le fichier écrit après coup serait vide.
plt.savefig("reponse_moteur.png", dpi=200, bbox_inches="tight")
plt.show()
| Argument | Rôle |
|---|---|
dpi=200 | résolution suffisante pour une impression A4 |
bbox_inches="tight" | rogne les marges blanches qui déséquilibrent la mise en page |
extension .pdf | format vectoriel, net à n'importe quel agrandissement |
Montrer une distribution
Jusqu'ici, chaque point de chaque figure était une mesure à un instant, et la question portait sur l'évolution. Il arrive que la question soit autre : comment se répartissent trois cents temps de réponse, trois cents temps de tour, trois cents relevés d'un capteur ? L'ordre des mesures n'a plus d'importance, seule compte la façon dont elles s'étalent.
Trois figures y répondent, et elles ne disent pas la même chose. Le chapitre de statistiques explique comment les lire ; celui-ci montre comment les tracer, sur deux services web mesurés sur trois cents requêtes chacun. Le premier interroge sa base à chaque fois, le second sert la moitié de ses réponses depuis un cache.
Les deux boîtes sont presque superposables : moins d'une milliseconde d'écart sur chaque quartile, ce que les nombres imprimés sous la figure confirment. Les deux violons, eux, n'ont rien de commun : une bosse d'un côté, deux de l'autre, avec un creux autour de 40 ms là où tombe justement la médiane. Les histogrammes disent la même chose que les violons, mais superposés ils se lisent mal, et au-delà de deux séries ils deviennent illisibles. C'est la raison d'être du violon : la forme de chaque série, côte à côte, sur un axe commun.
| Appel | Ce qu'il trace | Réglage qui compte |
|---|---|---|
plt.hist(x, bins=...) | une série, comptée classe par classe | bins : le nombre ou les bornes des classes |
plt.boxplot([x, y]) | une boîte par série | whis=1.5, la longueur des moustaches en écarts interquartiles |
plt.violinplot([x, y]) | un violon par série | bw_method, la largeur des noyaux ; showmedians=True |
plt.boxplot calcule ses quartiles comme np.percentile, en interpolant entre deux rangs, et non par la règle des deux moitiés qu'applique le cours de statistiques. Sur trois cents valeurs, la différence ne se voit pas. Sur les douze relevés du chapitre de statistiques, elle donne 17,25 au lieu de 16,5 pour Q₁ : une boîte tracée par matplotlib et une boîte calculée à la main ne coïncident donc pas toujours, et aucune des deux n'est fausse.
bw_method=0.1 dans l'appel à violinplot : le violon du service sans cache se hérisse de petites bosses qui ne sont que du bruit. Essayer ensuite bw_method=1 : les deux bosses du service avec cache se fondent en une seule, et le violon ne montre plus rien de plus que la boîte. La forme d'un violon dépend de ce réglage, et le laisser par défaut est un choix, pas une neutralité.
Deux détails pour qui compare des figures produites par des outils différents. violinplot arrête chaque violon à la plus petite et à la plus grande valeur observées ; la bibliothèque seaborn, courante sur une machine mais absente de l'éditeur du navigateur, prolonge au contraire la courbe au-delà, jusqu'à produire des durées négatives. Et violinplot ne trace pas les quartiles par défaut : quantiles=[[0.25, 0.75]] * 2 les ajoute, une liste par série.
Deux séries donnent deux boîtes à moustaches presque identiques. Que montre en plus un violon ?
Trois façons de mentir sans le vouloir
| Piège | Effet | Correction |
|---|---|---|
| Axe vertical ne partant pas de zéro | une variation de 2 % paraît spectaculaire | plt.ylim(0, ...), ou le signaler dans le titre |
| Trop peu de points calculés | sommets rabotés, allure fausse | augmenter le troisième argument de linspace |
| Courbes distinguées par la seule couleur | indiscernables en noir et blanc et pour un daltonien | varier aussi linestyle et marker |
Le premier piège est le plus répandu, et le seul qui soit parfois légitime : zoomer sur une plage étroite est utile quand la variation est le sujet. Ce qui ne l'est pas, c'est de laisser croire à un effondrement là où il y a une fluctuation de quelques pour cent.
Mettre en pratique
Exercice : la décharge du condensateur. La tension aux bornes d'un condensateur qui se décharge suit . Avec V et s, tracer la courbe sur une seconde, marquer la constante de temps, et habiller la figure aux normes.
Afficher la solution
Trois choix méritent d'être remarqués : les 300 points, sans lesquels la chute initiale serait tronquée ; le ylim(0, 5.5), qui ancre l'axe à zéro et rend l'amplitude honnête ; et le savefig placé avant show, sans quoi le fichier enregistré serait vide.
Pour aller plus loin : superposer la décharge pour trois valeurs de (0,1, 0,2 et 0,5 s) et vérifier sur la figure que la tension restante à est la même dans les trois cas.
Chapitre révisé en octobre 2026 · Une erreur dans ce chapitre ?
Dans la bibliothèque d'exercices
Calculer une série, la tracer, et lire sur la courbe ce qu'une colonne de nombres cache.
- Tracer un refroidissement3 · Confirmé
- Assez de points pour ne pas mentir2 · Fonctions
- Les bornes d'une barre d'erreur3 · Confirmé
- Ramener des séries à la même échelle3 · Confirmé
- Séparer les temps et les valeurs3 · Confirmé