0

I have the following reproducible code that gives me a boxplot with jittered points (nominal x axis with another grouping factor):

ggplot(mtcars,aes(as.factor(cyl),disp))+
 geom_jitter(aes(color=as.factor(am)),position=position_jitterdodge(dodge.width=0.88),cex=.8)+
 geom_boxplot(aes(fill=as.factor(am)),width=1,outlier.shape=NA,position=position_dodge(width=.88))+
 scale_fill_manual(values=c(NA,NA))

Boxplot Example

I would like to add whiskers to the boxplot, but the only way I know how is to use stat_boxplot, which puts an error bar straight through the IQR range of the boxplot, and it looks quite unattractive:

ggplot(mtcars,aes(as.factor(cyl),disp))+
  geom_jitter(aes(color=as.factor(am)),position=position_jitterdodge(dodge.width=0.88),cex=.8)+
  stat_boxplot(geom ='errorbar',position=position_dodge(width=.88),aes(fill=as.factor(am))) + 
  geom_boxplot(aes(fill=as.factor(am)),width=1,outlier.shape=NA,position=position_dodge(width=.88))+
  scale_fill_manual(values=c(NA,NA))

Second example

I have tried to do a work around by writing my own code for the upper and lower whiskers, and then using statsummary to put only the whisker lines I need, like this:

upper_whisker<-function(x) {
  work<-quantile(x,na.rm=T,names=F)
  obs<-max(x[x<=work[4]],na.rm=T)
  whisker<-obs+1.5*IQR(x,na.rm=T)
  return(whisker)
}

lower_whisker<-function(x) {
  work<-quantile(x,na.rm=T,names=F)
  obs<-min(x[x>=work[2]],na.rm=T)
  whisker<-obs-1.5*IQR(x,na.rm=T)
  return(whisker)
}
ggplot(mtcars,aes(as.factor(cyl),disp))+
  geom_jitter(aes(color=as.factor(am)),position=position_jitterdodge(dodge.width=0.88),cex=.8)+
  #stat_boxplot(geom ='errorbar',position=position_dodge(width=.88),aes(fill=as.factor(am))) + 
  stat_summary(aes(group=as.factor(am)),fun.y=upper_whisker,fun.ymin=upper_whisker,fun.ymax=upper_whisker,geom="errorbar",color="black",width=0.5,size=0.4,position=position_dodge(width=0.88))+
  stat_summary(aes(group=as.factor(am)),fun.y=lower_whisker,fun.ymin=lower_whisker,fun.ymax=lower_whisker,geom="errorbar",color="black",width=0.5,size=0.4,position=position_dodge(width=0.88))+
  geom_boxplot(aes(fill=as.factor(am)),width=1,outlier.shape=NA,position=position_dodge(width=.88))+
  scale_fill_manual(values=c(NA,NA))

Final Example

But as you can see the whiskers are not in the right place, so I must be doing something wrong with the formula (I found the formula here: https://www.r-bloggers.com/whisker-of-boxplot/)

If anyone could tell me how to do the formula correctly or if they have any better ideas about how to do whiskers the way I need them, I would much appreciate it.

1 Answer 1

1

In this line: obs<-min(x[x>=work[2]],na.rm=T), you take the minimum value of x, where x is above 1Q (which is just 1Q). This is not what you wanted to do.

Replace your whisker functions by:

EDIT 18/12/09 - use R boxplot to get coordinates

upper_whisker<-function(x) {
  box_stats <- boxplot(x)$stats[5]
  return(box_stats)
}

lower_whisker<-function(x) {
  box_stats <- boxplot(x)$stats[1]
  return(box_stats)
}
Sign up to request clarification or add additional context in comments.

4 Comments

I accepted your answer because it works on the mtcars data, but see my comment below
@Gerard Hard to say for sure without having data to test, but try to play around with how you apply your log transformation. Do you have correct results without it?
Without the log scale it's difficult to see anything at all, but long-story short, no it still doesn't work. I think the issue is that the boxplot does some fancy formula when there are outliers present. You can see in the 72 hours and the 2 week timepoints that it puts the whisker on the data point right before the outlier. I don't know how I could fix that in my formulas. Do you know a way of getting the necessary parameters from the boxplots perhaps? I don't know enough about ggplot functionality to do so, but that could be a good alternative to making my own formula
@Gerard I don't know how to get boxplot stats from ggplot object but you can do it easily with base R boxplot object. I edited my answer, try running on your data with this code. If this fails I'm afraid I have no idea what else can be wrong

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.