Home > Software design >  Add total number to ggplot legend
Add total number to ggplot legend

Time:06-09

I made a frequency barplot with the following data and code:

structure(list(Geslacht = c("man", "man", "man", "man", "man", 
"man", "man", "vrouw", "vrouw", "vrouw", "vrouw", "vrouw", "vrouw", 
"vrouw", "vrouw"), Lengteklasse = c(6, 7, 8, 9, 10, 11, 12, 6, 
7, 8, 9, 10, 11, 12, 13), Freq = c(1L, 9L, 19L, 21L, 35L, 22L, 
5L, 2L, 13L, 19L, 37L, 45L, 40L, 6L, 1L)), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -15L), groups = structure(list(
    Geslacht = c("man", "vrouw"), .rows = structure(list(1:7, 
        8:15), ptype = integer(0), class = c("vctrs_list_of", 
    "vctrs_vctr", "list"))), class = c("tbl_df", "tbl", "data.frame"
), row.names = c(NA, -2L), .drop = TRUE))
ggplot(Freq_lengteklasse, aes(Lengteklasse, Freq, fill = Geslacht)) 
  geom_col() 
  scale_x_continuous(breaks = seq(6,13, by = 1)) 
  scale_y_continuous(breaks = seq(0,80, by = 10)) 
  labs(x = "Lengteklasse (cm)", y = "Frequentie") 
  scale_fill_manual(values=c('lightgray','black')) 
  theme_classic()

I want to add the total count of man and vrouw which should say n = 275, positioned under the legend. How would one do this?

CodePudding user response:

You can add a tag in your labs which will display the total number. You can change the position of the tag in the theme with plot.tag.position. You can use the following code:

library(tidyverse)
ggplot(Freq_lengteklasse, aes(Lengteklasse, Freq, fill = Geslacht)) 
  geom_col() 
  scale_x_continuous(breaks = seq(6,13, by = 1)) 
  scale_y_continuous(breaks = seq(0,80, by = 10)) 
  labs(x = "Lengteklasse (cm)", y = "Frequentie", tag = paste('n =', sum(Freq_lengteklasse$Freq))) 
  scale_fill_manual(values=c('lightgray','black')) 
  theme_classic()  
  theme(plot.tag.position = c(0.95, 0.4))

Output:

enter image description here

Comment: italic n

You can use substitute and add your value in an env to paste it italic like this:

library(tidyverse)
ggplot(Freq_lengteklasse, aes(Lengteklasse, Freq, fill = Geslacht)) 
  geom_col() 
  scale_x_continuous(breaks = seq(6,13, by = 1)) 
  scale_y_continuous(breaks = seq(0,80, by = 10)) 
  labs(x = "Lengteklasse (cm)", y = "Frequentie", tag = substitute(expr = paste(italic("n"), " = ", x), env = base::list(x = sum(Freq_lengteklasse$Freq)))) 
  scale_fill_manual(values=c('lightgray','black')) 
  theme_classic()  
  theme(plot.tag.position = c(0.95, 0.4))

Output:

enter image description here

CodePudding user response:

annotation_custom will also work for your case.

Freq_lengteklasse %>%
  ggplot(aes(Lengteklasse, Freq, fill = Geslacht)) 
  geom_col() 
  scale_x_continuous(breaks = seq(6,13, by = 1)) 
  scale_y_continuous(breaks = seq(0,80, by = 10)) 
  labs(x = "Lengteklasse (cm)", y = "Frequentie") 
  scale_fill_manual(values=c('lightgray','black')) 
  theme_classic()   
  annotation_custom(grob = textGrob("n = 275"),  
                    xmin = 14, xmax = 16, ymin = 26, ymax = 30)  
  coord_cartesian(clip = "off") 

enter image description here

CodePudding user response:

Another option would be to use a cowplot and patchwork hack. Basically this involves to first extract the legend via cowplot::get_legend and creating the annotation as a grob. Afterwards we glue these elements together with the main plot via patchwork.

library(ggplot2)

p <- ggplot(Freq_lengteklasse, aes(Lengteklasse, Freq, fill = Geslacht))  
  geom_col()  
  scale_x_continuous(breaks = seq(6, 13, by = 1))  
  scale_y_continuous(breaks = seq(0, 80, by = 10))  
  labs(x = "Lengteklasse (cm)", y = "Frequentie")  
  scale_fill_manual(values = c("lightgray", "black"))  
  theme_classic()


library(cowplot)
library(patchwork)

legend <- (p   theme(legend.justification = "bottom")) |> get_legend()
annotation <- grid::textGrob(label = "n = 275", y = unit(1, "npc"), vjust = 1)

design = "
AB
AC
"
list(p   guides(fill = "none"), legend, annotation) |> 
  wrap_plots()   
  plot_layout(widths = c(9, 1), design = design)

  • Related