# Show significance on boxplots

**URL:** <https://discourse.julialang.org/t/show-significance-on-boxplots/77365>\
**Category:** Visualization\
**Tags:** statsplots\
**Created:** [March 3, 2022, 3:54pm UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365 "2022-03-03T15:54:17Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![jewh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jewh/32/28586_2.png) [@jewh](https://discourse.julialang.org/u/jewh)\
**Post date:** [March 3, 2022, 3:54pm UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/1 "2022-03-03T15:54:17Z")

</div>

I want to annotate the statistical significance of the difference between a pair of boxplots on my figure, as one of `'n.s.', '*', ' **', '***'`. An example image of what I want is below, the best analogue I can find of what I want is ggsignif in R: [https://github.com/const-ae/ggsignif](https://github.com/const-ae/ggsignif).

![ztl3U](https://global.discourse-cdn.com/julialang/original/3X/4/2/4224c621cc75a406b757953c1dda10f7a49b7740.png)

Does a functionality like this exist in `StatsPlots.boxplot`?

If no functionality exists, I can easily get one of `'n.s.', '*', ' **', '***'` using the p-value for a given hypothesis test in HypothesisTests. However I’m struggling with annotating the plot correctly - I could use `annotate!(x, y, text("*", :centre, 8))`, but I’m not sure how I’d know which x, y to pick to place the text correctly above the box? Anyone have any suggestions?

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [March 3, 2022, 4:03pm UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/2 "2022-03-03T16:03:10Z")

</div>

Wouldn’t a color with legend be more intuitive for people who never came across this “symbol jargon”? I use boxplots for a while and never came across \*\*\* ns, etc on papers.

---

<div class="post-metadata">

**Author:** ![jewh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jewh/32/28586_2.png) [@jewh](https://discourse.julialang.org/u/jewh)\
**Post date:** [March 3, 2022, 4:05pm UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/3 "2022-03-03T16:05:15Z")

</div>

Yeah colour’s a really nice idea, I’ll look at that. Unfortunately this notation is the standard in my field (developmental biology), so I can’t really dismiss it.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [March 4, 2022, 7:32am UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/4 "2022-03-04T07:32:38Z")

</div>

You can annotate StatsPlots boxplot as follows:

```julia
using StatsPlots, DataFrames
theme(:ggplot2)

# INPUT DATA:
X = ["setosa", "versicolor","virginica"]
Y = [rand(-3:3, 10) for _ in 1:length(X)]
X2 = [fill(x,length(y)) for (x,y) in zip(X,Y)]
df = DataFrame(X = X2, Y = Y)

# PLOT DATA:
p = @df df boxplot(:X, :Y, c=:black, fillcolor=:white, legend=false)

ymin, ymax = ylims(p)
dy = (ymax - ymin)/25
ymax += dy
xt = xticks(p[1])[1]
plot!(xt[2:3], [ymax,ymax], c=:black, ylims = (ymin, ymax + dy))
annotate!(mean(xt[2:3]), ymax + dy/2, text("***", 10))

```

the result is:  
 ![StatsPlot_Boxplot_annotate_pair](https://global.discourse-cdn.com/julialang/original/3X/e/9/e944f0bf29eb738ed8ca64060fa768dfa19ad896.png)

---

<div class="post-metadata">

**Author:** ![jewh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jewh/32/28586_2.png) [@jewh](https://discourse.julialang.org/u/jewh)\
**Post date:** [March 4, 2022, 9:19am UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/5 "2022-03-04T09:19:23Z")

</div>

Thanks, and how could I get a second bar like this one in red?

![ztl3U](https://global.discourse-cdn.com/julialang/original/3X/a/b/ab58ba7b72ea631adac966c97f2292438ba1d6aa.png)

Your solution’s great for annotating a comparison with the highest box, but I’d like to be able to annotate these bars at a consistent height above each box. Can I access the y values for the whiskers in each box?

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [March 4, 2022, 10:53am UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/6 "2022-03-04T10:53:24Z")

</div>

Would something like this be to your liking?  
 ![StatsPlot_Boxplot_annotate_pair](https://global.discourse-cdn.com/julialang/original/3X/1/5/15690531662b26509cb26020ea07ab51dab0d6f1.png)

---

<div class="post-metadata">

**Author:** ![jewh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jewh/32/28586_2.png) [@jewh](https://discourse.julialang.org/u/jewh)\
**Post date:** [March 4, 2022, 11:06am UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/7 "2022-03-04T11:06:20Z")

</div>

Not really, if boxes `virginica` and `setosa` are adjacent, I’d like the line the same height above the tallest whisker of the two, as the height above the whisker for versicolor.

Basically, for any pair of boxes `b1, b2`, I want the line to be at height `max{whiskers(b1), whiskers(b2)} + dy`, for some `dy` constant across the plot.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [March 4, 2022, 11:09am UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/8 "2022-03-04T11:09:35Z")

</div>

Take my last plot and annotate it by hand, please.

---

<div class="post-metadata">

**Author:** ![jewh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jewh/32/28586_2.png) [@jewh](https://discourse.julialang.org/u/jewh)\
**Post date:** [March 4, 2022, 11:15am UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/9 "2022-03-04T11:15:52Z")

</div>

![15690531662b26509cb26020ea07ab51dab0d6f1](https://global.discourse-cdn.com/julialang/original/3X/5/f/5fe5c8a9dace59b025d04c7dc12ee205a11d8926.png)

Here I’m assuming that `setosa` has an upper whisker \>= `virginica`. In either case, the line is always `dy` units above the tallest whisker.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [March 4, 2022, 11:25am UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/10 "2022-03-04T11:25:25Z")

</div>

OK, now it is clear. So you do not care about the outlier points displayed beyond the whiskers on the boxplot.

---

<div class="post-metadata">

**Author:** ![jewh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jewh/32/28586_2.png) [@jewh](https://discourse.julialang.org/u/jewh)\
**Post date:** [March 4, 2022, 11:26am UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/11 "2022-03-04T11:26:41Z")

</div>

I don’t, no

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [March 4, 2022, 12:08pm UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/12 "2022-03-04T12:08:30Z")

</div>

Annotating as you suggest can lead to situations like the one shown below:  
 ![StatsPlot_Boxplot_annotate_pair](https://global.discourse-cdn.com/julialang/original/3X/6/9/695f7e4eff55aff33b9afdad147ea1aa665b73af.png)

If there is a web resource showing more examples it would be helpful.

---

<div class="post-metadata">

**Author:** ![joa-quim](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joa-quim/32/227_2.png) [@joa-quim](https://discourse.julialang.org/u/joa-quim)\
**Post date:** [March 4, 2022, 12:14pm UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/13 "2022-03-04T12:14:35Z")

</div>

This recent [FEX contribution](https://www.mathworks.com/matlabcentral/fileexchange/88733-boxplotpro) (Matlab) seems to cover many of those cases

---

<div class="post-metadata">

**Author:** ![jewh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jewh/32/28586_2.png) [@jewh](https://discourse.julialang.org/u/jewh)\
**Post date:** [March 4, 2022, 12:15pm UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/14 "2022-03-04T12:15:43Z")

</div>

In cases like this I’d re-order the x axis to prevent these things occurring. How did you alter your code to achieve this?

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [March 4, 2022, 12:27pm UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/15 "2022-03-04T12:27:32Z")

</div>

Joaquim, that is the Lamborghini of boxplots. Way beyond my skills and time.

The buit-in logic seems to annotate mostly at the top, never going across the data, which doesn’t seem to be sorted:

 ![Matlab_BoxplotPro](https://global.discourse-cdn.com/julialang/original/3X/e/1/e1d1a43dcfa817016fac6966f157ac01429e4fed.png)

---

<div class="post-metadata">

**Author:** ![jewh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jewh/32/28586_2.png) [@jewh](https://discourse.julialang.org/u/jewh)\
**Post date:** [March 4, 2022, 12:30pm UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/16 "2022-03-04T12:30:24Z")

</div>

I guess what I’m really asking for (to save you time) is if there’s a way to get the y values of the whiskers for each plot (excluding outliers)?

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [March 4, 2022, 12:33pm UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/17 "2022-03-04T12:33:01Z")

</div>

> [@jewh](#):
>
> if there’s a way to get the y values of the whiskers for each plot (excluding outliers)?

The answer is yes:

```julia
p = @df df boxplot(:X, :Y, c=:black, fillcolor=:white, legend=false)
xt = xticks(p[1])[1]
yminmax = [extrema(filter(!isnan, p[1][3(i-1)+1][:y])) for i in axes(xt,1)]

```

---

<div class="post-metadata">

**Author:** ![jewh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jewh/32/28586_2.png) [@jewh](https://discourse.julialang.org/u/jewh)\
**Post date:** [March 4, 2022, 12:54pm UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/18 "2022-03-04T12:54:27Z")

</div>

Wonderful, thank you.

---

<div class="post-metadata">

**Author:** ![mahmah](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mahmah/32/214326_2.png) [@mahmah](https://discourse.julialang.org/u/mahmah)\
**Post date:** [January 31, 2026, 10:32am UTC](https://discourse.julialang.org/t/show-significance-on-boxplots/77365/19 "2026-01-31T10:32:34Z")

</div>

I think having a package offering this functionality would be great. These are very common visualizations of ANOVAs and t-tests.
