Geom_text above grouped geom_bar when theres negative values present

38 Views Asked by At

Consider this data:

# A tibble: 15 x 3
   group variable value
   <int> <fct>    <int>
 1     1 1            0
 2     1 2            0
 3     1 3           -2
 4     2 1            1
 5     2 2           -2
 6     2 3            1
 7     3 1           -1
 8     3 2           -2
 9     3 3           -2
10     4 1            0
11     4 2           -1
12     4 3            2
13     5 1            0
14     5 2            1
15     5 3           -2

library(tidyverse)

df %>% 
  ggplot() + 
  aes(x = group ,weight = value) + 
  geom_bar(aes(y = after_stat(proportions(count)), fill = variable), 
           stat = "count") + 
  coord_flip() +
  geom_hline(yintercept = 0) + 
  geom_text(aes(y = after_stat(proportions(count)),
                label = str_c(percent(after_stat(proportions(count))), 
                              " | ", after_stat(count))), 
            stat = "count")

The code yields the plot with the text at y = group proportion of the whole dataset. What I would like is the text to be above the bars, i.e above the positive values. How can I achieve this with geom_bar()?

enter image description here

Dummy data:

structure(list(group = c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 
4L, 4L, 4L, 5L, 5L, 5L), variable = structure(c(1L, 2L, 3L, 1L, 
2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L), levels = c("1", 
"2", "3"), class = "factor"), value = c(0L, 0L, -2L, 1L, -2L, 
1L, -1L, -2L, -2L, 0L, -1L, 2L, 0L, 1L, -2L)), row.names = c(NA, 
-15L), class = c("tbl_df", "tbl", "data.frame"))
1

There are 1 best solutions below

0
stefan On

The only option I have found to achieve your desired result would be to aggregate the data for the labels outside of the ggplot() pipeline.

library(tidyverse)
library(scales)

df_label <- df |>
  summarise(
    count = sum(value),
    .by = c(group, variable)
  ) |> 
  mutate(
    prop = proportions(count),
    prop_pos = ifelse(count < 0, prop, 0)
  ) |> 
  summarise(
    label = paste0(percent(sum(prop)), " | ", sum(count)),
    y = sum(prop_pos),
    .by = group
  )

df %>%
  ggplot() +
  aes(x = group, weight = value) +
  geom_bar(
    aes(y = after_stat(proportions(count)), fill = variable),
    stat = "count"
  ) +
  coord_flip() +
  geom_hline(yintercept = 0) +
  geom_text(
    data = df_label,
    aes(
      y = y,
      label = label,
      weight = NULL
    ),
    hjust = -.1
  ) +
  scale_y_continuous(limits = c(NA, 1))