Partial Fill Stacked Barplot in ggplot2

I would like to make a barplot with different categories of appointments as different colors, and appointment for each color, partially filled based on whether it was cancelled or not.



df <- tribble(
  ~ apt, ~ count, ~ attended,
  "Consult", 5, 3,
  "Follow Up", 3, 2,
  "Procedure", 6, 6
) %>% mutate(apt = factor(apt))

df %>% 
  ggplot(aes(x = "Appointments", y = count, fill = apt)) + 
  geom_bar(stat = "identity", position = "stack")



I would like the Green "Follow Up" bar to be "filled" only 2/3 of the way and the red "Consult" bar to be "filled" only 3/5 of the way based on the 3rd variable "attended"

Is there a way to do that with the existing ggplot parameters? I was trying to come up with a way using color and fill parameters creatively but it introduces a lot of headaches

>Solution :

You can achieve this by counting the missed appointments for each appointment type, then pivoting into long format. You can then assign attended vs missed appointments to the alpha aesthetic.

df %>% 
  mutate(DNA = count - attended) %>%
  select(-count) %>%
  pivot_longer(attended:DNA) %>%
  ggplot(aes(x = "Appointments", y = value, fill = apt, alpha = name)) + 
  geom_col(position = "stack", color = 'gray60') +
  scale_alpha_manual(NULL, values = c(1, 0.2))

enter image description here

If I may make a suggestion however, it would be a much easier plot to understand (and therefore better from a data-viz perspective) if you had the appointment type on the x axis and used fill color to represent the attended / missed groups. It is better to use color to highlight some important aspect about the information on display rather than using it gratuitously.

For example, if the reason for creating the plot is to highlight the number of missed appointments in each appointment type, we could do:

df %>% 
  mutate(DNA = count - attended) %>%
  select(-count) %>%
  pivot_longer(attended:DNA) %>%
  ggplot(aes(x = apt, y = value, fill = name)) + 
  geom_col(position = position_stack(reverse = TRUE), width = 0.5,
           alpha = 0.8) +
  theme_minimal(base_size = 16) +
  labs(y = 'Number of appointments', x = 'Appointment type') +
                    values = c('gray50', 'red4'),
                    labels = c('Attended', 'Did not attend')) +
  theme(panel.grid.major.x = element_blank())

enter image description here

This is a plot which needs very little, if any, explanation, and to my eye looks more professional and elegant.

Leave a Reply