1

I am trying to label my violin plot in ggplot with mean_cl_boot and n values for each violin shape, and wondering if there is a way to adjust vjust differently for each violin shape, or if there is a way to get count values regularly up above the shapes. As you can see my violins have varying lengths, so setting vjust to -8 (for example) puts the labels all over the place relative to the shapes.

enter image description here

I've included my code for the below plot, as well as a reproducible example with iris, but I wanted to get the point across with my weird dataset because iris looks so clean. Sorry I simply haven't found the right search terms for my question but I imagine it is something simple.

# Now make a nicer plot of Known Behavioral Age Categories vs Display Rate 
ggplot(data_changedorderwithoutNAs, aes(x = KnownBehAgeCategories,y = Energetically.Expensive.Displays.Per.Hour)) +
  geom_violin(
    mapping = aes(
      x = KnownBehAgeCategories,
      y = Energetically.Expensive.Displays.Per.Hour, fill = KnownBehAgeCategories
    )
  )+
  theme_classic()+
  stat_summary(fun.data = "mean_cl_boot", geom = "pointrange")+
  stat_summary(fun.data = n_fun, geom = "text", vjust = -6)+
  labs(y="Display Rate", x="Known Behavioral Age")+
  scale_fill_brewer(palette="BuPu")

With the iris dataset:

ggplot(iris, aes(x = Species,y = Petal.Width)) +
  geom_violin(
    mapping = aes(
      x = Species,
      y = Petal.Width, fill = Species
    )
  )+
  theme_classic()+
  stat_summary(fun.data = "mean_cl_boot", geom = "pointrange")+
  stat_summary(fun.data = n_fun, geom = "text", vjust = -8)+
  labs(y="Species", x="Petal Width")+
  scale_fill_brewer(palette="BuPu")
zx8754
  • 52,746
  • 12
  • 114
  • 209
ksh530
  • 33
  • 4

2 Answers2

1

Set vjust to 0, and use n_fun updated version (from this post: Automatic n plotting with ggplot and stat_summary) with y value set to the max:

n_fun <- function(x){
  return(data.frame(y = max(x), label = paste0("n = ",length(x))))
} 

ggplot(iris, aes(x = Species,y = Petal.Width,fill = Species)) +
  geom_violin() +
  theme_classic() +
  stat_summary(fun.data = "mean_cl_boot", geom = "pointrange") +
  stat_summary(fun.data = n_fun, geom = "text", vjust = 0) +
  labs(y="Species", x="Petal Width")+
  scale_fill_brewer(palette="BuPu")

enter image description here

zx8754
  • 52,746
  • 12
  • 114
  • 209
  • Thanks so much! This looks a great deal better, but on my plot the text is grazing the top of the shapes still. Any ideas what to use for this? I've seen nudge_y just wondering if it applies here. – ksh530 Mar 15 '23 at 18:11
0

The following code ended up working for me, thanks to some amendments from the respondent yesterday. Sorry for the stupid names but I hope this helps someone.

# create function for readout values
n_fun <- function(x){
  return(data.frame(y = max(x), label = paste0("n = ",length(x))))
} 

# Now make a nicer plot of Known Behavioral Age Categories vs Display Rate 
ggplot(data_changedorderwithoutNAs, aes(x = KnownBehAgeCategories,y = Energetically.Expensive.Displays.Per.Hour)) +
  geom_violin(
    mapping = aes(
      x = KnownBehAgeCategories,
      y = Energetically.Expensive.Displays.Per.Hour, fill = KnownBehAgeCategories
    )
  )+
  theme_classic()+
  stat_summary(fun.data = "mean_cl_boot", geom = "pointrange")+
  stat_summary(fun.data = n_fun, geom = "text", vjust = -1)+
  labs(y="Display Rate", x="")+
  scale_fill_brewer(palette="BuPu")+
  scale_y_continuous(limits = c(0,10))
ksh530
  • 33
  • 4