Heatmap Seaborn : matrice de corrélation, FacetGrid & thèmes
Voyez d’un coup d’œil comment vos colonnes se corrèlent, décomposez une comparaison en petits multiples, et contrôlez tout le système visuel — colormap, facettes et thème.
Construisez une heatmap de corrélation en seaborn à partir de df.corr avec des annotations, une colormap divergente centrée sur zéro et un triangle supérieur masqué ; opposez-la à une heatmap séquentielle ; puis créez des facettes avec FacetGrid, col_wrap et des axes partagés, et contrôlez tout le rendu avec set_theme et les familles de palettes.
Date de publication
17 juillet 2026
Modifié
18 juillet 2026
AstucePoints clés
Une heatmap de corrélation, c’est un seul appel une fois la matrice obtenue.df.corr(numeric_only=True) puis sns.heatmap(corr, annot=True, fmt=".2f") transforme chaque paire numérique en une grille colorée et étiquetée — la lecture la plus rapide de la façon dont vos colonnes évoluent ensemble.
Une heatmap de corrélation exige une colormap divergente centrée sur 0. Les corrélations vont de −1 à +1 avec un zéro qui a du sens, alors passez cmap="vlag", vmin=-1, vmax=1, center=0 — une carte séquentielle masque le signe, faisant passer une forte corrélation négative pour une simple valeur « faible ».
Masquez le triangle supérieur pour une figure épurée. Une matrice de corrélation est symétrique ; mask=np.triu(...) supprime le miroir redondant (et la diagonale triviale à 1.00) pour que le lecteur voie chaque paire une seule fois.
Séquentielle ou divergente : c’est là toute la décision de colormap. Des magnitudes toutes positives (effectifs, moyennes) → séquentielle ("mako", viridis) ; des valeurs signées autour d’un zéro qui a du sens (corrélations, différences) → divergente ("vlag") ; des catégories sans ordre → qualitative.
FacetGrid, c’est le facettage que vous construisez à la main.FacetGrid(df, col=, row=, hue=).map_dataframe(sns.scatterplot, ...) donne des petits multiples avec col_wrap= et des axes partagés ou indépendants (sharey=) ; les fonctions de niveau figure relplot/displot/catplot sont le raccourci en une ligne.
set_theme(style=, context=, palette=) contrôle tout le rendu. Réglez le style (whitegrid/darkgrid/ticks), l’échelle (notebook/talk) et la palette par défaut une seule fois — chaque figure en hérite.
Introduction
Vous avez la table des manchots et ses colonnes numériques sous les yeux, et deux questions qu’un analyste se pose après les premiers graphiques : comment toutes ces mesures évoluent-elles ensemble, et puis-je décomposer la comparaison en petits multiples que je peux parcourir côte à côte ? La première est l’affaire d’une heatmap — toute une matrice de corrélation lue comme de la couleur. La seconde, c’est le facettage — l’idée des petits multiples que distributions & relations et graphiques catégoriels ont effleurée avec relplot et catplot, poussée plus loin ici jusqu’à la grille que vous pilotez vous-même.
Le plan suit un seul workflow. Nous construisons une heatmap de corrélation des quatre mesures — annotée, sur la bonne colormap, avec la moitié redondante masquée — puis nous l’opposons à une heatmap séquentielle où la couleur signifie tout autre chose. De là, nous créons des facettes : un FacetGrid que nous assemblons à la main, puis le raccourci de niveau figure, puis le choix de partage des axes qui décide si une comparaison à facettes est honnête. Nous terminons sur le panneau de contrôle — set_theme et les familles de palettes — qui régit chaque figure de cette série.
Cela s’appuie sur les trois leçons qui précèdent. La distinction niveau axes ou niveau figure de la leçon 2 tient toujours — heatmap est de niveau axes (il prend votre ax=), tandis que FacetGrid, relplot et catplot sont de niveau figure (ils construisent leur propre figure pour accueillir les panneaux). Et le style maison est le même : sns.set_theme() plus la palette d’espèces échantillonnée sur viridis, fixée par espèce, de sorte qu’une espèce garde sa couleur ici aussi.
Les données sont le même CSV de manchots livré à côté de cette leçon, lu avec pd.read_csv — aucun seaborn.load_dataset n’accède au réseau. Chaque figure a été produite par le code montré, et les blocs s’enchaînent dans l’ordre. Pour expérimenter, modifiez la cellule Essayez en direct à la fin et appuyez sur Run ; elle s’exécute dans votre navigateur via Pyodide.
Mise en place — le même style maison
Aucun nouveau style à apprendre : c’est la mise en place de la leçon 2 à l’identique — set_theme() pour le rendu, l’azur #3a86d4 pour une série unique, et la palette d’espèces échantillonnée sur viridis fixée en dict pour qu’Adelie soit le même violet ici que partout ailleurs. Exécutez-la une fois ; chaque figure ci-dessous en hérite.
import matplotlib.pyplot as pltimport numpy as npimport pandas as pdimport seaborn as sns# House style — one call, applied to every figure that follows (same as lessons 1–3)sns.set_theme( style="whitegrid", context="notebook", rc={"figure.figsize": (7, 4.5),"figure.dpi": 110,"axes.spines.top": False,"axes.spines.right": False,"grid.color": "#e6e6e6","grid.linewidth": 0.8,"axes.titlesize": 13,"axes.titleweight": "bold","legend.frameon": False, },)AZURE ="#3a86d4"# brand colour for a single seriespenguins = pd.read_csv("penguins.csv")# The SAME three species colours as lessons 1–3, pinned so a species keeps its colourSPECIES = ["Adelie", "Chinstrap", "Gentoo"]PALETTE =dict(zip(SPECIES, plt.get_cmap("viridis")(np.linspace(0.1, 0.85, 3))))MEASURES = ["bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g"]print(penguins.shape, "rows x cols")
(344, 7) rows x cols
Une remarque avant la première heatmap. Les heatmaps et les corrélations sont déterministes — les mêmes données donnent la même matrice à chaque fois — donc contrairement au jitter et au bootstrap de la leçon 3, rien sur cette page n’a besoin d’une graine aléatoire avant la section sur les palettes, tout à la fin.
La heatmap de corrélation
La question est comment les quatre mesures évoluent-elles ensemble ? — et le premier pas honnête, c’est toute la matrice de corrélation, pas une paire triée sur le volet. df.corr(numeric_only=True) la calcule ; sns.heatmap la restitue en couleur.
import matplotlib.pyplot as pltimport seaborn as snscorr = penguins[MEASURES].corr() # a 4x4 matrix of Pearson correlationsfig, ax = plt.subplots(figsize=(6.5, 5.2))sns.heatmap( corr, annot=True, fmt=".2f", # print each correlation in its cell cmap="vlag", vmin=-1, vmax=1, center=0, # DIVERGING, pinned so white sits exactly at 0 square=True, linewidths=0.5, linecolor="white", cbar_kws={"label": "Pearson r", "shrink": 0.8}, ax=ax,)ax.set_title("How the penguin measurements correlate")fig.tight_layout()plt.show()
Figure 1
Lisez-la d’abord par la couleur, ensuite par le chiffre. Le rouge le plus intense hors diagonale, c’est longueur de la nageoire × masse corporelle à 0.87 — les gros manchots ont de grandes nageoires, la relation la plus forte du tableau et celle que la leçon 2 avait tracée en nuage de points. La longueur du bec est modérément positive avec la longueur de la nageoire (0.66) comme avec la masse corporelle (0.60). Et la profondeur du bec fait bande à part : elle est négative face aux trois autres mesures — légèrement face à la longueur du bec (−0.24), plus fortement face à la longueur de la nageoire (−0.58) et à la masse corporelle (−0.47). Ce signe négatif est un piège qu’il faut connaître : agrégé toutes espèces confondues, un bec plus profond va de pair avec un manchot plus petit, mais au sein de chaque espèce, becs et corps grandissent ensemble — le renversement du paradoxe de Simpson que la leçon 1 a rencontré sur ces mêmes colonnes. Une heatmap vous montre où regarder ; elle ne résout pas à elle seule un facteur de confusion.
Trois arguments font de ceci une figure plutôt qu’un déversement de chiffres. annot=True inscrit le nombre dans chaque cellule et fmt=".2f" l’arrondit à deux décimales (sans fmt, vous obtenez le format long par défaut de seaborn). square=True garde les cellules carrées, et linewidths avec un linecolor blanc trace une fine gouttière pour que la grille se lise nettement. Le choix de la colormap est celui qui compte le plus — le paragraphe suivant lui est entièrement consacré.
Pourquoi une colormap divergente, centrée sur zéro
Une corrélation va de −1 à +1 avec un zéro qui a du sens — zéro signifie aucune relation linéaire, et le signe vous donne la direction. C’est exactement la forme pour laquelle une colormap divergente est faite : une teinte pour le négatif, une autre pour le positif, et une couleur neutre au centre. cmap="vlag" donne un dégradé du bleu au rouge en passant par un blanc cassé, si bien que vous lisez le signe à la teinte et la force au degré de saturation de la cellule.
Les trois arguments qui l’accompagnent verrouillent cette lecture. center=0 force la couleur neutre à tomber exactement sur zéro ; vmin=-1 et vmax=1 fixent l’échelle à toute la plage des corrélations, de sorte que la carte soit symétrique — un +0.5 et un −0.5 ressortent tout aussi saturés, seulement de teintes différentes. Omettez-les et seaborn met à l’échelle automatiquement sur les min et max propres aux données, ce qui éloigne le blanc du zéro et fait paraître extrême une corrélation modérée.
Optez pour une carte séquentielle ici — viridis, disons — et vous casseriez la figure en silence : un dégradé séquentiel va du sombre au clair dans une seule direction, il associe donc −0.58 et +0.60 à deux couleurs différentes mais monotones, et les fortes relations négatives de la profondeur du bec se liraient comme de simples valeurs « faibles » plutôt que « fortes, et pointant dans l’autre sens ». Pour une heatmap de corrélation, divergente-et-centrée est le choix honnête par défaut — et c’est l’unique exception délibérée à la règle de marque azur/viridis de cette série, faite parce que les données ont un signe que la palette doit respecter.
Masquer la moitié redondante
Une matrice de corrélation est symétrique — la cellule nageoire × masse est identique à masse × nageoire — et sa diagonale vaut 1.00 partout, par définition. La moitié de la grille est de la répétition. Le geste qui épure la figure, c’est de masquer le triangle supérieur pour que chaque paire n’apparaisse qu’une fois.
import matplotlib.pyplot as pltimport numpy as npimport seaborn as snscorr = penguins[MEASURES].corr()# True on and above the diagonal -> those cells are hiddenmask = np.triu(np.ones_like(corr, dtype=bool))nice = ["Bill length", "Bill depth", "Flipper length", "Body mass"]fig, ax = plt.subplots(figsize=(6.5, 5.2))sns.heatmap( corr, mask=mask, annot=True, fmt=".2f", cmap="vlag", vmin=-1, vmax=1, center=0, square=True, linewidths=0.5, linecolor="white", xticklabels=nice, yticklabels=nice, cbar_kws={"label": "Pearson r", "shrink": 0.8}, ax=ax,)ax.set_title("Penguin measurement correlations")fig.tight_layout()plt.show()
Figure 2
Les mêmes chiffres, moitié moins d’encre. np.triu construit un tableau booléen qui vaut True sur la diagonale et au-dessus ; le passer en mask= indique à heatmap de laisser ces cellules vides, de sorte que seul le triangle inférieur — chaque paire exactement une fois — est dessiné. (Utilisez plutôt np.triu(..., k=1) si vous voulez conserver la diagonale à 1.00 ; ici, nous la supprimons, puisque la corrélation d’une variable avec elle-même n’apporte aucune information.) Les étiquettes réécrites sont la dernière touche : seaborn étiquette les axes avec les noms bruts des colonnes, donc les renommer en "Bill length", "Body mass" et ainsi de suite fait toute la différence entre un brouillon et une figure que vous publieriez. Cette heatmap masquée, annotée et divergente est celle à sortir chaque fois que la question est comment tout se corrèle-t-il ?
Une heatmap séquentielle : quand la couleur signifie « plus »
Toutes les heatmaps ne sont pas des matrices de corrélation, et toutes ne réclament pas une carte divergente. Construisez une grille de magnitudes toutes positives — des effectifs, ou une moyenne par groupe — et la bonne colormap est séquentielle : plus foncé signifie plus, sans centre particulier. Voici la masse corporelle moyenne pour chaque cellule espèce × sexe, directement issue de pivot_table.
import matplotlib.pyplot as pltimport seaborn as sns# mean body mass for each species x sex combinationmass = penguins.pivot_table( values="body_mass_g", index="species", columns="sex", aggfunc="mean",).reindex(SPECIES) # pin the row orderfig, ax = plt.subplots(figsize=(5.6, 4.2))sns.heatmap( mass, annot=True, fmt=".0f", # whole grams cmap="mako_r", # SEQUENTIAL — perceptually uniform, colourblind-safe (darker = heavier) linewidths=0.5, linecolor="white", cbar_kws={"label": "Mean body mass (g)", "shrink": 0.8}, ax=ax,)ax.set_xlabel("Sex")ax.set_ylabel("Species")ax.set_title("Mean body mass by species and sex")fig.tight_layout()plt.show()
Figure 3
Le dégradé se lit d’emblée : la cellule Gentoo-mâle est la plus foncée à 5485 g, la cellule Adelie-femelle la plus claire à 3369 g, et au sein de chaque espèce la cellule mâle est plus foncée que la femelle — les mâles sont plus lourds, dans les trois espèces, le même constat que le graphique de points de la leçon 3 traçait en deux lignes montantes. Une carte séquentielle convient ici parce que ces nombres n’ont aucun zéro qui ait du sens de part et d’autre duquel se placer — 3369 g n’est le « négatif » de rien, c’est simplement moins que 5485 g — donc un dégradé à sens unique est exactement la lecture voulue. "mako_r" est l’une des cartes séquentielles perceptuellement uniformes propres à seaborn — "mako" tout court va du clair au foncé, et le suffixe _r inverse n’importe quelle colormap, de sorte qu’ici la cellule la plus foncée est la plus lourde (viridis, "rocket", "crest" sont d’autres options séquentielles) ; toutes sont adaptées au daltonisme et conformes à la marque.
Voilà toute la décision de colormap en deux figures. Des valeurs signées autour d’un vrai zéro — corrélations, différences, anomalies — appellent une carte divergente centrée sur 0. Des magnitudes ordonnées — effectifs, moyennes, intensités — appellent une carte séquentielle. Accordez la palette à la forme des données et la couleur fait la lecture à votre place ; désaccordez-la et la couleur induit en erreur, en silence.
Note
Attention aux unités. Cette matrice fonctionne avec une carte séquentielle parce que les cellules partagent une seule unité (les grammes). Une pivot_table mêlant des colonnes d’unités différentes — des millimètres de bec à côté de grammes de masse — serait dominée par les grands nombres, et aucune échelle de couleur unique ne pourrait toutes les lire ; standardisez d’abord chaque colonne (un score z) si vous devez mettre des unités mixtes dans une même heatmap.
Le facettage, plus en profondeur : FacetGrid
Le facettage dessine le même graphique une fois par sous-ensemble — des petits multiples — pour comparer les groupes panneau par panneau au lieu de se battre sur un seul axe surchargé. Les leçons 2 et 4 y arrivaient via relplot et catplot ; sous les deux se trouve FacetGrid, l’objet que vous pouvez piloter à la main quand vous voulez un graphique que les fonctions de niveau figure n’enveloppent pas.
Le motif tient en deux étapes : construire la grille (quelles colonnes sont associées aux lignes, aux colonnes et à la couleur), puis appliquer avec .map une fonction de tracé à chaque panneau.
import seaborn as snsg = sns.FacetGrid( penguins, col="island", col_order=["Biscoe", "Dream", "Torgersen"], col_wrap=2, # 3 panels -> 2 columns, wraps to a 2nd row hue="species", hue_order=SPECIES, palette=PALETTE, height=3.1, aspect=1.1,)g.map_dataframe(sns.scatterplot, x="flipper_length_mm", y="body_mass_g", s=35, alpha=0.8)g.add_legend(title="Species")g.set_axis_labels("Flipper length (mm)", "Body mass (g)")g.set_titles("{col_name}")g.figure.suptitle("Mass vs. flipper length, by island", y=1.02, fontweight="bold")plt.show()
Figure 4
Créer des facettes par île étale la structure un panneau à la fois, et cela révèle le même facteur de confusion que la leçon 2 avait débusqué : les espèces ne sont pas réparties entre les îles. Les Gentoo ne vivent que sur Biscoe, les Chinstrap seulement sur Dream, et seuls les Adelie se retrouvent sur les trois — donc tout « effet d’île » sur la masse corporelle est en réalité l’espèce qui y vit.
Quatre habitudes font marcher FacetGrid. col=/row= choisissent la variable qui se découpe en panneaux — passez les deux pour une grille complète. col_wrap= est celle utilisée ici : avec une seule variable de facettage, elle enroule les panneaux en lignes de la largeur que vous donnez (trois îles s’enroulent à deux par ligne en un 2×2 avec un emplacement vide) — vous ne pouvez pas combiner col_wrap avec row. .map_dataframe(func, ...) appelle func sur la tranche de données de chaque panneau avec les noms de colonnes en arguments nommés (l’ancien .map(func, "col1", "col2") les passe par position) ; hue= se définit sur la grille, pas dans l’appel à map. Et parce qu’un FacetGrid est une grille, pas un Axes, vous l’étiquetez avec g.set_axis_labels, g.set_titles et g.add_legend, et vous descendez jusqu’à matplotlib via g.figure — la même API de grille que toute fonction de niveau figure.
relplot / displot / catplot : le raccourci en une ligne
Vous avez rarement besoin de construire la grille à la main. Les fonctions de niveau figure sont un FacetGrid avec une fonction de tracé pré-câblée — relplot applique scatterplot/lineplot, displot applique les tracés de distribution, catplot applique les tracés catégoriels — de sorte que la construction en deux étapes se réduit à un seul appel avec col= et row=.
import seaborn as snsg = sns.relplot( data=penguins.dropna(subset=["sex"]), x="flipper_length_mm", y="body_mass_g", col="island", col_order=["Biscoe", "Dream", "Torgersen"], row="sex", row_order=["Female", "Male"], hue="species", hue_order=SPECIES, palette=PALETTE, kind="scatter", height=2.6, aspect=1.15, s=32, alpha=0.8,)g.set_axis_labels("Flipper length (mm)", "Body mass (g)")g.set_titles("{row_name} · {col_name}")g.legend.set_title("Species")g.figure.suptitle("Mass vs. flipper length, by island and sex", y=1.02, fontweight="bold")plt.show()
Figure 5
Un seul appel, une grille 2×3 d’île contre sexe. row= et col= croisent deux variables de facettage d’un coup, et la ligne des mâles posée un peu au-dessus de celle des femelles, c’est encore la différence de masse, désormais séparée de la structure des îles. Utilisez le raccourci de niveau figure chaque fois que le graphique est l’un des types enveloppés ; ne descendez à un FacetGrid bâti à la main que lorsque vous avez besoin d’une fonction de tracé qu’ils n’enveloppent pas, ou d’un contrôle par panneau qu’ils n’exposent pas.
Axes partagés ou indépendants
Chaque panneau ci-dessus partageait une échelle x et une échelle y — c’est le comportement par défaut, et c’est ce qui rend les panneaux comparables : un point au même endroit signifie la même chose partout. Désactivez le partage et chaque panneau se remet à l’échelle de ses propres données, ce qui est parfois ce que vous voulez et souvent un piège.
import seaborn as snsg = sns.displot( penguins, x="body_mass_g", col="species", col_order=SPECIES, hue="species", hue_order=SPECIES, palette=PALETTE, legend=False, kind="hist", bins=15, height=3, aspect=0.9, edgecolor="white", facet_kws={"sharey": False}, # each panel rescales its OWN y-axis)g.set_axis_labels("Body mass (g)", "Count")g.set_titles("{col_name}")g.figure.suptitle("Independent y-axes hide the sample-size difference", y=1.03, fontweight="bold")plt.show()
Figure 6
C’est le piège, à dessein. Avec sharey=False, chaque panneau étire sa barre la plus haute jusqu’en haut, si bien que le panneau Chinstrap — seulement 68 oiseaux — paraît exactement aussi haut que le panneau Adelie qui en compte 151. Un lecteur qui parcourt les panneaux du regard croirait que les trois échantillons ont la même taille. Ce n’est pas le cas, et le sharey=Truepar défaut l’aurait montré : sur un axe d’effectifs partagé, le panneau Chinstrap est nettement plus court. Gardez les axes partagés quand vous comparez des groupes sur la même mesure — c’est ce qui fait d’une facette une comparaison juste. Ne désactivez le partage que lorsque les panneaux vivent réellement sur des échelles différentes (des variables différentes par ligne, disons), et quand vous le faites, dites-le, car le lecteur ne peut pas le voir. sharex=/sharey= sont des arguments de FacetGrid ; sur les fonctions de niveau figure, vous les passez via facet_kws={"sharey": False}, comme ci-dessus.
Thèmes et palettes : le panneau de contrôle
Tout sur cette page a hérité de son rendu de l’unique appel à set_theme() en tête. Cet appel a trois leviers qui valent la peine d’être connus, parce qu’ils changent toutes les figures d’un coup.
style= définit l’arrière-plan et la grille. sns.set_theme(style="darkgrid") donne le panneau gris emblématique de seaborn ; "whitegrid" (le nôtre) un panneau blanc avec une grille légère ; "white" et "ticks" suppriment complètement la grille, "ticks" ajoutant des graduations d’axe — le choix le plus épuré pour un nuage de points ou une figure de publication où une grille n’est qu’encombrement.
import matplotlib.pyplot as pltimport seaborn as snsstyles = ["whitegrid", "darkgrid", "white", "ticks"]fig = plt.figure(figsize=(8, 6))for i, style inenumerate(styles):with sns.axes_style(style): # apply the style only to this panel ax = fig.add_subplot(2, 2, i +1) sns.scatterplot(data=penguins, x="flipper_length_mm", y="body_mass_g", hue="species", hue_order=SPECIES, palette=PALETTE, s=22, alpha=0.8, legend=False, ax=ax) ax.set_title(f'style="{style}"') ax.set_xlabel("Flipper length (mm)") ax.set_ylabel("Body mass (g)")fig.suptitle("The same scatter under four seaborn styles", y=1.01, fontweight="bold")fig.tight_layout()plt.show()sns.set_theme(style="whitegrid", context="notebook") # restore the house style
Figure 7
Les données sont identiques dans les quatre panneaux ; seul le cadre change. sns.axes_style(style) est la forme gestionnaire de contexte — elle applique un style aux seuls panneaux créés dans son bloc with, et c’est ainsi que quatre styles partagent une même figure sans déborder l’un sur l’autre. (Son cousin sns.plotting_context("talk") fait de même pour l’échelle.) context= est le deuxième levier : il met à l’échelle les polices, les épaisseurs de trait et les marqueurs selon le support — "notebook" (le nôtre) pour un rapport, "talk" et "poster" progressivement plus grands pour les diapositives et les tirages, "paper" plus petit pour une figure dense. Réglez-le une fois et toutes les étiquettes se redimensionnent ensemble.
palette= est le troisième, et en choisir une revient en fait à choisir une famille à accorder à vos données — le même signal que la décision de colormap plus haut :
import matplotlib.pyplot as pltimport numpy as npimport seaborn as snsfamilies = {"Qualitative — distinct categories\n(viridis, 3 species)": [PALETTE[s] for s in SPECIES],"Sequential — ordered magnitude\n(mako)": sns.color_palette("mako", 8),"Diverging — signed, centred\n(vlag)": sns.color_palette("vlag", 9),"Sequential — custom ramp\n(cubehelix)": sns.cubehelix_palette(8),}fig, axes = plt.subplots(len(families), 1, figsize=(7.5, 4))for ax, (name, colours) inzip(axes, families.items()): n =len(colours) ax.imshow(np.arange(n).reshape(1, n), cmap=plt.matplotlib.colors.ListedColormap(colours), aspect="auto") ax.set_yticks([]); ax.set_xticks([]) ax.set_ylabel(name, rotation=0, ha="right", va="center", fontsize=9)fig.suptitle("Three palette families — match the family to the data", y=1.02, fontweight="bold")fig.tight_layout()plt.show()
Figure 8
Les trois familles répondent à trois formes de données différentes. Une palette qualitative donne des teintes maximalement distinctes et sans ordre pour des catégories sans ordre — nos trois espèces ; les "deep", "colorblind" de seaborn ou un échantillon de viridis conviennent tous, et fixer l’association en dict (comme nous le faisons pour les espèces) est ce qui maintient une catégorie sur sa couleur d’une figure à l’autre. Une palette séquentielle — "mako", viridis, "rocket" — progresse dans une direction pour une magnitude ordonnée ; color_palette("mako", 8) en échantillonne huit paliers, et light_palette("#3a86d4", 8) ou cubehelix_palette(8) construisent un dégradé personnalisé à partir d’une seule teinte (les deux sont déterministes, ils n’ont donc besoin d’aucune graine). Une palette divergente — "vlag", "coolwarm", diverging_palette(...) — a deux teintes autour d’un centre neutre, pour des données signées. Choisissez la famille d’après les données, et sns.set_theme(palette=...) ou un palette= par graphique l’applique partout.
Quand un graphique réclame un rendu que matplotlib expose mais pas seaborn, descendez jusqu’aux rcParams — sns.set_theme(rc={"axes.grid.axis": "y", "font.family": "serif"}) superpose n’importe quel réglage matplotlib au style seaborn, exactement comme la leçon 1 réglait les rcParams directement. Le thème de seaborn est une mise à jour des rcParams avec de meilleurs défauts ; vous ne quittez jamais matplotlib.
Quelle colormap pour quelle question ?
Une heatmap n’est honnête que dans la mesure de sa colormap. Choisissez la famille d’après la forme des valeurs, pas par habitude :
Vos valeurs
Famille
Un bon choix par défaut
Exemple ici
Signées, avec un zéro qui a du sens (corrélations, différences, anomalies)
Divergente, center=0
"vlag", "coolwarm"
la heatmap de corrélation
Magnitudes toutes positives, ordonnées du bas vers le haut (effectifs, moyennes, intensités)
Séquentielle
"mako", viridis, "rocket"
la masse corporelle moyenne par groupe
Catégories sans ordre (espèce, île, traitement)
Qualitative
un échantillon de viridis, "colorblind"
les couleurs des espèces
Un dégradé bâti à partir d’une seule teinte de marque
Séquentielle (personnalisée)
light_palette("#3a86d4"), cubehelix
une heatmap monochrome
Dans le doute, demandez-vous : zéro signifie-t-il quelque chose de particulier ? Si oui, divergente et centrée. Les nombres ne font-ils que monter ? Séquentielle. Ne sont-ils que des étiquettes ? Qualitative. Accordez la famille et la couleur se lit d’elle-même ; désaccordez-la et même une matrice correcte raconte une fausse histoire.
Les mêmes graphiques en R
Vous travaillez en R, ou dans les deux langages ? Les équivalents en grammaire des graphiques se trouvent dans les séries biostatistiques et ggplot2, et ils se correspondent un pour un — df.corr() + heatmap, c’est cor() + ggcorrplot(), et le facettage col=/row=, c’est facet_wrap()/facet_grid() :
Les blocs ci-dessus ont été exécutés au moment de la compilation. Modifiez celui-ci et appuyez sur Run pour construire vous-même la heatmap de corrélation — il s’exécute dans votre navigateur via Pyodide (aucune installation). Le premier Run télécharge seaborn et les dépendances de sa pile scientifique une fois (pandas, matplotlib et SciPy — quelques dizaines de Mo), puis c’est mis en cache et instantané.
🟢 Avec un agent IA
Apportez votre propre table — collez un df.head() et demandez à Prova« construis-moi une heatmap de corrélation, et quelle colormap devrait-elle utiliser ? » Elle écrit l’appel df.corr() + sns.heatmap, choisit une carte divergente centrée sur 0 pour des corrélations (ou une carte séquentielle pour une matrice d’effectifs/de moyennes), masque le triangle redondant, et crée des facettes d’une comparaison avec col=/row= quand vous le demandez. Parce que le runtime est juste là, vous l’exécutez et voyez la figure réelle — puis changez la colormap, ajoutez le masque, modifiez la facette — au lieu de faire confiance à un extrait à l’air plausible. The runtime is the judge. Demander à Prova →
Problèmes fréquents
Votre heatmap de corrélation utilise une colormap séquentielle et masque le signe.sns.heatmap(df.corr()) avec la carte par défaut ("rocket", séquentielle) — ou n’importe quelle carte de la famille viridis — progresse dans une seule direction, si bien qu’une forte corrélation négative se lit comme une valeur « faible » indiscernable de sens d’une faible corrélation positive. Les corrélations sont signées autour de zéro : passez une carte divergente avec le centre verrouillé — cmap="vlag", vmin=-1, vmax=1, center=0 — pour que le bleu signifie négatif, le rouge positif, et le blanc aucune relation. Dès l’instant où vos valeurs ont un zéro qui a du sens, divergente-et-centrée est le seul choix honnête.
Les annotations forment un mur de chiffres illisible sur une grande matrice.annot=True inscrit chaque cellule, ce qui est parfait pour un 4×4 et sans espoir pour un 30×30 — le texte s’effondre en bruit. Sur une grande matrice, supprimez les annotations (annot=False) et laissez la couleur porter l’information, ou réduisez-les avec annot_kws={"size": 7}, ou masquez le triangle supérieur (mask=np.triu(...)) pour diviser l’encombrement par deux. Réservez les annotations fmt=".2f" aux matrices assez petites pour qu’un lecteur lise réellement les chiffres.
Vos panneaux à facettes ne sont pas comparables parce que les axes se sont remis à l’échelle. Si vous avez construit la facette avec sharey=False (ou sharex=False), chaque panneau s’étire à ses propres données, si bien qu’un petit groupe paraît aussi « grand » qu’un grand, et qu’une distribution décalée paraît centrée. À moins que les panneaux ne vivent réellement sur des échelles différentes, gardez la valeur par défaut sharey=True — sur relplot/displot/catplot, passez facet_kws={"sharey": True} — pour qu’une position signifie la même chose dans chaque panneau. Si vous avez vraiment besoin d’axes indépendants, dites-le dans la légende de figure ; le lecteur ne peut pas le deviner à l’œil.
heatmap a écrasé ou étiré vos cellules. Par défaut, heatmap remplit l’Axes qu’on lui donne, si bien qu’une figure large donne des cellules rectangulaires larges. Pour une matrice de corrélation — où la grille doit se lire comme une grille — passez square=True pour que chaque cellule soit carrée quel que soit le rapport d’aspect de la figure, et dimensionnez la figure d’après la matrice plutôt que l’inverse.
Questions fréquentes
NoteComment faire une heatmap de corrélation en seaborn ?
Calculez la matrice, puis dessinez-la : corr = df.corr(numeric_only=True) suivi de sns.heatmap(corr, annot=True, fmt=".2f", cmap="vlag", vmin=-1, vmax=1, center=0). Le numeric_only=True écarte les colonnes non numériques, annot=True avec fmt=".2f" inscrit chaque corrélation, et la cmapdivergente centrée sur 0 montre le signe correctement. Ajoutez mask=np.triu(np.ones_like(corr, dtype=bool)) pour masquer le triangle supérieur redondant, et square=True pour que les cellules se lisent comme une grille.
NoteComment annoter une heatmap seaborn avec les valeurs ?
Passez annot=True pour inscrire la valeur de chaque cellule à l’intérieur, et fmt= pour formater le nombre — fmt=".2f" pour deux décimales, fmt=".0f" pour arrondir à l’entier, fmt="d" pour des entiers. Contrôlez le texte avec annot_kws, par exemple annot_kws={"size": 8} pour le réduire sur une matrice chargée. Pour annoter avec des nombres différents des couleurs (disons, afficher des effectifs mais colorer par pourcentage), passez un second tableau à annot= au lieu de True.
NoteQuelle colormap utiliser pour une heatmap seaborn ?
Accordez la famille de colormap aux données. Valeurs signées avec un zéro qui a du sens (corrélations, différences) → une carte divergente centrée sur zéro : cmap="vlag" (ou "coolwarm") avec center=0, vmin=-1, vmax=1. Magnitudes toutes positives (effectifs, moyennes) → une carte séquentielle où plus foncé signifie plus : "mako", viridis, "rocket". Évitez une carte séquentielle pour des corrélations — elle masque si une relation est positive ou négative — et évitez une carte divergente pour de pures magnitudes, où le centre neutre n’a aucun sens.
NoteQuelle est la différence entre FacetGrid et catplot en seaborn ?
FacetGrid est le moteur de facettage général : vous construisez la grille (col=/row=/hue=) puis appliquez avec .map n’importe quelle fonction de tracé à chaque panneau — contrôle total, deux étapes. catplot (ainsi que relplot, displot) est un raccourci de niveau figure qui est un FacetGrid avec une fonction de tracé pré-câblée, de sorte que sns.catplot(..., kind="box", col=...) construit la grille et dessine les boîtes en un seul appel. Utilisez la fonction de niveau figure quand votre graphique est l’un des types enveloppés ; descendez à FacetGrid quand vous avez besoin d’une fonction qu’ils n’enveloppent pas ou d’un contrôle par panneau qu’ils n’exposent pas.
NoteComment changer le thème ou la palette par défaut en seaborn ?
Appelez sns.set_theme() une fois en tête et chaque figure en hérite. style= définit l’arrière-plan ("whitegrid", "darkgrid", "white", "ticks") ; context= met à l’échelle les éléments selon le support ("notebook", "talk", "poster", "paper") ; palette= définit le cycle de couleurs par défaut. Pour styler seulement quelques panneaux sans changer le rendu global, utilisez les gestionnaires de contexte with sns.axes_style("ticks"): et with sns.plotting_context("talk"):. Tout réglage matplotlib que le thème n’expose pas passe par rc=, par exemple sns.set_theme(rc={"font.family": "serif"}).
Testez vos connaissances
ImportantÀ vous — une heatmap et une facette
Utilisez les données penguins (penguins = pd.read_csv("penguins.csv")) dans la cellule Essayez en direct ci-dessus.
Tâche 1. Construisez une heatmap de corrélation des quatre mesures avec le triangle supérieur, diagonale comprise, masqué, annotée à deux décimales, sur une colormap divergente centrée sur zéro. Puis changez cmap en "mako" et décrivez ce qui casse.
AstuceIndice
corr = penguins[measures].corr(), puis mask = np.triu(np.ones_like(corr, dtype=bool)). Passez mask=mask, annot=True, fmt=".2f", cmap="vlag", vmin=-1, vmax=1, center=0 à sns.heatmap. Remplacez par cmap="mako" et regardez les deux cellules de la profondeur du bec.
AstuceSolution
import matplotlib.pyplot as pltimport numpy as npimport pandas as pdimport seaborn as snspenguins = pd.read_csv("penguins.csv")sns.set_theme(style="whitegrid")measures = ["bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g"]corr = penguins[measures].corr()mask = np.triu(np.ones_like(corr, dtype=bool))fig, ax = plt.subplots(figsize=(6, 5))sns.heatmap(corr, mask=mask, annot=True, fmt=".2f", cmap="vlag", vmin=-1, vmax=1, center=0, square=True, linewidths=0.5, linecolor="white", ax=ax)plt.show()
Avec cmap="mako" (séquentielle) le signe disparaît : les corrélations négatives de la profondeur du bec (−0.58 avec la longueur de la nageoire, −0.47 avec la masse corporelle) et les positives (nageoire × masse à 0.87) se rendent toutes en points le long d’un unique dégradé du sombre au clair, si bien que vous ne pouvez plus distinguer une forte relation négative d’une relation positive modérée. C’est exactement pourquoi une heatmap de corrélation a besoin d’une carte divergente centrée sur zéro.
Tâche 2. Créez des facettes d’un nuage de points de bill_length_mm contre bill_depth_mm par species avec relplot, coloré par espèce, avec les axes partagés. Pourquoi le partage des axes importe-t-il ici ?
Les axes partagés (le défaut) placent les trois panneaux sur la même échelle de longueur et de profondeur du bec, de sorte que vous voyez que chaque espèce occupe une région différente du même espace — Adelie court-et-profond, Chinstrap long-et-profond, Gentoo long-et-peu profond. Avec des axes indépendants, chaque nuage remplirait son propre panneau et les différences entre espèces — tout l’intérêt — s’évanouiraient.
Vérification rapide. Vous avez une matrice d’effectifs (tous positifs, sans zéro qui ait du sens) à dessiner en heatmap. Optez-vous pour cmap="vlag" ou cmap="mako" ?
AstuceAfficher la réponse
cmap="mako" — une carte séquentielle. Les effectifs sont des magnitudes ordonnées sans centre particulier, donc un unique dégradé du sombre au clair les lit correctement (plus foncé = plus). Une carte divergente comme "vlag" est faite pour des données signées autour d’un zéro qui a du sens (corrélations, différences) ; son centre neutre n’aurait aucun sens sur de purs effectifs.
Conclusion
Vous avez lu toute une table des deux façons dont un analyste le fait. Une heatmap de corrélation — df.corr() versé dans sns.heatmap — a montré chaque paire numérique d’un coup, et bien la réussir consistait surtout à bien choisir la couleur : une carte divergente centrée sur zéro pour que le signe soit honnête, le triangle redondant masqué, les cellules annotées et carrées. Une heatmap séquentielle de moyennes par groupe a rendu le contraste concret — accordez la famille de palette selon que les données ont ou non un zéro qui a du sens. Puis le facettage a décomposé la comparaison en petits multiples : FacetGrid à la main, relplot/displot/catplot comme raccourci en une ligne, et les axes partagés comme ce qui maintient une facette en comparaison juste. Enfin, le style, le context et la palette de set_theme vous ont donné l’unique endroit d’où contrôler le rendu de toute la série.
Deux choses se transposent à vos propres données. La colormap est une décision, pas un réglage par défaut — divergente-et-centrée pour des valeurs signées, séquentielle pour des magnitudes, qualitative pour des catégories — et la mauvaise induit en erreur, en silence. Et gardez les axes de facettes partagés à moins que les panneaux ne vivent vraiment sur des échelles différentes, pour qu’une position signifie la même chose partout. Réglez le thème une fois, accordez la palette aux données, et la figure se lit d’elle-même.
Prouvez que vous savez le faire. Maîtrisez toute la série Visualisation de données en Python — suivez votre parcours, construisez des projets et obtenez un certificat.