Search code examples
rggplot2labelexpressionfigure

R: Programmatically changing ggplot scale labels to Greek letters with expressions


I am trying to change the labels in a ggplot object to Greek symbols for an arbitrary number of labels. Thanks to this post, I can do this manually when I know the number of labels in advance and the number is not too large:

    # Simulate data 
   df <- data.frame(name = rep(c("alpha1","alpha2"), 50),
               value = rnorm(100))
   
   # Create a plot with greek letters for labels
   ggplot(df, aes(x = value, y = name)) + geom_density() +
     scale_y_discrete(labels = c("alpha1" = expression(alpha[1]),
                                 "alpha2" = expression(alpha[2])))
   

For our purposes, assume I need to change k default labels, where each of the k labels is the pre-fix "alpha" followed by a number 1:k. Their corresponding updated labels would substitute the greek letter for "alpha" and use a subscript. An example of this is below:

# default labels
paste0("alpha", 1:k)

# desired labels
for (i in 1:k) { expression(alpha[i]) }

I was able to hack together the below programmatic solution that appears to produce the desired result thanks to this post:

   ggplot(df, aes(x = value, y = name)) + geom_density() +
       scale_y_discrete(labels = parse(text = paste("alpha[", 1:length(unique(df)), "]")))

However, I do not understand this code and am seeking clarification about:

  1. What is parse() doing here that expression() otherwise would do?
  2. While I understand everything to the right-hand side of =, what is text doing on the left-hand side of the =?

Solution

  • Another option to achieve your desired result would be to add a new column to your data which contains the ?plotmath expression as a string and map this new column on y. Afterwards you could use scales::label_parse() to parse the expressions:

    set.seed(123)
    
    df <- data.frame(name = rep(c("alpha1","alpha2"), 50),
                     value = rnorm(100))
    df$label <- gsub("^(.*?)(\\d+)$", "\\1[\\2]", df$name)
    
    library(ggplot2)
    library(scales)
    
    ggplot(df, aes(x = value, y = label)) + geom_density() +
      scale_y_discrete(labels = scales::label_parse())