14

I'd like to draw a line through my rideplots for the mean. The built-in quantile arguments draw a line in the style I want, but at the median. How can I draw one at the mean, preferably without using geom_vline() or pluck at the ggplot build object but staying in the ggridges ecology?

library(tidyverse)
library(ggridges)

#adding a column for the mean of each Species of the iris dataframe
iris_meaned <- iris %>%
  group_by(Species) %>% 
  mutate(mean_petal_len = mean(Petal.Length)) %>% 
  ungroup()


iris_meaned %>% 
  ggplot() +
  geom_density_ridges(
    aes(x = Petal.Length, y = Species, fill = Species), 
    quantile_lines = T, quantiles = 2 #adding lines for the median
  ) +
  geom_text(
    aes(x = mean_petal_len, y = Species, label = round(mean_petal_len, 2)),
    size = 2, nudge_x = 0.03, nudge_y = 0.35
  ) +
  theme_classic() +
  theme(
    axis.title = element_blank(), 
    legend.position = "None"
  ) 

Example with median lines

Claus Wilke
  • 16,992
  • 7
  • 53
  • 104
Laserhedvig
  • 381
  • 2
  • 13

1 Answers1

13

You can provide an arbitrary function to the argument quantile_fun. The function has to take a numeric vector as the first argument, and the number of quantiles as the second. But it's fine to ignore the second argument. The mean() function satisfies these criteria, and thus quantile_fun = mean creates vertical lines at the mean.

Note that in your example, you're plotting the text labels over and over. I've fixed the code so it works appropriately.

library(tidyverse)
library(ggridges)

iris_meaned <- iris %>%
  group_by(Species) %>% 
  summarize(mean_petal_len = mean(Petal.Length))

ggplot(iris) +
  geom_density_ridges(
    aes(x = Petal.Length, y = Species, fill = Species), 
    quantile_lines = T, quantile_fun = mean)  + 
  geom_text(
    data = iris_meaned,
    aes(x = mean_petal_len, y = Species, label = round(mean_petal_len, 2)),
    size = 2, nudge_x = 0.03, nudge_y = 0.35
  ) +
  theme_classic() +
  theme(
     axis.title = element_blank(), 
     legend.position = "None"
  ) 
#> Picking joint bandwidth of 0.155

Created on 2020-05-23 by the reprex package (v0.3.0)

To provide a second example, let's draw lines at the mean as well as the mean +/- 1 standard deviation. We can do so by defining a function meansd() that returns a vector of these three values.

library(tidyverse)
library(ggridges)

meansd <- function(x, ...) {
  mean <- mean(x)
  sd <- sd(x)
  c(mean - sd, mean, mean + sd)
}

ggplot(iris) +
  geom_density_ridges(
    aes(x = Petal.Length, y = Species, fill = Species), 
    quantile_lines = T, quantile_fun = meansd)  + 
  theme_classic() +
  theme(
    axis.title = element_blank(), 
    legend.position = "None"
  ) 
#> Picking joint bandwidth of 0.155

Created on 2020-05-23 by the reprex package (v0.3.0)

Claus Wilke
  • 16,992
  • 7
  • 53
  • 104
  • is it possible to do this in any ways for weighted means with wtd.mean or a similar function? I keep getting errors when I try. – Tobias P. G. May 11 '21 at 14:07
  • 1
    For succinctness, I rather avoid computing `iris_meaned` and use `stat_summary()` instead. To this end, first map the aesthetics to `ggplot(iris, aes(x = Petal.Length, y = Species, fill = Species))`, then add `geom_density_ridges(quantile_lines = T, quantile_fun = mean)`, and finally `stat_summary(aes(label = round(..x.., 2)), fun = "mean", geom = "text", size = 2` . @clauswilke, is there a reason to favor `iris_meaned` nevertheless? – Emman Jul 07 '21 at 08:45
  • @Emman Is there some reference to the use of `..x..`? I cannot find it at any place. How should it be used? I ask you because trying the equivalent in my code to `label = round(Petal.Length, 2)` (inside `stat_summary` as you do) does not work. (and it works using `..x..` exactly as you) Thanks! – iago Nov 19 '21 at 23:44
  • 1
    @iago, `..x..` refers to what's mapped earlier in `aes(x = blah)`. Look up "internal/special variables in ggplot". E.g.,: [this](https://stackoverflow.com/a/20140431/6105259), [this](https://stackoverflow.com/a/35067032/6105259), [this](https://stackoverflow.com/a/14570974/6105259). I don't know a formal reference though. – Emman Nov 20 '21 at 08:05