Dan Goldstein
Dan Goldstein

Reputation: 24889

R: Generate plot axis break labels with superscripts programmatically

I would like to make tick labels with superscripts as in mylabels in the following example. However, I don't want to hand code them, I want them to go up to 3^LEVELS, where LEVELS is a constant

library(ggplot2)

LEVELS = 4

mylabels = c(
  expression(paste(3^4,"= 81")),
  expression(paste(3^3,"= 27")),
  expression(paste(3^2,"= 9")),
  expression(paste(3^1,"= 3")),
  expression(paste(3^0,"= 1")))
mylabels
length(mylabels)


df=data.frame(x=runif(40),y=(runif(40)*10)%%5)
p = ggplot(df,aes(x,y))  + 
  geom_point() + 
  scale_y_continuous(breaks = 0:LEVELS, labels = mylabels)
p

The hard coded version works perfectly. But I can't seem to get it programmatically. The following:

mylabels=c(paste("expression(paste(3^",LEVELS:0,'," = ',3^(LEVELS:0),'"))',sep=""))

doesn't properly evaluate in the chart (e.g., it writes the word 'expression', etc. in the label). It creates:

[1] "expression(paste(3^4,\" = 81\"))" "expression(paste(3^3,\" = 27\"))" "expression(paste(3^2,\" = 9\"))" 
[4] "expression(paste(3^1,\" = 3\"))"  "expression(paste(3^0,\" = 1\"))" 

and what I want is:

expression(paste(3^4, "= 81"), paste(3^3, "= 27"), paste(3^2, 
"= 9"), paste(3^1, "= 3"), paste(3^0, "= 1"))

Have messed about with collapse, noquote, eval, sprintf, etc.

Upvotes: 3

Views: 278

Answers (1)

bgoldst
bgoldst

Reputation: 35314

You need to build the expression vector as a character vector first, and then parse it using parse(), which returns an expression vector correspondent to the input character vector. Building the character vector is best done with sprintf():

mylabels <- parse(text=sprintf('paste(3^%d,\' = %d\')',LEVELS:0,3^(LEVELS:0)));
mylabels;
## expression(paste(3^4,' = 81'), paste(3^3,' = 27'), paste(3^2,' = 9'),
##     paste(3^1,' = 3'), paste(3^0,' = 1'))

plot


Other tips:

1: When providing sample code that depends on random number generation, please call set.seed() before generating any randomness.

2: The expression() function is variadic, and returns an expression vector whose elements correspond to the input arguments. Hence you can replace

c(
    expression(paste(3^4,"= 81")),
    expression(paste(3^3,"= 27")),
    expression(paste(3^2,"= 9")),
    expression(paste(3^1,"= 3")),
    expression(paste(3^0,"= 1"))
)

with

expression(
    paste(3^4,"= 81"),
    paste(3^3,"= 27"),
    paste(3^2,"= 9"),
    paste(3^1,"= 3"),
    paste(3^0,"= 1")
)

3: Avoid redundant calls to c(). You can replace

c(paste("expression(paste(3^",LEVELS:0,'," = ',3^(LEVELS:0),'"))',sep=""))

with

paste("expression(paste(3^",LEVELS:0,'," = ',3^(LEVELS:0),'"))',sep="")

Upvotes: 3

Related Questions