In ggplot2, what do the end of the boxplot lines represent?
Asked Answered
W

4

45

I can't find a description of what the end points of the lines of a boxplot represent.

For example, here are point values above and below where the lines end. enter image description here

(I realize that the top and bottom of the box are 25th and 75th percentile, and the centerline is the 50th). I assume, as there are points above and below the lines that they do not represent the max/min values.

Woodcraft answered 9/2, 2011 at 15:32 Comment(0)
U
75

The "dots" at the end of the boxplot represent outliers. There are a number of different rules for determining if a point is an outlier, but the method that R and ggplot use is the "1.5 rule". If a data point is:

  • less than Q1 - 1.5*IQR
  • greater than Q3 + 1.5*IQR

then that point is classed as an "outlier". The whiskers are defined as:

upper whisker = min(max(x), Q_3 + 1.5 * IQR)

lower whisker = max(min(x), Q_1 – 1.5 * IQR)

where IQR = Q_3 – Q_1, the box length. So the upper whisker is located at the smaller of the maximum x value and Q_3 + 1.5 IQR, whereas the lower whisker is located at the larger of the smallest x value and Q_1 – 1.5 IQR.

Additional information

  • See the wikipedia boxplot page for alternative outlier rules.
  • There are actually a variety of ways of calculating quantiles. Have a look at `?quantile for the description of the nine different methods.

Example

Consider the following example

> set.seed(1)
> x = rlnorm(20, 1/2)#skewed data
> par(mfrow=c(1,3))
> boxplot(x, range=1.7, main="range=1.7")
> boxplot(x, range=1.5, main="range=1.5")#default
> boxplot(x, range=0, main="range=0")#The same as range="Very big number"

This gives the following plot: enter image description here

As we decrease range from 1.7 to 1.5 we reduce the length of the whisker. However, range=0 is a special case - it's equivalent to "range=infinity"

Unnatural answered 9/2, 2011 at 15:38 Comment(3)
See the help pages for ?boxplot or ?boxplot.stats . ggplot uses the standard R functions for these calculations.Unnatural
In ggplot2, the upper whisker is computed as max(x[x < Q3 + 1.5 * IQR]), similarly with min and > for the lower whisker.Stupid
@Stupid is correct. I've added an answer with an example that shows where the whisker value is not the same as the calculated value using Q1 - 1.5*IQRBionomics
A
15

I think ggplot using the standard defaults, the same as boxplot: "the whiskers extend to the most extreme data point which is no more than [1.5] times the length of the box away from the box"

See: boxplot.stats

Almshouse answered 9/2, 2011 at 15:41 Comment(6)
I call this the Tukey boxplot to save confusion with the myriad other types of (worse) boxplots people have since created.Desiderata
As far as i understand ?boxplot.stats, the criterium is +/-1.58 * IQR/sqrt(n) and not [1.5] times the length of the box. Am I misunderstanding something?Peak
@Henrik: you're confusing the whiskers with the notches.Almshouse
Thanks, for the clarification. but for what does the notch stands.Peak
McGill's paper is very readable: lis.epfl.ch/~markus/References/McGill78.pdfAlmshouse
The link to McGill's paper no longer works. I couldn't find a new (free) link. The paper can be downloaded from jstor.org/stable/2683468?seq=1#page_scan_tab_contents , but it costs $14 (or you need to have institutional access).Ns
A
2

P1IMSA Tutorial 8 - Understanding Box and Whisker Plots video offers a visual step-by-step explanation of (Tukey) box and whisker plots.

At 4m 23s I explain the meaning of the whisker ends and its relationship to the 1.5*IQR.

Although the chart shown in the video was rendered using D3.js rather than R, its explanations jibe with the R implementations of boxplots mentioned.

Attractant answered 10/4, 2015 at 20:25 Comment(0)
B
0

As highlighted by @TemplateRex in a comment, ggplot doesn't draw the whiskers at the upper/lower quartile plus/minus 1.5 times the IQR. It actually draws them at max(x[x < Q3 + 1.5 * IQR]) and min(x[x > Q1 + 1.5 * IQR]). For example, here is a plot drawn using geom_boxplot where I've added a dashed line at the value Q1 - 1.5*IQR:

enter image description here

Q1 = 52

Q3 = 65

Q1 - 1.5 * IQR = 52 - 13*1.5 = 32.5 (dashed line)

Lower whisker = min(x[x > Q1 + 1.5 * IQR]) = 35 (where x is the data used to create the boxplot, outlier is at x = 27).

MWE Note this isn't the exact code I used to produce the image above but it gets the point over.

library("mosaic") # For favstats()

df <-  c(54, 41, 55, 66, 71, 50, 65, 54, 72, 46, 36, 64, 49, 64, 73, 
         52, 53, 66, 49, 64, 44, 56, 49, 54, 61, 55, 52, 64, 60, 54, 59, 
         67, 58, 51, 63, 55, 67, 68, 54, 53, 58, 26, 53, 56, 61, 51, 51, 
         50, 51, 68, 60, 67, 66, 51, 60, 52, 79, 62, 55, 74, 62, 59, 35, 
         67, 58, 74, 48, 53, 40, 62, 67, 57, 68, 56, 75, 55, 41, 50, 73, 
         57, 62, 61, 48, 60, 64, 53, 53, 66, 58, 51, 68, 69, 69, 58, 54, 
         57, 65, 78, 70, 52, 59, 52, 65, 70, 53, 57, 72, 47, 50, 70, 41, 
         64, 59, 58, 65, 57, 60, 70, 46, 40, 76, 60, 64, 51, 38, 67, 57, 
         64, 51)
df <- as.data.frame(df)


Q1 <- favstats(df)$Q1
Q3 <- favstats(df)$Q3

IQR <- Q3 - Q1

lowerlim <- Q1 - 1.5*IQR
upperlim <- Q3 + 1.5* IQR

boxplot_Tukey_lower <- min(df[df > lowerlim])
boxplot_Tukey_upper <- max(df[df < upperlim])



ggplot(df, aes(x = "", y = df)) +
  stat_boxplot(geom ='errorbar', width = 0.5) +
  geom_boxplot() + 
  geom_hline(yintercept = lowerlim, linetype = "dashed") +
  geom_hline(yintercept = upperlim, linetype = "dashed")

Bionomics answered 18/1, 2021 at 11:59 Comment(5)
thanks for your contribution. It would generally be helpful to have the exact code to your plot. (No need for the theme calls and lab titles that you have, just use ggplot() + geom_boxplot(). Ideally, a fully reproducible example would be great, for example on an inbuilt data set. Maybe try the "reprex" package.Jos
where is favstats from? I thought maybe the mosaic package, so I added the call, but this does not work when I try to reproduce this.Jos
It is in mosaic. Not sure why it didn't work for you.Bionomics
In a fresh R session (using reprex package): Q1 <- favstats(df)$Q1 #> Warning in fav_stats(x, ..., na.rm = na.rm): Auto-converting data.frame to #> numeric. #> Error in fav_stats(x, ..., na.rm = na.rm): 'list' object cannot be coerced to type 'double'Jos
in other words your code does not work ;)Jos

© 2022 - 2024 — McMap. All rights reserved.