Home > Net >  Aligning a geom_text layer vertically on a bar chart
Aligning a geom_text layer vertically on a bar chart

Time:02-21

I currently have the geom_text set to the center of the bar chart...

enter image description here

enroll_bar <- enroll_cohort %>% filter(chrt_grad != 2013) %>%
  mutate(college_enrolled = factor(college_enrolled),
         chrt_grad = factor(chrt_grad)) %>%
  mutate(label_height = cumsum(n)) %>%
  ggplot()  
  geom_col(mapping = aes(x = chrt_grad, y = n, fill = fct_rev(college_enrolled)))  
  geom_text(aes(x = chrt_grad, y = label_height, label = n), color = "white", 
            position = position_stack(vjust = 0.5))  
  scale_y_continuous(expand = expansion(mult = c(0, 0.1)))  
  labs(x = NULL,
       y = NULL)  
  scale_fill_manual(labels = c("Enrolled", "Not Enrolled"), values = c("#00aeff", "#005488"))

How do I align the text vertically, so the geom_text layer is set at the same y-axis position for each bar? Also, is there a way to do this so the text is always aligned no matter the scale of the y-axis because this is a parameterized report and the y-axis values change with each report?

CodePudding user response:

If you want the labels to be at a uniform height, you can designate a y in geom_text() outside of aes with the height you're looking for.

I used the dataset diamonds. The columns are too non-uniform for the white text to be visible, so I changed the top labels to black.

Because the bottom group's lowest value is really low, I set it to 100. The top group is set to 5000. Essentially, I created a vector -- 100, 5000, 100, 5000, 100... and so on, using rep() (repeat).

The data is set up differently since you didn't include that in your question. However, that shouldn't matter.

library(tidyverse)

diamonds %>% 
  filter(color %in% c("E", "I")) %>% 
  ggplot(aes(x = cut,
             fill = color))   
  geom_bar()  
  geom_text(aes(label = ..count..),  # use the count
            y = rep(c(100, 5000),    # btm label y = 100, top label y = 5K
                    times = 5),
            stat = 'count',
            color = rep(c("white", "black"), # btm label white, top black
                        times = 5),
            position = position_stack(vjust = .5))  
  scale_y_continuous(expand = expansion(mult = c(0, 0.1)))  
  labs(x = NULL, y = NULL)  
  scale_fill_manual(labels = c("E", "I"),
                    values = c("#00aeff", "#005488"))  
  theme_bw()

enter image description here

CodePudding user response:

You can set a uniform label height for each group using if_else (or case_when for >2 groups). For a single plot, you can simply set a value, e.g., label_height = if_else(college_enrolled == "Enrolled", 20000, 3000). To make the relative height consistent across plots, you can instead set label_height as a proportion of the y-axis range:

library(tidyverse)

# make a fake dataset
enroll_cohort <- expand_grid(
    chrt_grad = factor(2014:2021),
    college_enrolled = factor(c("Enrolled", "Not Enrolled")),
  ) %>%
  mutate(
    n = sample(18000:26000, 16),
    n = if_else(college_enrolled == "Enrolled", n, as.integer(n / 3))
  )

enroll_bar <- enroll_cohort %>% 
  group_by(chrt_grad) %>%            # find each bar's height by summing up `n`
  mutate(bar_height = sum(n)) %>%    # within each year
  ungroup() %>%
  mutate(label_height = if_else(
    college_enrolled == "Enrolled", 
    max(bar_height) * .6,            # y-axis height is max() of bar heights;
    max(bar_height) * .1             # set label_height as % of bar height
  )) %>%
  ggplot()  
  geom_col(aes(x = chrt_grad, y = n, fill = college_enrolled), color = NA)  
  geom_text(
    aes(x = chrt_grad, y = label_height, label = n), 
    color = "white"
  )  
  scale_y_continuous(expand = expansion(mult = c(0, 0.1)))  
  labs(x = NULL, y = NULL)  
  scale_fill_manual(values = c("#00aeff", "#005488"))
A stacked bar chart with y axis 0 to about 30,000. Value labels are at the same height for each group regardless of y value.

If we generate another dataset with a different range -- e.g., by setting n = sample(18000:26000, 16) -- the text labels stay at the same relative positions: A stacked bar chart with y axis 0 to 2500. Value labels are at the same height for each group regardless of y value.

  • Related