6

I am trying to add significance levels to my boxplots in the form of asterisks using ggplot2 and the ggpubr package, but I have many comparisons and I only want to show the significant ones.

I try to use the option hide.ns=TRUE in stat_compare_means, but it clearly does not work, it might be a bug in the ggpubr package.

Besides, you see that I leave out group "PGMC4" from the pairwise wilcox.test comparisons; how can I leave this group out also for the kruskal.test?

The last question I have is how the significance level works? As in * is significant below 0.05, ** below 0.025, *** below 0.01? what is the convention ggpubr uses? Is it showing p-values or adjusted p-values? If the latter, what's the adjusting method? BH?

Please check my MWE below and this link and this other one for reference

##############################
##MWE
set.seed(5)
#test df
mydf <- data.frame(ID=paste(sample(LETTERS, 163, replace=TRUE), sample(1:1000, 163, replace=FALSE), sep=''),
                   Group=c(rep('C',10),rep('FH',10),rep('I',19),rep('IF',42),rep('NA',14),rep('NF',42),rep('NI',15),rep('NS',10),rep('PGMC4',1)),
                   Value=rnorm(n=163))
#I don't want to compare PGMC4 cause I have only onw sample
groups <- as.character(unique(mydf$Group[which(mydf$Group!="PGMC4")]))
#function to make combinations of groups without repeating pairs, and avoiding self-combinations
expand.grid.unique <- function(x, y, include.equals=FALSE){
    x <- unique(x)
    y <- unique(y)
    g <- function(i){
        z <- setdiff(y, x[seq_len(i-include.equals)])
        if(length(z)) cbind(x[i], z, deparse.level=0)
    }
    do.call(rbind, lapply(seq_along(x), g))
}
#all pairs I want to compare
combs <- as.data.frame(expand.grid.unique(groups, groups), stringsAsFactors=FALSE)
head(combs)
my.comps <- as.data.frame(t(combs), stringsAsFactors=FALSE)
colnames(my.comps) <- NULL
rownames(my.comps) <- NULL
#pairs I want to compare in list format for stat_compare_means
my.comps <- as.list(my.comps)
head(my.comps)
pdf(file="test.pdf", height=20, width=25)
print(#or ggsave()
  ggplot(mydf, aes(x=Group, y=Value, fill=Group)) + geom_boxplot() +
    stat_summary(fun.y=mean, geom="point", shape=5, size=4) +
    scale_fill_manual(values=myPal) +
    ggtitle("TEST TITLE") +
    theme(plot.title = element_text(size=30),
      axis.text=element_text(size=12),
      axis.text.x = element_text(angle=45, hjust=1),
      axis.ticks = element_blank(),
      axis.title=element_text(size=20,face="bold"),
      legend.text=element_text(size=16)) +
  stat_compare_means(comparisons=my.comps, method="wilcox.test", label="p.signif", size=14) + #WHY DOES hide.ns=TRUE NOT WORK??? WHY DOES size=14 NOT WORK???
  stat_compare_means(method="kruskal.test", size=14) #GLOBAL COMPARISON ACROSS GROUPS (HOW TO LEAVE PGMC4 OUT OF THIS??)
)
dev.off()
##############################

The MWE will produce the following boxplots:

test

The questions would be:

1- How to make hide.ns=TRUE work?

2- How to increase the size of the *?

3- How to exclude a group from the kruskal.test comparison?

4- What is the * convention used by ggpubr, and are the p-values shown adjusted or not?

Many thanks!!

EDIT

Besides, when doing

stat_compare_means(comparisons=my.comps, method="wilcox.test", p.adjust.method="BH")

I do not obtain the same p-values as when doing

wilcox.test(Value ~ Group, data=mydf.sub)$p.value

where mydf.sub is a subset() of mydf for a given comparison of 2 groups.

What is ggpubr doing here? How does it calculate the p.values?

EDIT 2

Please help, the solution does not have to be with ggpubr (but it has to be with ggplot2), I just need to be able to hide the NS and make the size of the asterisks bigger, as well as a p-value calculation identical to wilcox.test() + p.adjust(method"BH").

Thanks!

Roman
  • 17,008
  • 3
  • 36
  • 49
DaniCee
  • 2,397
  • 6
  • 36
  • 59
  • 1. yes indeed. seems to be a bug; 2. no idea; 3. use `stat_compare_means(data=mydf[ mydf$Group != "PGMC4", ],aes(x=Group, y=Value, fill=Group), size=5)` 4. compare the results to `pairwise.wilcox.test(mydf$Value, mydf$Group, p.adjust.method = "none")` – Roman Aug 03 '17 at 10:09
  • How should I notify about this bug? and do you know if there is any chance that it can get solved soon? many thanks! – DaniCee Aug 03 '17 at 10:48
  • plot all the stuff by yourself, e.g. use `library(ggsignif);geom_signif()` and annotation. See here the last answer: https://stackoverflow.com/questions/17084566/put-stars-on-ggplot-barplots-and-boxplots-to-indicate-the-level-of-significanc/27073333 – Roman Aug 03 '17 at 11:02
  • could you develop that into an answer? Using ggsignif's geom_signif() I don't seem to figure out how to remove the NS comparisons, how to change the size of the **, and how to place the brackets so they don't overlap (like with ggpubr)... So I'm at the same point – DaniCee Aug 03 '17 at 11:29
  • Please anybody can shed some light here? Many thanks! – DaniCee Aug 06 '17 at 06:55
  • "4- What is the * convention used by ggpubr": People often like to interpret a 'level' of significance based on the order of magnitude of the p-value, e.g. <0.05 = *, <0.001 = **, <0.0001 ***. This is a complete fallacy. A p value is significant if lower than the alpha value (usually 0.05), and not significant otherwise. All this 'level of significance' is nonsense. (NHST is a shamanism anyway, but that's a different discussion) – Scransom Aug 07 '17 at 01:45
  • I think the same way, a comparison is not "more significant" than other if both are significant at the same alpha cutoff... but how does ggpubr even calculate the p-values? It doesn't return the same results as when applying wilcox.test(), and p.adjust() alone... – DaniCee Aug 07 '17 at 01:52
  • I will just be content if someone could find a way to remove NS and to increase the * size... Thanks! – DaniCee Aug 07 '17 at 04:57

1 Answers1

11

Edit: Since I discovered the rstatix package I would do:

set.seed(123)
#test df
mydf <- data.frame(ID=paste(sample(LETTERS, 163, replace=TRUE), sample(1:1000, 163, replace=FALSE), sep=''),
                   Group=c(rep('C',10),rep('FH',10),rep('I',19),rep('IF',42),rep('NA',14),rep('NF',42),rep('NI',15),rep('NS',10),rep('PGMC4',1)),
                   Value=c(runif(n=100), runif(63,max= 0.5)))


library(tidyverse)

stat_pvalue <- mydf %>% 
 rstatix::wilcox_test(Value ~ Group) %>%
 filter(p < 0.05) %>% 
 rstatix::add_significance("p") %>% 
 rstatix::add_y_position() %>% 
 mutate(y.position = seq(min(y.position), max(y.position),length.out = n())

ggplot(mydf, aes(x=Group, y=Value)) + geom_boxplot() +
  ggpubr::stat_pvalue_manual(stat_pvalue, label = "p.signif") +
  theme_bw(base_size = 16)

enter image description here

Old Answer:

You can try following. The idea is that you calculate the stats by your own using pairwise.wilcox.test. Then you use the ggsignif function geom_signif to add the precalculated pvalues. With y_position you can place the brackets so they don't overlap.

library(tidyverse)
library(ggsignif)
library(broom)
# your list of combinations you want to compare
CN <- combn(levels(mydf$Group)[-9], 2, simplify = FALSE)
# the pvalues. I use broom and tidy to get a nice formatted dataframe. Note, I turned off the adjustment of the pvalues. 
pv <- tidy(with(mydf[ mydf$Group != "PGMC4", ], pairwise.wilcox.test(Value, Group, p.adjust.method = "none")))
#  data preparation 
CN2 <- do.call(rbind.data.frame, CN)
colnames(CN2) <- colnames(pv)[-3]
# subset the pvalues, by merging the CN list
pv_final <- merge(CN2, pv, by.x = c("group2", "group1"), by.y = c("group1", "group2"))
# fix ordering
pv_final <- pv_final[order(pv_final$group1), ] 
# set signif level
pv_final$map_signif <- ifelse(pv_final$p.value > 0.05, "", ifelse(pv_final$p.value > 0.01,"*", "**"))  

# the plot
ggplot(mydf, aes(x=Group, y=Value, fill=Group)) + geom_boxplot() +
  stat_compare_means(data=mydf[ mydf$Group != "PGMC4", ], aes(x=Group, y=Value, fill=Group), size=5) + 
  ylim(-4,30)+
  geom_signif(comparisons=CN,
              y_position = 3:30, annotation= pv_final$map_signif) + 
  theme_bw(base_size = 16)

enter image description here

The arguments vjust, textsize, and size are not properly working. Seems to be a bug in the latest version ggsignif_0.3.0.


Edit: When you want to show only the significant comparisons, you can easily subset the dataset CN. Since I updated to ggsignif_0.4.0 and R version 3.4.1, vjust and textsize are working now as expected. Instead of y_position you can try step_increase.

# subset 
gr <- pv_final$p.value <= 0.05
CN[gr]

ggplot(mydf, aes(x=Group, y=Value, fill=Group)) + 
  geom_boxplot() +
  stat_compare_means(data=mydf[ mydf$Group != "PGMC4", ], aes(x=Group, y=Value, fill=Group), size=5) + 
  geom_signif(comparisons=CN[gr], textsize = 12, vjust = 0.7, 
             step_increase=0.12, annotation= pv_final$map_signif[gr]) + 
  theme_bw(base_size = 16)

You can use ggpubr as well. Add:

stat_compare_means(comparisons=CN[gr], method="wilcox.test", label="p.signif", color="red")

enter image description here

Roman
  • 17,008
  • 3
  • 36
  • 49
  • Hi Jimbou, thanks for the suggestion, but my aim with this is not just remove the actual letters "NS", but also all those useless brackets that make the plot extremely busy and squash down the boxplots... – DaniCee Aug 07 '17 at 08:10
  • I upgraded to ggsignif_0.4.0 but I still cannot change the size of the *** – DaniCee Aug 07 '17 at 09:13
  • "textsize" and "size" do not work, and "cex" change the thickness of the brackets... – DaniCee Aug 07 '17 at 09:17
  • I am using geom_signif with ggsignif_0.4.0, not ggpubr... cannot change the * size... – DaniCee Aug 07 '17 at 09:23
  • Oh I got it now! it seems loading ggpubr screws it up even if you dont use it in the actual plot... let me digest all this and accept the answer – DaniCee Aug 07 '17 at 09:26
  • But that leaves me the problem of the Kruskal-Wallis test... can we do it without stat_compare_means? let's get rid of ggpubr altogether – DaniCee Aug 07 '17 at 09:28
  • @DaniCee so far I see no solution for this in `ggsignif`. You can try `geom_text(x=2, y=6, label=paste("Kruskal-Wallis, p=", round(with(mydf[ mydf$Group != "PGMC4", ], kruskal.test(Value~ Group)$p.value),2)))` – Roman Aug 07 '17 at 09:57
  • could you please have a look at this question I just posted (https://stackoverflow.com/questions/45552715/r-ggplot2-perform-pairwise-tests-per-pair-in-a-facet-and-show-the-p-values-wit)? I feel it must be something really similar but I cannot get around it... Many many thanks! – DaniCee Aug 07 '17 at 17:42
  • Hi @Jimbou, I am trying to do something similar, but this time I combine multiple groups to compare, and multiple facets as well... If you could have a look, I'd appreciate! Thanks https://stackoverflow.com/questions/46446392/r-ggplot2-boxplots-with-significance-level-more-than-2-groups-kruskal-test-an – DaniCee Sep 27 '17 at 11:12