I want to move some stacks of a stacked bar plot to below the x axis but doing so breaks the order of the stacks

32 views Asked by At

I have a df with the percentage of students that got a grade in a test (from A to D) for several schools. This df has the following structure

str(DF)
'data.frame':   244 obs. of  3 variables:
 $ School: Factor w/ 61 levels 
 $ variable: Factor w/ 4 levels "A","B","C","D"
 $ value   : num  22.4 29.8 16.7 35.1 23.6 ...

(the school column is a factor so i can plot them in a specific order)

I am using the following ggplot 2 code to graph this data, this code works perfectly to show the stacked bars in the correct order (A at the top and D at the bottom):

ggplot(DF, aes(x = School, y = -value, fill = variable)) +
  geom_bar(stat = "identity") +
  scale_fill_manual(values=paleta, labels = etiquetas)+
  geom_text(aes(label = paste0(round(value), "%")), position = position_stack(vjust = 0.5), size = 2, color = "black") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))+
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
        axis.text.y = element_blank(),
        panel.grid.major.y = element_blank(),
        panel.grid.minor.y = element_blank(),
        legend.position = "bottom")+
  guides(fill = guide_legend(reverse = TRUE))+
  scale_x_discrete(labels = function(x) str_sub(x, end = 20))```

I have tried many methods to move the percentage of students that got either a D or a C grade to below the x axis but whenever i do it the order of the stack breaks, usually the stack above the x axis flip so A is at the bottom and B is at the top.

1

There are 1 answers

0
Susan Switzer On

You may consider calling an empty ggplot() with two filtered geom_bar()s

df <- data.frame(school = rep(c('Adams', "Berkley", "Canter"), 4), 
                 variable = rep(c('A', 'B', 'C', 'D'), 3), 
                 value = c(5, 10, 20, 
                           55, 45, 50, 
                           20, 15, 20,  
                           20, 30, 10
                           )
                 ) %>% 
  mutate(value = case_when(
    variable %in% c('C', 'D') ~ -value, 
    TRUE ~ value
  )) %>% 
  mutate(variable = factor(variable, 
                           levels = c('A', 'B', 'D', 'C'))) %>% 
  arrange(school, variable)


ggplot() +
  geom_bar(data = filter(df,value >= 0),
           mapping = aes(x = school, 
               y = value, 
               fill = variable), 
           stat="identity"
           ) +
  geom_bar(data = filter(df,value < 0),
           mapping = aes(x = school, 
               y = value, 
               fill = variable), 
           stat="identity",
           position = position_stack(vjust = 0.5)) +
  geom_hline(yintercept = 0) +
  labs(fill = 'Grade')+
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))+
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
        axis.text.y = element_blank(),
        axis.title = element_blank(),
        panel.grid.major.y = element_blank(),
        panel.grid.minor.y = element_blank(),
        legend.position = "bottom")+
  guides(fill = guide_legend(reverse = T))+
  scale_fill_manual(values =  c('#e57a3c', '#e2a331', '#22a783', '#3688c8'), #colors
                    breaks =  c('D', 'C', 'B','A'),
                    labels =  c('D', 'C', 'B','A')) 

sample