Put p-values & significance stars on any ggplot in one call — live in your browser
Learn to add p-values and significance levels to a ggplot in R with ggpubr. Use compare_means() for the data-frame answer and stat_compare_means() to annotate box plots — two groups (Wilcoxon or t-test), paired samples, more than two groups (ANOVA/Kruskal-Wallis), pairwise brackets, a reference group, and significance symbols. Edit and run every example live.
Date de publication
22 juin 2026
Modifié
7 juillet 2026
AstuceÀ retenir
Deux fonctions font tout le travail : compare_means() renvoie le test sous forme de data frame ; stat_compare_means() affiche la p-value directement sur un ggplot.
Deux groupes : Wilcoxon par défaut — ajoutez method = "t.test" pour le test paramétrique ; paired = TRUE pour des échantillons appariés.
Plus de deux groupes : affichez un test global (method = "anova" ou Kruskal-Wallis) et/ou des crochets par paires via comparisons = list(...).
Comparez chaque groupe à une référence avec ref.group = "...", ou à la moyenne générale avec ref.group = ".all.".
Remplacez l’étiquette verbeuse par des étoiles de signification avec label = "p.signif", et ajustez les seuils avec symnum.args.
Chaque graphique ci-dessous est rendu pour vous — puis ajustez n’importe quel exemple en direct dans le bac à sable.
Vous avez une boîte à moustaches et la question d’un relecteur : la différence est-elle significative ? En R, le paquet ggpubr y répond en une ligne — ajoutez la p-value (ou les étoiles de signification ***) à n’importe quel ggplot — boîte à moustaches, violon, barres ou courbes — avec stat_compare_means(). Pas de t.test() manuel, pas de bidouillage des coordonnées de geom_text(), pas d’export vers un logiciel de statistiques.
Il n’y a que deux fonctions à connaître :
compare_means() — exécute la comparaison et vous renvoie un data frame soigné (la p-value, la p-value ajustée, le seuil de signification). À utiliser quand vous voulez les chiffres.
stat_compare_means() — la couche ggplot2 qui exécute la même comparaison et dessine le résultat sur le graphique. À utiliser quand vous voulez l’annotation.
Cette leçon parcourt l’ensemble du flux de travail canonique sur les données intégrées ToothGrowth : deux groupes (non paramétrique et paramétrique), échantillons appariés, plus de deux groupes (global + par paires), comparaison à un groupe de référence, et comment passer aux symboles de signification. Chaque figure est rendue ici même, et vous pouvez les ré-exécuter ou les modifier en direct.
ggpubr applique automatiquement son propre thème de publication (theme_pubr()) à l’intérieur de ggboxplot() et consorts, si bien que les graphiques sont prêts à publier dès le départ — vous n’ajoutez pas de thème.
Le graphique canonique : crochets par paires + une p-value globale
Voici l’image que la plupart des gens recherchent : une boîte à moustaches de la longueur des dents par dose, avec un crochet et une p-value au-dessus de chaque paire de doses, plus le test global dans le coin. comparisons est une liste des paires à tester ; un second stat_compare_means() nu ajoute la p-value globale. Tout le reste dans la leçon est une variation sur cet unique appel.
library(ggpubr)df <- ToothGrowthdf$dose <-factor(df$dose)# the pairs of doses to comparemy_comparisons <-list(c("0.5", "1"), c("1", "2"), c("0.5", "2"))ggboxplot(df, x ="dose", y ="len",color ="dose", palette ="jco", add ="jitter") +stat_compare_means(comparisons = my_comparisons, # pairwise bracketslabel.y =c(35, 40, 48)) +stat_compare_means(label.y =56) # global p-value
Nous y arriverons progressivement. D’abord, le cas le plus simple : deux groupes.
Comparer deux groupes (le data frame)
Commençons par la question dépouillée du graphique : les deux suppléments (OJ vs VC) diffèrent-ils en longueur des dents ? compare_means() prend une formulevalue ~ group et renvoie une seule ligne soignée.
library(ggpubr)compare_means(len ~ supp, data = ToothGrowth)
Les colonnes valent la peine d’être connues, car l’annotation du graphique est construite à partir d’elles :
p — la p-value · p.adj — ajustée pour les tests multiples (par défaut "holm")
p.format — la p-value formatée pour l’affichage · p.signif — le seuil de signification (ns, *, **, …)
method — le test utilisé.
Par défaut, le test est celui de Wilcoxon (non paramétrique). Pour un t-test paramétrique, passez method = "t.test".
Ajouter la p-value à une boîte à moustaches
Mettons maintenant ce résultat sur un graphique. Construisez un ggboxplot(), puis ajoutez stat_compare_means() — sans argument, il exécute la même comparaison par défaut (Wilcoxon) et affiche method + p.
library(ggpubr)ggboxplot(ToothGrowth, x ="supp", y ="len",color ="supp", palette ="jco", add ="jitter") +stat_compare_means()
Passez au t-test paramétrique en transmettant directement method — stat_compare_means() le relaie à compare_means().
library(ggpubr)ggboxplot(ToothGrowth, x ="supp", y ="len",color ="supp", palette ="jco", add ="jitter") +stat_compare_means(method ="t.test")
Choisir l’étiquette : méthode, p-value ou étoiles
L’étiquette par défaut accole method et p. Vous voulez généralement quelque chose de plus soigné. Mappez une colonne différente avec aes(label = after_stat(...)), ou passez le raccourci sous forme de chaîne label :
aes(label = after_stat(p.format)) — seulement la p-value formatée, sans le nom de la méthode
aes(label = after_stat(p.signif)) — seulement le symbole de signification (***)
Utilisez label.x / label.y pour placer l’annotation en unités de données. Ici, seulement les étoiles de signification, positionnées à la main.
library(ggpubr)ggboxplot(ToothGrowth, x ="supp", y ="len",color ="supp", palette ="jco", add ="jitter") +stat_compare_means(aes(label =after_stat(p.signif)),label.x =1.5, label.y =40)
Le raccourci sous forme de chaîne label = "p.signif" (ou label = "p.format") fait la même chose avec moins de frappe :
library(ggpubr)ggboxplot(ToothGrowth, x ="supp", y ="len",color ="supp", palette ="jco", add ="jitter") +stat_compare_means(label ="p.format", label.x =1.4, label.y =40)
Comparer deux échantillons appariés
Si les mêmes sujets ont été mesurés dans les deux conditions, les échantillons sont appariés — passez paired = TRUE pour que le test en tienne compte. ggpaired() dessine les observations appariées avec des lignes de liaison.
library(ggpubr)ggpaired(ToothGrowth, x ="supp", y ="len",color ="supp", palette ="jco",line.color ="gray", line.size =0.4) +stat_compare_means(paired =TRUE)
Savoir si vos données sont réellement appariées est une question de plan d’étude, pas de graphique — apparier les mauvais échantillons change la p-value. Voir la future série statistiques pour choisir le bon test.
Comparer plus de deux groupes : le test global
Avec trois groupes ou plus, la première question est celle de l’omnibus : y a-t-il quelque chose de différent entre toutes les doses ? Ajoutez un stat_compare_means() nu — pour plus de 2 groupes, il utilise par défaut Kruskal-Wallis (le test unidirectionnel non paramétrique).
library(ggpubr)ggboxplot(ToothGrowth, x ="dose", y ="len",color ="dose", palette ="jco") +stat_compare_means()
Pour le test omnibus paramétrique (ANOVA à un facteur), passez method = "anova".
library(ggpubr)ggboxplot(ToothGrowth, x ="dose", y ="len",color ="dose", palette ="jco") +stat_compare_means(method ="anova")
Comparaisons par paires entre groupes
Un test global significatif dit que quelque chose diffère ; les comparaisons par paires disent quelles paires. Donnez à comparisons une liste des paires qui vous intéressent — ggpubr dessine un crochet et une p-value au-dessus de chacune, et un second stat_compare_means() conserve aussi la p-value globale. (Les crochets proviennent du paquet ggsignif sous le capot.)
library(ggpubr)df <- ToothGrowthdf$dose <-factor(df$dose)my_comparisons <-list(c("0.5", "1"), c("1", "2"), c("0.5", "2"))ggboxplot(df, x ="dose", y ="len",color ="dose", palette ="jco") +stat_compare_means(comparisons = my_comparisons) +# pairwise bracketsstat_compare_means(label.y =50) # global p-value
Si les crochets se chevauchent, fixez explicitement leurs hauteurs avec label.y (une valeur par comparaison) :
Tester par paires chaque paire explose à mesure que les groupes augmentent. Souvent, vous voulez seulement chaque groupe par rapport à une référence (un contrôle). Fixez ref.group à ce niveau et étiquetez avec les étoiles — ici, tout est comparé à la dose 0.5, avec l’ANOVA globale conservée en haut.
library(ggpubr)df <- ToothGrowthdf$dose <-factor(df$dose)ggboxplot(df, x ="dose", y ="len",color ="dose", palette ="jco") +stat_compare_means(method ="anova", label.y =45) +# global p-valuestat_compare_means(label ="p.signif", method ="t.test",ref.group ="0.5") # each vs the reference 0.5
Comparer chaque groupe à la moyenne générale (.all.)
Avec de nombreux groupes, comparer chacun à l’ensemble des données regroupées (la moyenne générale, ou base-mean) est une façon nette de repérer quels groupes se démarquent. Utilisez le spécial ref.group = ".all." ; une ligne pointillée à la moyenne globale rend la comparaison lisible.
library(ggpubr)df <- ToothGrowthdf$dose <-factor(df$dose)ggboxplot(df, x ="dose", y ="len",color ="dose", palette ="jco") +geom_hline(yintercept =mean(df$len), linetype =2) +# the grand meanstat_compare_means(method ="anova", label.y =45) +# global p-valuestat_compare_means(label ="p.signif", method ="t.test",ref.group =".all.") # each vs the grand mean
Pour supprimer entièrement les annotations ns non informatives, ajoutez hide.ns = TRUE.
Personnaliser les symboles de signification
Les seuils par défaut sont 0.0001 / 0.001 / 0.01 / 0.05 associés à **** / *** / ** / * / ns. Remplacez- les — symboles et seuils — avec symnum.args, une liste de cutpoints et des symbols correspondants. Ici, trois crochets par paires étiquetés avec des étoiles personnalisées.
symnum.args fonctionne de la même façon pour une comparaison ref.group ou une étiquette globale — partout où un symbole p.signif est dessiné.
Ajouter des p-values aux diagrammes en barres et en courbes
stat_compare_means() est indépendant du type de graphique — il fonctionne sur n’importe quel graphique ggpubr, pas seulement les boîtes à moustaches. Ajoutez-le à un diagramme en barres ou à un graphique en courbes de moyennes de groupes exactement de la même façon : les crochets par paires et l’étiquette globale proviennent du même appel. (Pour les diagrammes en barres et en courbes eux-mêmes — types de barres d’erreur, regroupement, décalage — voir la leçon Means & error bars et les leçons ggplot2 Bar plot / Error bars.)
Diagramme en barres des moyennes — ggbarplot(..., add = "mean_se"), puis les mêmes p-values par paires + globale :
Graphique en courbes des moyennes — ggline(..., add = "mean_se"), avec une comparaison globale entre les doses :
library(ggpubr)df <- ToothGrowthdf$dose <-factor(df$dose)ggline(df, x ="dose", y ="len", add ="mean_se", color ="#3a86d4") +stat_compare_means(label.y =30)
La recette ne change jamais : construisez le graphique ggpubr, puis superposez stat_compare_means(). Boîte à moustaches, violon, barres, courbes, points — les p-values proviennent de la même fonction.
Essayez en direct
Les graphiques ci-dessus ont été rendus au moment de la construction. Envie d’expérimenter ? Modifiez le code et appuyez sur Run — il s’exécute dans votre navigateur via webR (pas de serveur, pas d’installation). Essayez de remplacer method = "t.test", de changer la liste comparisons, ou de basculer l’étiquette vers "p.signif".
Vous travaillez en Python ? Un guide basé sur statannotations arrive dans la série Python.
🟢 Avec un agent IA
Demandez à Prova« quel test stat_compare_means() devrait-il utiliser pour mes données — Wilcoxon, t-test ou ANOVA ? » — elle répond avec du code que vous pouvez exécuter sur votre propre data frame et vérifie les hypothèses, pour que le choix soit reproductible. The runtime is the judge.Ask Prova →
Problèmes courants
La p-value du crochet diffère de la globale. C’est attendu — les crochets par paires (comparisons) exécutent un test par paire, tandis que le stat_compare_means() nu exécute un seul test omnibus (Kruskal-Wallis ou ANOVA) sur tous les groupes. Ils répondent à des questions différentes.
Les crochets se chevauchent ou débordent par le haut. Fixez label.y explicitement (une valeur par comparaison) et donnez de la marge à l’axe y, par ex. + ylim(NA, 60).
Les étiquettes ns encombrent le graphique. Ajoutez hide.ns = TRUE pour supprimer les annotations non significatives.
Je veux la p-value ajustée sur le crochet. Les crochets de comparisons affichent la p brute par paire ; pour des p-values corrigées pour la multiplicité sur les crochets, pré-calculez avec rstatix et dessinez-les avec stat_pvalue_manual() — c’est la prochaine leçon de cette série.
Mes groupes en x sont numériques et comparisons échoue. Les entrées des paires sont des chaînes de caractères qui doivent correspondre aux niveaux du facteur — factor(dose) d’abord, puis utilisez c("0.5", "1").
Une échelle logarithmique (ou un axe transformé) sur l’axe y change silencieusement les p-values. Utilisez coord_trans(y = "log10") — il transforme seulement l’affichage, si bien que stat_compare_means() teste toujours les données d’origine. scale_y_continuous(trans = "log10") transforme les données avant que la couche statistique ne les voie, ce qui change le test. Optez pour coord_trans() quand vous voulez que la comparaison soit exécutée sur l’échelle brute.
Questions fréquentes
NoteComment ajouter une p-value à un ggplot en R ?
Utilisez ggpubr : ajoutez stat_compare_means() à n’importe quel graphique. Par exemple, ggboxplot(ToothGrowth, x = "dose", y = "len") + stat_compare_means() exécute le test et affiche la p-value en une seule couche — aucun calcul manuel. Ajoutez comparisons = list(c("0.5", "1")) pour des barres de comparaison par paires entre des groupes précis.
NoteQuel test statistique stat_compare_means() utilise-t-il par défaut ?
Pour deux groupes, il applique par défaut le test non paramétrique de Wilcoxon ; indiquez method = "t.test" pour un t-test paramétrique. Pour plus de deux groupes, il applique par défaut Kruskal-Wallis ; indiquez method = "anova" pour une ANOVA à un facteur paramétrique. Les barres par paires (comparisons =) et l’étiquette globale peuvent utiliser des méthodes différentes.
NoteQuelle est la différence entre stat_compare_means() et stat_pvalue_manual() ?
stat_compare_means() calcule le test et dessine l’étiquette en une seule étape — rapide pour les comparaisons standards. stat_pvalue_manual() affiche des p-values que vous avez calculées ailleurs (par exemple avec rstatixt_test() + adjust_pvalue()), ce qu’il faut pour des p-values ajustées, des dispositions groupées ou en facettes, ou tout test personnalisé. Le flux de travail rstatix est traité dans la leçon suivante, P-values issues de tests statistiques.
NoteComment masquer les p-values non significatives (ns) ?
Ajoutez hide.ns = TRUE à stat_compare_means() — cela retire les étiquettes ns pour n’annoter que les comparaisons significatives. Pour afficher des étoiles plutôt que des nombres, ajoutez label = "p.signif".
NotePeut-on ajouter des p-values aux diagrammes en barres et en courbes, pas seulement aux boîtes à moustaches ?
Oui. stat_compare_means() est indépendant du type de graphique — il fonctionne sur ggbarplot() et ggline() (utilisez add = "mean_se") exactement comme sur ggboxplot(). Voir la section Ajouter des p-values aux diagrammes en barres et en courbes ci-dessus.
Testez vos connaissances
ImportantExercice : afficher les étoiles de signification par rapport à un groupe de référence
Complétez le code pour que chaque dose soit comparée à la dose de référence "0.5" à l’aide d’un t-test, étiquetée avec des symboles de signification (pas la p-value brute).
library(ggpubr)
df <- ToothGrowth
df$dose <- factor(df$dose)
ggboxplot(df, x = "dose", y = "len", color = "dose", palette = "jco") +
stat_compare_means(label = "p.signif", method = "t.test", ref.group = "0.5")
library(ggpubr)df <- ToothGrowthdf$dose <-factor(df$dose)ggboxplot(df, x ="dose", y ="len", color ="dose", palette ="jco") +stat_compare_means(label ="p.signif", method ="t.test", ref.group ="0.5")
Conclusion
Vous avez ajouté des p-values aux ggplots de la façon canonique : compare_means() pour les chiffres et stat_compare_means() pour l’annotation — sur deux groupes (Wilcoxon et t-test), échantillons appariés, plus de deux groupes (ANOVA/Kruskal-Wallis global), crochets par paires, un groupe de référence et la moyenne générale (.all.), puis personnalisé les symboles de signification avec symnum.args. Cette seule couche transforme n’importe quelle boîte à moustaches ou graphique en violon en une figure prête à publier.
Pour un contrôle total sur les p-values qui apparaissent — p-values ajustées sur les crochets, graphiques en facettes, axes transformés — pré-calculez le test avec rstatix et dessinez-le avec stat_pvalue_manual() : c’est la prochaine leçon de cette série. Pour choisir et interpréter les tests eux-mêmes (t-test, ANOVA, hypothèses, taille d’effet), voir la prochaine série statistiques — ggpubr est le pont entre les deux.
Cette leçon est reproductible : les figures sont exécutées au moment de la construction (si elles s’affichent, le code fonctionne), et le bac à sable et le quiz se réexécutent en direct dans votre navigateur. The runtime is the judge.
@online{2026,
author = {},
title = {Add P-values to ggplots in R (ggpubr)},
date = {2026-06-22},
url = {https://www.datanovia.com/learn/data-visualization/ggpubr/add-p-values},
langid = {fr}
}