LC-datascientist
LC-datascientist

Reputation: 2106

Center alignment of text over each bar on faceted, dodged bar plot using ggplot2 in R

I would like my text to be center-aligned above each bar in a faceted dodged bar plot.

# setup
library(ggplot2); library(tidyverse)
data("iris")

# graph
iris %>% group_by(Species) %>% 
mutate(Petal_Group = ifelse(Petal.Width < median(Petal.Width), "Short", "Long")) %>% 
mutate(Sepal_Group = ifelse(Sepal.Width < median(Sepal.Width), "Short", "Long")) %>% 
group_by(Petal_Group, Sepal_Group, Species) %>% 
summarise(mean.Sepal.Length = mean(Sepal.Length)) %>% 
mutate(asterisks = "***") %>% 
ggplot(aes(x = Petal_Group, y = mean.Sepal.Length)) + 
    geom_col(aes(fill = Species), position = "dodge") + 
    geom_text(aes(label=asterisks, group = Species), position = position_dodge(width = 1)) + 
    facet_grid(~Sepal_Group, labeller = label_parsed) + 
    theme(legend.position = "bottom", panel.background = element_blank(), panel.border = element_rect(colour = "black", fill = NA, size = 0.2), strip.background = element_blank())

Example of a faceted dodged bar plot that needs text center-alignment

In the example (sorry if it's overcomplicated but I'm working with something like this), the triple asterisks ("***") are not centered over each bar. I.e., the asterisks over red bars appear on the left and the asterisks over the blue bars appear on the right.

I tried adjusting the hjust in geom_text but I couldn't get it right. (And isn't there a more universal way of center alignment, something like position = "center"?)

Upvotes: 3

Views: 2395

Answers (1)

Marius
Marius

Reputation: 60230

The default dodge width for geom_bar and geom_col is 0.9 I think, not 1, so your text is being dodged by a different amount to your bars. If you create a dodge object that you can apply to both the columns and the text they will align nicely:

# graph
dodger = position_dodge(width = 0.9)
iris %>% group_by(Species) %>% 
    mutate(Petal_Group = ifelse(Petal.Width < median(Petal.Width), "Short", "Long")) %>% 
    mutate(Sepal_Group = ifelse(Sepal.Width < median(Sepal.Width), "Short", "Long")) %>% 
    group_by(Petal_Group, Sepal_Group, Species) %>% 
    summarise(mean.Sepal.Length = mean(Sepal.Length)) %>% 
    mutate(asterisks = "***") %>% 
    ggplot(aes(x = Petal_Group, y = mean.Sepal.Length)) + 
    geom_col(aes(fill = Species), position = dodger) + 
    geom_text(aes(label=asterisks, group = Species), position = dodger) + 
    facet_grid(~Sepal_Group, labeller = label_parsed) + 
    theme(legend.position = "bottom", panel.background = element_blank(), 
          panel.border = element_rect(colour = "black", fill = NA, 
          size = 0.2), strip.background = element_blank())

Result:

enter image description here

Upvotes: 6

Related Questions