How to align value labels with geom_text in ggplot

I have this data:

structure(list(label2plot = structure(c(1L, 2L, 1L, 2L, 1L, 2L, 
1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L
), levels = c("aaa", "bbb"), class = c("ordered", "factor")), 
    var_abs = c(717L, 569L, 860L, 752L, 713L, 575L, 918L, 724L, 
    946L, 764L, 951L, 764L, 784L, 691L, 672L, 610L, 833L, 671L, 
    773L, 620L, 532L, 293L), var_rel = c(0.557542768273717, 0.442457231726283, 
    0.533498759305211, 0.466501240694789, 0.553571428571429, 
    0.446428571428571, 0.559074299634592, 0.440925700365408, 
    0.553216374269006, 0.446783625730994, 0.554518950437318, 
    0.445481049562682, 0.531525423728814, 0.468474576271186, 
    0.52418096723869, 0.47581903276131, 0.553856382978723, 0.446143617021277, 
    0.554917444364681, 0.445082555635319, 0.644848484848485, 
    0.355151515151515), cohort = structure(c(11L, 11L, 10L, 10L, 
    9L, 9L, 8L, 8L, 7L, 7L, 6L, 6L, 5L, 5L, 4L, 4L, 3L, 3L, 2L, 
    2L, 1L, 1L), levels = c("2010", "2011", "2012", "2013", "2014", 
    "2015", "2016", "2017", "2018", "2019", "2020"), class = "factor")), row.names = c(NA, 
-22L), class = "data.frame")

titel <- "ccc"
subtitel <- " "
werte <- c("aaa", "bbb")
start_abs <- "2010"
ende_abs <- "2020"

I have created a plot that is as far as I wanted it to be:

ggplot() +
  geom_bar (
    data = df,
    aes(
      x = factor(label2plot, levels = werte),
      y = var_rel,
      group = cohort,
      fill = forcats::fct_other(cohort, ende_abs, other_level = start_abs)
    ),
    stat = "identity",
    position = position_dodge()
  ) +
  scale_y_continuous(labels = scales::percent, limits = c(0, 1)) +
  theme_classic() +
  theme(
    legend.position = "bottom",
    plot.title = element_text(hjust = 0.5,
                              size = 14,
                              face = "bold"),
    plot.subtitle = element_text(hjust = 0.5),
    plot.caption = element_text(hjust = 0.5),
  ) +
  geom_text(
    size = 3,
    position = position_dodge2(preserve = 'single', width = 0.9),
    hjust = 0.5,
    vjust = -1,
    color = "black",
    aes(
      x = df$label2plot,
      y = df$var_rel,
      label = ifelse(df$cohort == ende_abs, paste0(sprintf(
        "%.1f", df$var_rel * 100
      ), "%"), "")
    )
  ) +
  scale_fill_manual(
    values = c("#AFCDE4", "#389DC3"),
    limits = c(start_abs, ende_abs),
    labels = c(paste0(start_abs, " - ", semvorende_abs), ende_abs)
  ) +
  labs(
    title = str_wrap(titel, 45),
    x = "",
    y =  "",
    fill = "Cohort"
  )

enter image description here

Unfortunately, the value labels are displayed above the wrong column. They should be displayed above the dark blue columns and not on the far left.

I have already tried many things, but it did not work. Does anyone have any ideas?

>Solution :

The issue is the grouping, i.e. as with your bars use group=cohort in geom_text too. Also as a general rule don’t use df$.... Simply make your dataset global by moving it inside ggplot:

library(ggplot2)

ggplot(data = df) +
  geom_bar (
    aes(
      x = factor(label2plot, levels = werte),
      y = var_rel,
      group = cohort,
      fill = forcats::fct_other(cohort, ende_abs, other_level = start_abs)
    ),
    stat = "identity",
    position = position_dodge()
  ) +
  scale_y_continuous(labels = scales::percent, limits = c(0, 1)) +
  theme_classic() +
  theme(
    legend.position = "bottom",
    plot.title = element_text(hjust = 0.5,
                              size = 14,
                              face = "bold"),
    plot.subtitle = element_text(hjust = 0.5),
    plot.caption = element_text(hjust = 0.5),
  ) +
  geom_text(
    size = 3,
    position = position_dodge2(preserve = 'single', width = 0.9),
    hjust = 0.5,
    vjust = -1,
    color = "black",
    aes(
      x = label2plot,
      y = var_rel,
      label = ifelse(cohort == ende_abs, paste0(sprintf(
        "%.1f", var_rel * 100
      ), "%"), ""),
      group = cohort
    )
  ) +
  scale_fill_manual(
    values = c("#AFCDE4", "#389DC3"),
    limits = c(start_abs, ende_abs),
    #labels = c(paste0(start_abs, " - ", semvorende_abs), ende_abs)
  ) +
  labs(
    title = str_wrap(titel, 45),
    x = "",
    y =  "",
    fill = "Cohort"
  )

enter image description here

Leave a Reply