geom_text positioning applies to both bars together instead of separately to each bar

Viewed 30

I have data as follows:

library(ggplot2)
library(dplyr)
library(tidyverse)
library(ggsignif)

graph <- structure(list(Constraint = structure(c(4L, 2L, 3L, 1L, 5L, 4L, 
2L, 3L, 1L, 5L), .Label = c("Major Constraint", "Minor Constraint", 
"Moderate Constraint", "No Constraint", "Total"), class = "factor"), 
    `Observation for Crime = 0` = c(3124, 2484, 3511, 4646, 13765, 
    3124, 2484, 3511, 4646, 13765), `Observation for Crime = 1` = c(762, 
    629, 1118, 1677, 4186, 762, 629, 1118, 1677, 4186), `Total Observations` = c(3886, 
    3113, 4629, 6323, 17951, 3886, 3113, 4629, 6323, 17951), 
    variable = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 
    2L), .Label = c("Crime = 0", "Crime = 1"), class = "factor"), 
    value = c(80.3911477097272, 79.79441053646, 75.847915316483, 
    73.4777795350308, 76.6809648487549, 19.6088522902728, 20.20558946354, 
    24.152084683517, 26.5222204649692, 23.3190351512451)), row.names = c(NA, 
-10L), class = "data.frame")

            Constraint Observation for Crime = 0 Observation for Crime = 1 Total Observations  variable    value
1        No Constraint                      3124                       762               3886 Crime = 0 80.39115
2     Minor Constraint                      2484                       629               3113 Crime = 0 79.79441
3  Moderate Constraint                      3511                      1118               4629 Crime = 0 75.84792
4     Major Constraint                      4646                      1677               6323 Crime = 0 73.47778
5                Total                     13765                      4186              17951 Crime = 0 76.68096
6        No Constraint                      3124                       762               3886 Crime = 1 19.60885
7     Minor Constraint                      2484                       629               3113 Crime = 1 20.20559
8  Moderate Constraint                      3511                      1118               4629 Crime = 1 24.15208
9     Major Constraint                      4646                      1677               6323 Crime = 1 26.52222
10               Total                     13765                      4186              17951 Crime = 1 23.31904

graph %>% 
  mutate(`Constraint` = fct_relevel(`Constraint`, "No Constraint", "Minor Constraint", "Moderate Constraint", "Major Constraint")) %>%
  ggplot(aes(x = `Constraint`, y = value)) + 
  geom_col(position = 'dodge', aes(fill = variable)) + 
  geom_text(position = position_dodge(width = .9),    # move to center of bars
            aes(label=sprintf("%.02f %%", round(value, digits = 1))),
            vjust = -2.5,    # nudge above top of bar
            hjust = - 0.2,
            size = 4) +        
  geom_text(position = position_dodge(width = .9),    # move to center of bars
            aes(label=`Observation for Crime = 0`),
            vjust = -0.6,    # nudge above top of bar
            hjust = - 0.2,
            size = 4) +     
  scale_fill_grey(start = 0.8, end = 0.5) +
  ylab("Percentage") + 
  xlab("Tax Constraint") + 
  theme_bw(base_size = 15)

Resulting in:

enter image description here

The following is not working out:

A) Although the percentages are in the middle for the dark grey bars, they are not for the light grey bars. Apparently I somehow made geom_text apply to the middle of the two bars, instead of the bars separately.

B) I would like to add the amount of observations in parentheses below the percentages, but I cannot figure out how to make sure that the dark grey and light grey bars take the observations from different columns.

Could anyone tell me what I am doing wrong?

1 Answers

The issue is that there is no grouping aesthetic in your geom_text layers, i.e. your bars are grouped and dodged by fill=variable, your labels are not. To solve this issue add group=variable to your geom_texts. Your second issue could be solved by an ifelse to conditionally select one of your columns.

library(ggplot2)
library(dplyr)
library(tidyverse)
library(ggsignif)

graph %>% 
  mutate(`Constraint` = fct_relevel(`Constraint`, "No Constraint", "Minor Constraint", "Moderate Constraint", "Major Constraint")) %>%
  ggplot(aes(x = `Constraint`, y = value)) + 
  geom_col(position = 'dodge', aes(fill = variable)) + 
  geom_text(position = position_dodge(width = .9),    # move to center of bars
            aes(label=sprintf("%.02f %%", round(value, digits = 1)), group = variable),
            vjust = -2.5,    # nudge above top of bar
            size = 4) +        
  geom_text(position = position_dodge(width = .9),    # move to center of bars
            aes(label= paste0("(", ifelse(variable == "Crime = 0", `Observation for Crime = 0`, `Observation for Crime = 1`), ")"), group = variable),
            vjust = -0.6,    # nudge above top of bar
            size = 4) +     
  scale_fill_grey(start = 0.8, end = 0.5) +
  ylab("Percentage") + 
  xlab("Tax Constraint") + 
  theme_bw(base_size = 15)

Related