Add count of samples used below columns in ggplot

Viewed 40

I have a data frame that looks similar to the one below and I would like to add the number A, B and C used in in each column and state it on the x-axis. To get something like A(n=1), B(n=2), C(n=0) written below the columns instead of just A, B and C. How could this be done?


df <- tibble(X = c("A","A","B","B","C","C","B","B","B","C","C"),
             value = c(5,2,7,3,1,6,9,4,2,5,2),
             type = c("t","t","t","t","t","s","s","s","s","s", "s"),
             group = c("Group1","Group2","Group1","Group2","Group1","Group1","Group3","Group2","Group3","Group3", "Group3"))


df %>% ggplot(aes(X,value)) +
  geom_col(aes(fill=type)) +
  facet_grid(~group)

enter image description here

Hope I explained my self clear enough.

2 Answers

How about this:

df <- tibble(X = c("A","A","B","B","C","C","B","B","B","C","C"),
             value = c(5,2,7,3,1,6,9,4,2,5,2),
             type = c("t","t","t","t","t","s","s","s","s","s", "s"),
             group = c("Group1","Group2","Group1","Group2","Group1","Group1","Group3","Group2","Group3","Group3", "Group3"))

To make sure that all the groups (even those with zeros are accounted for), you need to make a data set that contains all possible values of the grouping variable and the X variable. You want to set value=0 and it could be of either type, but type can't be NA.

all_cats <- expand_grid(X = sort(unique(df$X)), 
                        group = sort(unique(df$group)), 
                        type="s", 
                        value=0)

Then, you can full-join the all_cats data with the original data. You can group by X and group and then calculate the sum of the values to be plotted. You then make a label that pastes the values of X to a new line character and then n= the calculate total for that column. Then the plot proceeds as expected. Make sure to use scales="free_x" as an argument to facet_grid(). By appending the number to each X value, you've created 9 different values of X instead of 3. Using the scales="free_x" argument will make sure to only plot those levels relevant to the specific group.

df %>% 
    full_join(all_cats) %>% 
    group_by(X, group) %>% 
    mutate(n = sum(value), 
           Xlab = paste0(X, "\n(n=", n, ")")) %>%  
           ggplot(aes(Xlab,value)) +
    geom_col(aes(fill=type)) +
    facet_grid(~group, scales = "free_x") 

enter image description here

Here the solution:

library(tibble)
library(ggplot2)

# Your data.
df <- tibble(X = c("A","A","B","B","C","C","B","B","B","C","C"),
             value = c(5,2,7,3,1,6,9,4,2,5,2),
             type = c("t","t","t","t","t","s","s","s","s","s", "s"),
             group = c("Group1","Group2","Group1","Group2","Group1","Group1","Group3","Group2","Group3","Group3", "Group3"))

# Creating new column.
df$n = numeric(nrow(df)) # Pre-allocating memory.
df$n[df$X == "A"] = sum(df$X == "A")
df$n[df$X == "B"] = sum(df$X == "B")
df$n[df$X == "C"] = sum(df$X == "C")

df$n = paste(paste(df$X, paste("n", df$n, sep = "="), sep = "("), ")", sep = "")

# Plotting.
df %>% ggplot(aes(n, value)) +
  geom_col(aes(fill=type)) +
  labs(x = "X") + 
  facet_grid(~group)

I just created a new column in df storing the labels you wanted, and used this new variable in aes(). I also renamed the x-axis, so that you do not have issues in that sense. Below the resulting graph:

enter image description here

Related