Tracés catégoriels Seaborn : boxplot, barplot, violon, strip & catplot

Comparez une mesure entre groupes et terminez sur la figure qui mérite d’être montrée — une boîte qui ne cache jamais ses points bruts ni sa moyenne.

Comparez une mesure numérique entre groupes avec les tracés catégoriels de seaborn : boîte à moustaches, la vitrine boîte + points + moyenne, violon, barres avec intervalles de confiance, points-interaction, strip, swarm, effectifs et le catplot de niveau figure — chacun lu depuis un DataFrame avec un seul argument hue.

Date de publication

17 juillet 2026

Modifié

18 juillet 2026

AstucePoints clés
  • Les tracés catégoriels opposent une mesure numérique à une colonne de regroupement. sns.boxplot(data=df, x="species", y="body_mass_g") — une catégorie sur un axe, un nombre sur l’autre — est la forme de chaque tracé de cette page.
  • Ne livrez jamais une boîte nue. La figure maison est une boîte plus les points bruts dispersés plus la moyenne du groupe — le lecteur voit le résumé, l’échantillon et la moyenne dans un seul cadre.
  • Chaque tracé répond à une question différente : boxplot (le résumé à cinq nombres), violinplot (la forme complète), barplot (une moyenne et son intervalle de confiance), pointplot (moyennes et interactions), stripplot/swarmplot (chaque point), countplot (effectifs).
  • Une barre cache la distribution — dites-le. Une barre de moyennes de groupe est honnête sur la moyenne et muette sur la dispersion ; ce silence est exactement pourquoi nous superposons des points sur une boîte à la place.
  • hue= ajoute un second regroupement ; dodge= et split= le placent. Un seul argument scinde chaque tracé catégoriel selon une seconde variable — boîtes côte à côte, violons scindés, points décalés.
  • catplot est celui de niveau figure. Les mêmes tracés via kind=, plus le facettage col=/row= — la seule fonction catégorielle qui construit sa propre figure.

Introduction

Vous avez la table des manchots et une colonne de regroupement — espèce, sexe, île — et la question que se pose ensuite un analyste : comment une mesure se compare-t-elle entre ces groupes, et puis-je produire une figure qui mérite d’être montrée ? Seaborn : distributions et relations répondait à comment les mesures sont-elles liées et quelle forme ont-elles. Cette leçon répond à comment diffèrent-elles par groupe — la moitié catégorielle de seaborn.

Le plan est une vraie comparaison, construite pas à pas. Nous partons d’une boîte à moustaches de la masse corporelle par espèce, puis nous en faisons la figure autour de laquelle toute cette série est bâtie — une boîte qui montre ses points bruts et sa moyenne, jamais un résumé nu. À partir de là, nous échangeons les autres tracés catégoriels à mesure que la question change : un violon pour la forme complète, une barre pour la moyenne et son incertitude, un point plot pour une interaction, strip et swarm pour les valeurs brutes, un tracé d’effectifs pour les fréquences, et catplot pour facetter le tout selon un second regroupement.

Cela s’appuie directement sur les deux leçons qui la précèdent. La distinction niveau-axes vs niveau-figure de la leçon 2 gouverne encore tout ici : boxplot, violinplot, barplot, stripplot, swarmplot, countplot et pointplot sont tous de niveau-axes (ils dessinent sur un Axes que vous passez avec ax= et le renvoient), tandis que catplot est la seule fonction de niveau-figure qui construit sa propre figure pour pouvoir facetter. Et le style maison — sns.set_theme() plus une palette viridis fixée par espèce — est le même, si bien qu’une espèce garde sa couleur à travers les trois leçons.

Les données sont le même CSV des manchots livré à côté de cette leçon, lu avec pd.read_csv — pas de seaborn.load_dataset qui va chercher sur le réseau. Chaque figure a été produite par le code montré, et les blocs se construisent dans l’ordre. Pour expérimenter, éditez 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 au mot près — set_theme() pour l’allure, 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 dans toutes les autres leçons. Exécutez-la une fois ; chaque figure ci-dessous en hérite.

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

# House style — one call, applied to every figure that follows (same as lessons 1 and 2)
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 series
SEX_COLORS = ["#4c9be8", "#f4a259"]        # a two-level hue (male / female)

penguins = pd.read_csv("penguins.csv")

# The SAME three species colours as lessons 1 and 2, pinned so a species keeps its colour
SPECIES = ["Adelie", "Chinstrap", "Gentoo"]
PALETTE = dict(zip(SPECIES, plt.get_cmap("viridis")(np.linspace(0.1, 0.85, 3))))

print(penguins.shape, "rows x cols")
print(penguins["species"].value_counts().to_dict())
(344, 7) rows x cols
{'Adelie': 152, 'Gentoo': 124, 'Chinstrap': 68}

Deux habitudes traversent toute la leçon. Nous passons toujours order=SPECIES pour que les catégories apparaissent dans une séquence fixe plutôt que dans l’ordre où elles se présentent dans le fichier, et nous passons palette=PALETTE (un dict) pour que chaque espèce soit épinglée à sa couleur, que les trois soient présentes ou non.

boxplot : le résumé à cinq nombres

Prenez une boîte à moustaches pour comparer une distribution entre groupes d’un coup d’œil. Chaque boîte couvre l’écart interquartile (IQR, les 50 % du milieu — du 25e au 75e percentile), la ligne à l’intérieur est la médiane, et les moustaches atteignent les points les plus éloignés à moins de 1.5×IQR ; tout ce qui les dépasse est dessiné en valeur aberrante. Un seul appel vous donne les trois espèces côte à côte.

import matplotlib.pyplot as plt
import seaborn as sns

fig, ax = plt.subplots()
sns.boxplot(
    data=penguins, x="species", y="body_mass_g", order=SPECIES,
    hue="species", palette=PALETTE, legend=False, width=0.6, ax=ax,
)
ax.set_xlabel("Species")
ax.set_ylabel("Body mass (g)")
ax.set_title("Body mass by species")
fig.tight_layout()
plt.show()
Box plot of penguin body mass in grams for the three species, coloured Adelie purple, Chinstrap teal and Gentoo green. The Adelie and Chinstrap boxes overlap heavily with medians at about 3700 grams, while the Gentoo box sits distinctly higher with a median near 5000 grams. One outlier point sits just above and one just below the Chinstrap whiskers; the Adelie and Gentoo boxes have none.
Figure 1

La comparaison est immédiate. Gentoo se place nettement au-dessus des deux autres — médiane 5000 g contre 3700 g pour Adelie comme pour Chinstrap — et les boîtes d’Adelie et de Chinstrap se chevauchent presque entièrement. La boîte rapporte aussi la dispersion : Chinstrap est le groupe le plus resserré (IQR 3488–3950 g), Adelie un peu plus large (3350–4000 g), et Gentoo le plus large (4700–5500 g). C’est la même histoire à trois grappes, Gentoo-est-le-lourd, que racontaient les histogrammes de la leçon 2, désormais en comparaison directe entre groupes.

Parce que boxplot est de niveau-axes, il a pris notre ax= et l’a renvoyé, si bien que les appels ax.set_* de la leçon 1 fonctionnent inchangés — le schéma de chaque tracé de cette leçon sauf catplot.

La figure qui mérite d’être montrée : boîte + points + moyenne

Une boîte à moustaches est un résumé, et un résumé peut mentir par omission : il cache la taille d’échantillon brute et les points individuels, et il montre la médiane, non la moyenne. Le standard maison corrige les deux — dessinez la boîte, dispersez les observations réelles par-dessus avec un stripplot, et marquez la moyenne de chaque groupe avec un pointplot. Résumé, échantillon et moyenne dans un seul cadre.

import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns

np.random.seed(42)                         # stripplot jitter is random — pin it

fig, ax = plt.subplots(figsize=(7.5, 5))

# 1. the box, softened so the points read on top
sns.boxplot(
    data=penguins, x="species", y="body_mass_g", order=SPECIES,
    hue="species", palette=PALETTE, legend=False,
    width=0.55, showfliers=False,          # points show the outliers — don't double-draw them
    boxprops={"alpha": 0.35}, linewidth=1.3, ax=ax,
)
# 2. every raw observation, jittered so they don't stack
sns.stripplot(
    data=penguins, x="species", y="body_mass_g", order=SPECIES,
    hue="species", palette=PALETTE, legend=False,
    size=3.2, alpha=0.6, jitter=0.18, ax=ax,
)
# 3. the group mean as a diamond
sns.pointplot(
    data=penguins, x="species", y="body_mass_g", order=SPECIES,
    estimator="mean", errorbar=None, color="black",
    markers="D", markersize=9, linestyle="none", ax=ax,
)

ax.set_xlabel("Species")
ax.set_ylabel("Body mass (g)")
ax.set_title("Body mass by species — box, points and mean")
fig.tight_layout()
plt.show()
Box plot of penguin body mass in grams for three species, coloured Adelie purple, Chinstrap teal and Gentoo green, with the raw observations jittered as small points over each box and a black diamond marking each group mean. Adelie and Chinstrap overlap near 3700 grams while Gentoo stand clearly higher near 5000 grams; the mean sits almost on the median for Adelie and Chinstrap and slightly above it for Gentoo.
Figure 2

C’est la figure à privilégier, et elle se lit sur trois niveaux à la fois. La boîte donne la médiane et la dispersion ; les points dispersés montrent chaque manchot et la taille d’échantillon honnête — vous voyez qu’il y a bien moins de Chinstrap (68) que d’Adelie (151) ; et le losange noir marque la moyenne (Adelie 3701 g, Chinstrap 3733 g, Gentoo 5076 g). Remarquez que le losange se place presque exactement sur la ligne de médiane pour Adelie et Chinstrap — leurs distributions sont symétriques — mais un peu au-dessus de la médiane pour Gentoo, la signature d’une légère asymétrie à droite qu’une boîte nue ne montrerait jamais.

Trois détails la rendent de qualité publication. showfliers=False sur la boîte l’empêche de dessiner des valeurs aberrantes que la couche strip montre déjà, si bien qu’aucun point n’est dessiné deux fois. boxprops={"alpha": 0.35} estompe le remplissage de la boîte pour que les points ressortent clairement par-dessus. Et np.random.seed(42) n’est pas optionnel : stripplot ajoute une gigue horizontale aléatoire, donc sans graine fixe la figure change à chaque rendu — épinglez-la et le tracé est reproductible. (estimator="mean" et errorbar=None transforment pointplot en simple marqueur de moyenne ; nous ajoutons l’intervalle de confiance délibérément dans la section suivante.)

violinplot : la forme complète

Une boîte à moustaches résume une distribution à cinq nombres ; un graphique en violon dessine toute sa densité — la même courbe de noyau de la leçon 2, reflétée en une forme et dressée sur l’axe des catégories. C’est le tracé à utiliser quand la forme compte : bimodalité, asymétrie, une queue épaisse qu’une boîte aplatirait. Passer un hue à deux niveaux avec split=True met un groupe sur chaque moitié, si bien que vous comparez deux distributions dans la largeur d’un seul violon.

import matplotlib.pyplot as plt
import seaborn as sns

fig, ax = plt.subplots(figsize=(7.5, 5))
sns.violinplot(
    data=penguins.dropna(subset=["sex"]), x="species", y="body_mass_g", order=SPECIES,
    hue="sex", split=True, gap=0.1, inner="quart",
    palette=SEX_COLORS, ax=ax,
)
ax.set_xlabel("Species")
ax.set_ylabel("Body mass (g)")
ax.set_title("Body mass by species and sex")
ax.legend(title="Sex")
fig.tight_layout()
plt.show()
Split violin plot of penguin body mass in grams by species, with the male half in blue on the left and the female half in orange on the right of each violin. In every species the male half sits higher than the female half, and the gap is widest for Gentoo. Dashed lines inside each half mark the quartiles.
Figure 3

Scinder par sexe révèle ce que la boîte agrégée ne pouvait pas : les mâles sont plus lourds que les femelles dans chaque espèce, et les formes mâle et femelle se chevauchent à peine au sein d’une espèce. L’écart est le plus large chez Gentoo — la moitié mâle culmine près de 5485 g contre 4680 g pour les femelles — et plus étroit chez Adelie et Chinstrap. Cette différence d’écarts est un vrai motif (une interaction), et les deux tracés suivants la précisent.

Deux arguments font le travail. split=True a besoin d’un hue à exactement deux niveaux — il en reflète un de chaque côté de la ligne centrale. inner="quart" dessine les quartiles en lignes pointillées à l’intérieur de chaque moitié ("box" niche une mini boîte à moustaches, "point" montre chaque observation, None la laisse épurée). Et notez le .dropna(subset=["sex"]) : 11 manchots n’ont pas de sexe enregistré, et un violon split dessinerait sinon une troisième catégorie bancale — retirez-les explicitement pour que la comparaison soit propre.

barplot : une moyenne et son incertitude — et ce qu’elle cache

Un diagramme en barres dans seaborn n’est pas un graphique de fréquences (ça, c’est countplot, ci-dessous) — par défaut il dessine la moyenne de y pour chaque groupe, avec un intervalle de confiance à 95 % en barre d’erreur. C’est le bon tracé quand la moyenne est le message et que vous voulez son incertitude sur la figure.

import matplotlib.pyplot as plt
import seaborn as sns

fig, ax = plt.subplots()
sns.barplot(
    data=penguins, x="species", y="body_mass_g", order=SPECIES,
    hue="species", palette=PALETTE, legend=False,
    estimator="mean", errorbar=("ci", 95), seed=42,   # bootstrap CI — seed it
    capsize=0.15, ax=ax,
)
ax.set_xlabel("Species")
ax.set_ylabel("Mean body mass (g)")
ax.set_title("Mean body mass by species, with 95% CI")
fig.tight_layout()
plt.show()
Bar chart of mean penguin body mass in grams by species, Adelie purple, Chinstrap teal and Gentoo green, each bar topped with a short error-bar cap. The Adelie and Chinstrap bars are almost the same height near 3700 grams while the Gentoo bar is much taller near 5075 grams. The Chinstrap error bar is visibly wider than the others.
Figure 4

Les hauteurs de barres sont les trois moyennes — Adelie 3701 g, Chinstrap 3733 g, Gentoo 5076 g — et les caps sont les intervalles de confiance à 95 %. Lisez-les : Adelie a l’intervalle le plus resserré (environ ±70 g) — c’est elle qui compte le plus d’oiseaux (151) — tandis que celui de Chinstrap est le plus large (environ ±90 g) sur le plus petit effectif (68), donc sa moyenne est la moins certaine ; Gentoo se situe entre les deux. L’intervalle de confiance porte sur la précision de la moyenne, non sur la dispersion des manchots — une distinction sur laquelle revient la section Problèmes fréquents.

Passons à la partie honnête. Ce diagramme en barres dit Adelie ≈ Chinstrap < Gentoo, et c’est tout ce qu’il dit. Il a jeté tout ce que la boîte à moustaches montrait — que les distributions d’Adelie et de Chinstrap se chevauchent presque entièrement, que Gentoo a la plus large dispersion, que les tailles d’échantillon diffèrent d’un facteur trois. Une barre de moyennes est muette sur la distribution, et ce silence est précisément pourquoi la figure boîte + points ci-dessus est le meilleur choix par défaut : elle garde la moyenne et montre ce que la barre cache. Utilisez un diagramme en barres quand la moyenne est réellement toute l’histoire ; prenez la boîte sinon.

Parce que l’intervalle de confiance est calculé par rééchantillonnage bootstrap — un processus aléatoire — passez seed=42 pour que les barres d’erreur soient identiques à chaque rendu. Sans lui, elles vacillent légèrement à chaque fois.

pointplot : moyennes et interactions

Un point plot montre les mêmes moyennes de groupe qu’un diagramme en barres, mais sous forme de points reliés par des lignes. Les barres ont disparu, et c’est tout l’intérêt : les lignes facilitent la comparaison des moyennes entre groupes et, quand vous ajoutez un second hue, la lecture d’une interaction — si l’effet d’une variable change selon les niveaux d’une autre.

import matplotlib.pyplot as plt
import seaborn as sns

fig, ax = plt.subplots()
sns.pointplot(
    data=penguins.dropna(subset=["sex"]), x="species", y="body_mass_g", order=SPECIES,
    hue="sex", palette=SEX_COLORS,
    estimator="mean", errorbar=("ci", 95), seed=42,
    dodge=0.15, ax=ax,
)
ax.set_xlabel("Species")
ax.set_ylabel("Mean body mass (g)")
ax.set_title("Mean body mass by species and sex")
ax.legend(title="Sex")
fig.tight_layout()
plt.show()
Point plot of mean penguin body mass in grams by species, with a separate line for males in blue and females in orange, each point carrying a short confidence-interval bar. Both lines rise from Adelie to Gentoo, the male line always above the female line, and the vertical gap between them is widest at Gentoo — the lines are not parallel.
Figure 5

Lisez les deux lignes. Les mâles (bleu) sont plus lourds que les femelles (orange) dans chaque espèce — les deux lignes montent d’Adelie à Gentoo — mais les lignes ne sont pas parallèles : l’écart mâle–femelle est de 675 g chez Adelie, se resserre à 412 g chez Chinstrap, puis s’élargit fortement à 805 g chez Gentoo. Des lignes non parallèles sont la signature visuelle d’une interaction — l’ampleur de la différence de sexe dépend de l’espèce. Il y a aussi un croisement plus subtil : les mâles Adelie (4043 g) pèsent plus que les mâles Chinstrap (3939 g), pourtant les femelles Adelie (3369 g) sont plus légères que les femelles Chinstrap (3527 g), et c’est pourquoi les deux espèces paraissent identiques quand on agrège les sexes mais diffèrent une fois qu’on les scinde.

dodge=0.15 décale les deux lignes latéralement pour que leurs barres de confiance ne se chevauchent pas. Les lignes de liaison n’impliquent pas que l’espèce soit ordonnée ou continue — ici, elles sont purement une aide visuelle pour suivre les moyennes de chaque sexe et repérer où l’écart change. Quand une comparaison tient à comment une différence varie entre groupes, le point plot est la façon la plus claire de le montrer.

stripplot et swarmplot : chaque point

Parfois vous ne voulez aucun résumé — juste les observations brutes, un point par manchot. stripplot les disperse avec un peu de gigue pour qu’ils ne s’empilent pas ; swarmplot les tasse pour qu’aucun ne se chevauche, au prix d’être lent sur de grandes données. Les deux sont ce que vous superposez sur une boîte (comme dans la vitrine) — mais seuls, ils sont le choix honnête pour un petit groupe où une boîte sur-résumerait une poignée de points.

import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns

np.random.seed(42)                         # strip jitter is random; swarm is deterministic

fig, axes = plt.subplots(1, 2, figsize=(9, 4.5), sharey=True)

sns.stripplot(
    data=penguins, x="species", y="body_mass_g", order=SPECIES,
    hue="species", palette=PALETTE, legend=False,
    size=3.5, alpha=0.7, jitter=0.2, ax=axes[0],
)
axes[0].set(xlabel="Species", ylabel="Body mass (g)", title="stripplot (jittered)")

sns.swarmplot(
    data=penguins, x="species", y="body_mass_g", order=SPECIES,
    hue="species", palette=PALETTE, legend=False,
    size=3.5, ax=axes[1],
)
axes[1].set(xlabel="Species", ylabel="", title="swarmplot (non-overlapping)")

fig.tight_layout()
plt.show()
Two side-by-side panels of penguin body mass by species. The left panel is a strip plot with jittered points that overlap in dense regions; the right panel is a swarm plot with the same points spread horizontally so none overlap, making the shape of each species' distribution clearer. Both show Adelie and Chinstrap near 3700 grams and Gentoo higher near 5000 grams.
Figure 6

Mêmes données, deux façons de placer les points. Le strip plot disperse horizontalement d’une quantité aléatoire, si bien que les régions denses s’empilent encore — rapide, et parfait en superposition. Le swarm plot calcule une disposition sans chevauchement, si bien que la largeur du nuage à une hauteur donnée se lit comme une densité : vous voyez que Chinstrap s’amincit et que Gentoo s’étale largement. Le swarm est le plus informatif des deux quand il est seul, mais il ralentit et avertit dès qu’un groupe dépasse plusieurs centaines de points — pour ceux-là, superposez plutôt un strip dispersé sur une boîte.

Une note de reproductibilité se reporte depuis la vitrine : stripplot a besoin de np.random.seed(42) pour être stable, tandis que la disposition de swarmplot est déterministe et ne nécessite aucune graine.

countplot : combien dans chaque groupe

Chaque tracé jusqu’ici plaçait une mesure sur l’axe des y. Un tracé d’effectifs n’y met rien — il compte les lignes de chaque catégorie, la réponse catégorielle à « quelle est la taille de chaque groupe ? ». C’est histplot pour une variable catégorielle, et c’est le tracé qui vous garde honnête sur la taille d’échantillon.

import matplotlib.pyplot as plt
import seaborn as sns

fig, ax = plt.subplots()
sns.countplot(
    data=penguins, x="species", order=SPECIES,
    hue="sex", palette=SEX_COLORS, ax=ax,
)
ax.set_xlabel("Species")
ax.set_ylabel("Number of penguins")
ax.set_title("How many penguins, by species and sex")
ax.legend(title="Sex")
# label each bar with its count
for container in ax.containers:
    ax.bar_label(container, fontsize=8, padding=2)
fig.tight_layout()
plt.show()
Grouped bar chart counting penguins per species, split by sex into a blue male bar and an orange female bar. Adelie has 73 of each sex, Chinstrap 34 of each, and Gentoo 58 females and 61 males. The male and female bars are nearly equal within every species.
Figure 7

Les effectifs confirment ce que les points dispersés laissaient entendre : les groupes sont déséquilibrés par espèce (Adelie 146, Gentoo 119, Chinstrap 68 une fois les 11 oiseaux sans sexe retirés) mais presque parfaitement équilibrés par sexe au sein de chacun (Adelie 73/73, Chinstrap 34/34, Gentoo 58 femelles / 61 mâles). Cet équilibre vaut la peine d’être vérifié avant de faire confiance à une comparaison par sexe — et il explique les larges barres d’erreur de Chinstrap plus haut : moins d’oiseaux, moyennes moins certaines. ax.bar_label inscrit l’effectif exact sur chaque barre, transformant un graphique que vous plisseriez les yeux à lire en un que vous lisez directement.

catplot : la version de niveau figure, facettée

Tout ce qui précède est de niveau-axes — il dessine sur l’Axes que vous lui remettez. catplot est la seule fonction catégorielle de niveau-figure : choisissez le tracé avec kind= ("box", "violin", "bar", "strip", "swarm", "count", "point"), et obtenez le facettage col=/row= gratuitement — le même bénéfice que relplot et displot donnaient dans la leçon 2.

import seaborn as sns

g = sns.catplot(
    data=penguins.dropna(subset=["sex"]),
    x="sex", y="body_mass_g",
    col="species", col_order=SPECIES,
    hue="species", palette=PALETTE, legend=False,
    kind="box", showfliers=False,
    height=3.6, aspect=0.7,
)
g.set_axis_labels("Sex", "Body mass (g)")
g.set_titles("{col_name}")
g.figure.suptitle("Body mass by sex, per species", y=1.03, fontweight="bold")
plt.show()
Three side-by-side box-plot panels, one per species, each comparing male and female body mass in grams. In every panel the male box sits higher than the female box; the male-minus-female gap is small for Chinstrap and large for Gentoo. The panels share a y-axis so the Gentoo panel is visibly shifted upward.
Figure 8

Facetter par espèce dispose l’interaction panneau par panneau : au sein de chaque espèce les mâles pèsent plus que les femelles, et l’ampleur de cet écart grandit de gauche à droite — à peine un pas chez Chinstrap, un saut net chez Gentoo. Parce que les panneaux partagent un axe des y, le panneau Gentoo est visiblement relevé, si bien que vous lisez la différence entre espèces et la différence de sexe intra-espèce d’un même coup d’œil. C’est le même résultat que le point plot, montré en distributions complètes plutôt qu’en simples moyennes.

Quatre habitudes de catplot reflètent les fonctions de niveau figure de la leçon 2. kind= choisit le tracé. height= et aspect= dimensionnent chaque panneau — pas figsize=, qu’une fonction de niveau figure rejette. col_order= épingle la séquence des panneaux. Et g.set_axis_labels(...), g.set_titles("{col_name}") et g.figure.suptitle(...) étiquettent la grille, car après un appel de niveau figure g est une grille, non un Axes — ax.set_title(...) ne ferait silencieusement rien.

Note

Le facettage, les palettes et les thèmes ont leur propre leçon, la suivante de cette série. Ici, catplot apparaît seulement comme le membre de niveau figure de la famille catégorielle.

Quel tracé catégoriel pour quelle question ?

La leçon 1 choisissait un tracé à partir de la question et la leçon 2 ajoutait la dimension de groupe ; ici la question est toujours comparer entre catégories — donc choisissez selon ce que vous voulez montrer de chaque groupe.

Votre question Le tracé L’appel
Comparer une distribution entre groupes (résumé) Boîte sns.boxplot(data=df, x="g", y="v")
…et montrer les points bruts et la moyenne Boîte + strip + point boîte, puis stripplot, puis pointplot(estimator="mean")
Comparer la forme complète entre groupes Violon sns.violinplot(..., hue=, split=True)
Comparer une moyenne et son incertitude Barre sns.barplot(..., estimator="mean", errorbar=("ci", 95))
Lire une interaction entre deux regroupements Point sns.pointplot(..., hue=, dodge=True)
Montrer chaque observation Strip / swarm sns.stripplot(...) / sns.swarmplot(...)
Compter combien dans chaque catégorie Effectifs sns.countplot(data=df, x="g", hue=)
N’importe lequel ci-dessus, facetté selon une variable catplot sns.catplot(..., kind=, col=)

En cas de doute : commencez par la figure boîte + points + moyenne — elle répond à la plupart des comparaisons entre groupes d’un coup — puis passez à un violon si la forme compte, une barre ou un point si seule la moyenne compte, ou un tracé d’effectifs si vous vous interrogez sur la taille d’échantillon plutôt que sur une mesure.

Les mêmes tracés en R

Vous travaillez en R, ou dans les deux langages ? Les équivalents en grammaire des graphiques vivent dans les séries ggplot2 et ggpubr, et ils se correspondent un pour un — hue= est aes(fill = sex), et la figure boîte + points + moyenne est le standard maison ggpubr :

Essayez en direct

Les blocs ci-dessus ont tourné à la compilation. Éditez celui-ci et appuyez sur Run pour construire vous-même la figure boîte + points + moyenne — elle s’exécute dans votre navigateur via Pyodide (sans installation). Le premier Run télécharge seaborn et ses dépendances scientifiques 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 « quel tracé catégoriel compare ma mesure entre ces groupes, et comment superposer les points bruts et la moyenne ? » Elle choisit entre boxplot, violinplot et barplot à partir de ce que vous demandez, écrit l’appel hue=/dodge=/split=, et superpose le strip et la moyenne à la façon maison. Parce que le runtime est juste là, vous l’exécutez et voyez la figure réelle — puis changez le regroupement, la palette, la facette — au lieu de faire confiance à un extrait à l’air plausible. The runtime is the judge. Demander à Prova →

Problèmes fréquents

Vos groupes apparaissent dans le mauvais ordre — et il change avec de nouvelles données. Seaborn ordonne les catégories selon l’ordre où elles apparaissent d’abord dans le DataFrame, si bien qu’un fichier re-trié ou rechargé rebrasse silencieusement vos barres. Épinglez-le : passez order=["Adelie", "Chinstrap", "Gentoo"] (et hue_order=[...] pour la scission hue). C’est aussi ainsi que vous retirez une catégorie — ne listez que celles que vous voulez. Fixez toujours order= sur un tracé que vous publierez ; le défaut n’est pas stable.

La gigue (ou l’intervalle de confiance) est différente à chaque rendu. La gigue de stripplot et les intervalles de confiance bootstrap de barplot/pointplot sont aléatoires. Pour une figure reproductible, fixez np.random.seed(42) avant un stripplot/swarmplot, et passez seed=42 à barplot/pointplot. Sans cela, les points et les barres d’erreur vacillent à chaque exécution — sans conséquence à l’écran, mais cela casse une figure archivée. (swarmplot est déterministe et ne nécessite aucune graine.)

Vos points hue se retrouvent les uns sur les autres. Quand vous ajoutez un hue à un stripplot, swarmplot ou pointplot, seaborn empile les sous-groupes à la même position x sauf si vous lui dites de les séparer. Passez dodge=True pour les décaler côte à côte — sinon les points mâles et femelles se superposent et vous ne pouvez pas les comparer. (boxplot/violinplot/barplot décalent automatiquement quand on leur donne un hue.)

Vous lisez la barre d’erreur de la barre comme la dispersion des données. Une barre d’erreur de barplot est un intervalle de confiance à 95 % pour la moyenne par défaut — il rétrécit à mesure que l’échantillon grandit, et ce n’est pas l’étendue des manchots. Si vous voulez que la barre d’erreur montre la variabilité à la place, passez errorbar="sd" (écart-type) ou errorbar=("pi", 95) (un intervalle de percentiles). Dites laquelle vous avez utilisée dans la légende de figure ; un lecteur ne peut pas les distinguer à l’œil.

Questions fréquentes

Passez la colonne de regroupement à x= (ou y= pour des boîtes horizontales) et la colonne numérique à l’autre axe : sns.boxplot(data=df, x="species", y="body_mass_g"). Seaborn dessine une boîte par catégorie. Pour scinder chaque boîte selon une seconde variable, ajoutez hue="sex" — les boîtes se décalent côte à côte automatiquement. Épinglez l’ordre des catégories avec order=[...] (et hue_order=[...]) pour qu’il ne change pas quand les données changent.

Dessinez la boîte, puis superposez un stripplot (points dispersés) ou swarmplot (sans chevauchement) sur le même Axes : sns.boxplot(data=df, x="species", y="body_mass_g", ax=ax) puis sns.stripplot(data=df, x="species", y="body_mass_g", ax=ax). Utilisez showfliers=False sur la boîte pour que les valeurs aberrantes ne soient pas dessinées deux fois, et estompez la boîte avec boxprops={"alpha": 0.35} pour que les points ressortent par-dessus. Fixez d’abord np.random.seed(42), car la gigue du strip est aléatoire. Ajoutez un pointplot avec estimator="mean" pour marquer aussi la moyenne du groupe.

Une boîte à moustaches résume chaque groupe à cinq nombres — médiane, quartiles, moustaches — donc elle est compacte et se lit d’un coup d’œil, mais elle cache la forme de la distribution. Un graphique en violon dessine la densité par noyau complète, révélant bimodalité, asymétrie ou une queue épaisse qu’une boîte aplatirait — au prix d’être plus chargé et de dépendre d’une largeur de lissage. Utilisez une boîte pour une comparaison rapide à cinq nombres ; utilisez un violon (souvent avec split=True pour un hue à deux niveaux) quand la forme est le sujet. Dans les deux cas, superposer les points bruts vous garde honnête sur la taille d’échantillon.

Par défaut, ce sont un intervalle de confiance à 95 % pour la moyenne du groupe, calculé par rééchantillonnage bootstrap — elles décrivent donc avec quelle précision la moyenne est estimée, et elles rétrécissent à mesure que l’échantillon grandit. Ce n’est pas la dispersion des données. Changez-les avec errorbar="sd" pour l’écart-type, errorbar=("se", 1) pour une erreur standard, ou errorbar=("pi", 95) pour un intervalle de percentiles. Parce que l’intervalle de confiance par défaut est bootstrap (aléatoire), passez seed=42 pour une figure reproductible.

Ils répondent à trois questions différentes. barplot dessine une statistique de résumé (la moyenne par défaut) d’une colonne numérique par catégorie, avec un intervalle de confiance. countplot dessine le nombre de lignes de chaque catégorie — pas de colonne numérique, c’est un diagramme en barres de fréquences. histplot (de la leçon 2) répartit une colonne numérique en intervalles et compte chaque intervalle. Règle générale : une moyenne par groupe → barplot ; combien par catégorie → countplot ; la distribution d’un seul nombre → histplot.

Testez vos connaissances

Utilisez les données penguins (penguins = pd.read_csv("penguins.csv")) dans la cellule Essayez en direct ci-dessus.

Tâche 1. Construisez la figure maison pour flipper_length_mm au lieu de la masse corporelle : une boîte à moustaches par espèce, avec les points bruts dispersés et la moyenne du groupe (un losange) superposés. Épinglez l’ordre des espèces et fixez la graine de la gigue.

Trois appels de niveau-axes sur un même ax, dans l’ordre : sns.boxplot(...) avec showfliers=False et un boxprops estompé, puis sns.stripplot(...), puis sns.pointplot(..., estimator="mean", errorbar=None, linestyle="none"). Appelez np.random.seed(42) avant le strip plot.

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

penguins = pd.read_csv("penguins.csv")
sns.set_theme(style="whitegrid")
np.random.seed(42)
order = ["Adelie", "Chinstrap", "Gentoo"]

fig, ax = plt.subplots(figsize=(7.5, 5))
sns.boxplot(data=penguins, x="species", y="flipper_length_mm", order=order,
            color="#3a86d4", boxprops={"alpha": 0.35}, showfliers=False, ax=ax)
sns.stripplot(data=penguins, x="species", y="flipper_length_mm", order=order,
              color="#3a86d4", size=3.2, alpha=0.6, jitter=0.18, ax=ax)
sns.pointplot(data=penguins, x="species", y="flipper_length_mm", order=order,
              estimator="mean", errorbar=None, color="black",
              markers="D", markersize=9, linestyle="none", ax=ax)
ax.set(xlabel="Species", ylabel="Flipper length (mm)",
       title="Flipper length by species — box, points and mean")
fig.tight_layout()
plt.show()

La longueur des nageoires sépare les espèces plus nettement que la masse corporelle : Adelie (~190 mm) et Chinstrap (~196 mm) se chevauchent encore un peu, mais Gentoo (~217 mm) se place presque entièrement à l’écart des deux — trois boîtes distinctes plutôt que deux qui se chevauchent.

Tâche 2. Dessinez un violinplot de body_mass_g par species, scindé par sex. Pourquoi devez-vous passer exactement un hue à deux niveaux pour split=True ?

fig, ax = plt.subplots(figsize=(7.5, 5))
sns.violinplot(data=penguins.dropna(subset=["sex"]),
               x="species", y="body_mass_g", order=["Adelie", "Chinstrap", "Gentoo"],
               hue="sex", split=True, inner="quart", ax=ax)
ax.set(xlabel="Species", ylabel="Body mass (g)")
plt.show()

split=True reflète un niveau de hue sur chaque moitié du violon, il lui faut donc exactement deux niveaux — un par côté. Retirez d’abord les lignes sans sexe, sinon la troisième catégorie (NaN) casse la scission. La figure montre les mâles plus lourds que les femelles dans chaque espèce, avec l’écart le plus large chez Gentoo.

Vérification rapide. Vous voulez une boîte à moustaches dans le panneau en bas à droite d’une grille plt.subplots(2, 2). Appelez-vous sns.catplot ou sns.boxplot ?

sns.boxplot(..., ax=axes[1, 1]). Il est de niveau-axes, donc il dessine sur un Axes que vous avez déjà créé. catplot est de niveau figure — il construit sa propre figure séparée et n’a pas de paramètre ax=, il ne peut donc pas viser un panneau de votre grille.

Conclusion

Vous avez comparé une mesure entre groupes comme le fait un analyste : un boxplot pour le résumé à cinq nombres, puis la figure maison — boîte plus points dispersés plus moyenne — qui garde le résumé, l’échantillon et la moyenne dans un seul cadre honnête. À partir de là, le tracé suivait la question : un violinplot pour la forme complète, un barplot quand seule la moyenne et son intervalle de confiance comptent (et un aveu de ce qu’une barre nue cache), un pointplot pour lire l’interaction sexe-par-espèce, stripplot/swarmplot pour les points bruts, countplot pour les tailles d’échantillon, et catplot pour tout facetter. Les résultats tenaient ensemble — Gentoo l’espèce lourde, les mâles plus lourds que les femelles partout, l’écart le plus large chez Gentoo.

Deux choses se reportent sur vos propres données. Ne livrez jamais une boîte nue : superposez les points et la moyenne, et épinglez order= plus une graine pour que la figure soit reproductible. Et choisissez le tracé à partir de ce que vous voulez montrer de chaque groupe — une distribution, une forme, une moyenne, une interaction ou un effectif. Définissez le thème une fois, épinglez votre palette, et le reste consiste à choisir le bon tracé catégoriel pour la question.

Leçons connexes

Cette page vous a-t-elle été utile ?

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.

Commencer gratuitement →

Passez à Pro — Prova illimité sur vos propres données et un certificat vérifiable qui atteste la compétence.

dès 15 $/mois facturé annuellement

Passer à Pro →

✓ Vous êtes Pro — continuez. The runtime is the judge.

Recevez les nouvelles leçons R & Python par e-mail

Pratique, reproductible, sans spam. Désinscription à tout moment.

Double opt-in. Nous ne partageons jamais votre e-mail.

Partager cette pageXLinkedInRedditHN

Réutilisation

Citation

BibTeX
@online{2026,
  author = {},
  title = {Tracés catégoriels Seaborn : boxplot, barplot, violon, strip
    \& catplot},
  date = {2026-07-17},
  url = {https://www.datanovia.com/learn/programming/python-data-visualization/seaborn-categorical},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
“Tracés catégoriels Seaborn : boxplot, barplot, violon, strip & catplot.” 2026. July 17. https://www.datanovia.com/learn/programming/python-data-visualization/seaborn-categorical.