Add P-values to ggplots in R (ggpubr)

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.
Obtenez le livre — R Graphics Essentials (PDF)

Introduction

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 <- ToothGrowth
df$dose <- factor(df$dose)

# the pairs of doses to compare
my_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 brackets
                     label.y = c(35, 40, 48)) +
  stat_compare_means(label.y = 56)                        # global p-value

A ggpubr box plot of tooth length by dose with pairwise comparison brackets between 0.5-1, 1-2 and 0.5-2, and a global Kruskal-Wallis p-value at the top.

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 formule value ~ group et renvoie une seule ligne soignée.

library(ggpubr)
compare_means(len ~ supp, data = ToothGrowth)
# A tibble: 1 × 8
  .y.   group1 group2      p p.adj p.format p.signif method  
  <chr> <chr>  <chr>   <dbl> <dbl> <chr>    <chr>    <chr>   
1 len   OJ     VC     0.0645 0.064 0.064    ns       Wilcoxon

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()

A ggpubr box plot of tooth length by supplement (OJ vs VC) with a Wilcoxon p-value annotated above the boxes.

Passez au t-test paramétrique en transmettant directement methodstat_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")

A ggpubr box plot of tooth length by supplement with a parametric t-test p-value annotated above the boxes.

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 (***)
  • aes(label = after_stat(paste0("p = ", p.format))) — votre propre modèle

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)

A ggpubr box plot of tooth length by supplement showing only the significance symbol (ns) placed between the two boxes.

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)

A ggpubr box plot of tooth length by supplement using the label shortcut to show only the p-value, formatted without the method name.

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)

A ggpubr paired plot of tooth length by supplement, with gray lines connecting matched observations and a paired Wilcoxon p-value annotated above.

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()

A ggpubr box plot of tooth length across three doses with a global Kruskal-Wallis p-value annotated at the top.

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")

A ggpubr box plot of tooth length across three doses with a global one-way ANOVA p-value annotated at the top.

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 <- ToothGrowth
df$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 brackets
  stat_compare_means(label.y = 50)                      # global p-value

A ggpubr box plot of tooth length by dose with three pairwise comparison brackets (0.5 vs 1, 1 vs 2, 0.5 vs 2) and a global Kruskal-Wallis p-value at the top.

Si les crochets se chevauchent, fixez explicitement leurs hauteurs avec label.y (une valeur par comparaison) :

library(ggpubr)
df <- ToothGrowth
df$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,
                     label.y = c(29, 35, 40)) +
  stat_compare_means(label.y = 45)

The same pairwise box plot with the three comparison brackets manually spaced at y = 29, 35 and 40 and the global p-value at y = 45.

Comparer chaque groupe à une référence

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 <- ToothGrowth
df$dose <- factor(df$dose)

ggboxplot(df, x = "dose", y = "len",
          color = "dose", palette = "jco") +
  stat_compare_means(method = "anova", label.y = 45) +        # global p-value
  stat_compare_means(label = "p.signif", method = "t.test",
                     ref.group = "0.5")                        # each vs the reference 0.5

A ggpubr box plot of tooth length by dose with each dose compared to the reference 0.5 (significance stars) and a global ANOVA p-value at the top.

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 <- ToothGrowth
df$dose <- factor(df$dose)

ggboxplot(df, x = "dose", y = "len",
          color = "dose", palette = "jco") +
  geom_hline(yintercept = mean(df$len), linetype = 2) +       # the grand mean
  stat_compare_means(method = "anova", label.y = 45) +        # global p-value
  stat_compare_means(label = "p.signif", method = "t.test",
                     ref.group = ".all.")                      # each vs the grand mean

A ggpubr box plot of tooth length by dose with a dashed line at the grand mean and each dose compared to the base-mean using significance stars, plus a global ANOVA p-value.

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.

library(ggpubr)
df <- ToothGrowth
df$dose <- factor(df$dose)
my_comparisons <- list(c("0.5", "1"), c("1", "2"), c("0.5", "2"))

# custom cut-points -> symbols
symnum.args <- list(
  cutpoints = c(0, 0.0001, 0.001, 0.01, 0.05, 1),
  symbols   = c("****", "***", "**", "*", "ns")
)

ggboxplot(df, x = "dose", y = "len",
          color = "dose", palette = "jco") +
  stat_compare_means(comparisons = my_comparisons,
                     label = "p.signif",
                     symnum.args = symnum.args)

A ggpubr box plot of tooth length by dose with three pairwise brackets labelled using custom significance symbols defined by symnum.args.

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 moyennesggbarplot(..., add = "mean_se"), puis les mêmes p-values par paires + globale :

library(ggpubr)
df <- ToothGrowth
df$dose <- factor(df$dose)
my_comparisons <- list(c("0.5", "1"), c("1", "2"), c("0.5", "2"))

ggbarplot(df, x = "dose", y = "len", add = "mean_se",
          fill = "dose", palette = "jco") +
  stat_compare_means(comparisons = my_comparisons, label = "p.signif",
                     label.y = c(30, 34, 40)) +
  stat_compare_means(label.y = 46) +
  ylim(NA, 50)

A ggpubr bar plot of mean tooth length by dose with mean_se error bars, pairwise significance stars, and a global Kruskal-Wallis p-value.

Graphique en courbes des moyennesggline(..., add = "mean_se"), avec une comparaison globale entre les doses :

library(ggpubr)
df <- ToothGrowth
df$dose <- factor(df$dose)

ggline(df, x = "dose", y = "len", add = "mean_se", color = "#3a86d4") +
  stat_compare_means(label.y = 30)

A ggpubr line plot of mean tooth length across doses with mean_se error bars and a global p-value.

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

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.

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.

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 rstatix t_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.

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".

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

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).

# stat_compare_means() takes three arguments here:
#   label = "p.signif", method = "t.test", ref.group = "0.5"
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 <- 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")

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.

Leçons connexes

Vous préférez un livre ? R Graphics Essentials est disponible en PDF téléchargeable — toutes les leçons de cette série, hors ligne et à vous.

Obtenir le livre (PDF) →Les leçons restent gratuites en ligne.
Cette page vous a-t-elle été utile ?

Prouvez que vous savez le faire. Maîtrisez toute la série ggpubr — 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
Note

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.

Réutilisation

Citation

BibTeX
@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}
}
Veuillez citer ce travail comme suit :
“Add P-values to ggplots in R (ggpubr).” 2026. June 22. https://www.datanovia.com/learn/data-visualization/ggpubr/add-p-values.