Automatically Convert Polynomials to Expression for ggplot Legend in R

Viewed 67

I'm currently trying to convert polynomial variable strings into expressions in R and have seen this similar link. However, I'm struggling to conceptualize a method that would allow me to provide a list of variables and develop a string that would appear correct for a ggplot legend. For example, I have the below string:

variable.names <- c("x", "y", "yy", "xxx", "xxy", "yyy", 
                    "xxxxx", "xxxxy", "xxxyy", "xxyyy", "yyyyy")

and would like to convert it automatically to:

new.variable.names <- c("x", "y", expression(y^2),
                    expression(x^3), expression(paste(x^2, y)), expression(y^3),
                    expression(x^5), expression(paste(x^4, y)), expression(paste(x^3, y)),
                    expression(paste(x^2, y^3)), expression(y^5))

This is one example, but I am hoping to write a function that can do this with possibly more variables in variable.names. I was thinking there was possibly a way to use regular expressions, but don't know how to develop a function that would determine the pattern of letters, and put them in the right position for the expression and paste functions to create the names automatically.

Thanks in advance.

2 Answers
variable.names <- c("x", "y", "yy", "xxx", "xxy", "yyy", 
                    "xxxxx", "xxxxy", "xxxyy", "xxyyy", "yyyyy")

foo <- function(x) {
  runlength <- rle(x)
  string <- gsub("^1", "", 
                 paste0(paste(runlength$values, 
                              runlength$lengths, sep = "^"), 
                        collapse = "*"), 
                 fixed = TRUE)
  parse(text = string)
}

res <- lapply(strsplit(variable.names, ""), foo)



plot.new()

plot.window(c(0, 2), c(0, 11))
text(1, 10:0, do.call(c, res))

resulting plot

Here's a tidy solution UPDATED 2020-11-24T13:35:33 to work for any number of variables and to not include the ^ and output expression:

purrr::map(strsplit(variable.names, ""), ~{
    
    .str <- .x
    .vars <- purrr::map(unique(.str), ~{
        .instances <- sum(.str %in% .x)
        if (.instances == 0) .v <- NULL else if (.instances == 1) .v <- .x else if  (.instances > 1) .v <- paste0(.x,"^",.instances)
    })
    
    parse(text = paste0(.vars, collapse = "*"))  
    
})
Related