76

Consider this simple example:

labNames <- c('xLab','yLabl')
plot(c(1:10),xlab=expression(paste(labName[1], x^2)),ylab=expression(paste(labName[2], y^2)))

What I want is for the character entry defined by the variable 'labName, 'xLab' or 'yLab' to appear next to the X^2 or y^2 defined by the expression(). As it is, the actual text 'labName' with a subscript is joined to the superscripted expression.

Any thoughts?

Léo Léopold Hertz 준영
  • 134,464
  • 179
  • 445
  • 697
aaron
  • 6,339
  • 12
  • 54
  • 80

5 Answers5

86

An alternative solution to that of @Aaron is the bquote() function. We need to supply a valid R expression, in this case LABEL ~ x^2 for example, where LABEL is the string you want to assign from the vector labNames. bquote evaluates R code within the expression wrapped in .( ) and subsitutes the result into the expression.

Here is an example:

labNames <- c('xLab','yLab')
xlab <- bquote(.(labNames[1]) ~ x^2)
ylab <- bquote(.(labNames[2]) ~ y^2)
plot(c(1:10), xlab = xlab, ylab = ylab)

(Note the ~ just adds a bit of spacing, if you don't want the space, replace it with * and the two parts of the expression will be juxtaposed.)

Gavin Simpson
  • 170,508
  • 25
  • 396
  • 453
  • 3
    More examples: https://www.r-bloggers.com/2018/03/math-notation-for-r-plot-titles-expression-and-bquote/ – ekatko1 Mar 30 '21 at 20:39
  • wondering why this answer was selected/got more upvotes than the substitute solution? I thought more people would be familiar with substitute than bquote – leo Apr 09 '21 at 11:09
  • 2
    @timing I don't know, but I find the `bquote()` syntax less verbose and it allows you to work with expressions, not strings – Gavin Simpson Apr 09 '21 at 15:02
39

EDIT: added a new example for ggplot2 at the end

See ?plotmath for the different mathematical operations in R

You should be able to use expression without paste. If you use the tilda (~) symbol within the expression function it will assume there is a space between the characters, or you could use the * symbol and it won't put a space between the arguments

Sometimes you will need to change the margins in you're putting superscripts on the y-axis.

par(mar=c(5, 4.3, 4, 2) + 0.1)
plot(1:10, xlab = expression(xLab ~ x^2 ~ m^-2),
     ylab = expression(yLab ~ y^2 ~ m^-2),
     main="Plot 1")

enter image description here

plot(1:10, xlab = expression(xLab * x^2 * m^-2),
     ylab = expression(yLab * y^2 * m^-2),
     main="Plot 2")

enter image description here

plot(1:10, xlab = expression(xLab ~ x^2 * m^-2),
     ylab = expression(yLab ~ y^2 * m^-2),
     main="Plot 3")

enter image description here

Hopefully you can see the differences between plots 1, 2 and 3 with the different uses of the ~ and * symbols. An extra note, you can use other symbols such as plotting the degree symbol for temperatures for or mu, phi. If you want to add a subscript use the square brackets.

plot(1:10, xlab = expression('Your x label' ~ mu[3] * phi),
     ylab = expression("Temperature (" * degree * C *")"))

enter image description here

Here is a ggplot example using expression with a nonsense example

require(ggplot2)

Or if you have the pacman library installed you can use p_load to automatically download and load and attach add-on packages

# require(pacman)
# p_load(ggplot2)

data = data.frame(x = 1:10, y = 1:10)

ggplot(data, aes(x,y)) + geom_point() + 
  xlab(expression(bar(yourUnits) ~ g ~ m^-2 ~ OR ~ integral(f(x)*dx, a,b))) + 
  ylab(expression("Biomass (g per" ~ m^3 *")")) + theme_bw()

enter image description here

Axeman
  • 32,068
  • 8
  • 81
  • 94
s_scolary
  • 1,361
  • 10
  • 21
  • I've started using ggplot as my main plotting tool and this method works for ggplot as well – s_scolary Apr 02 '17 at 19:10
  • 2
    while a nicely elaborated example of matplotlib, this answer doesn't actually allow for substition of values from a character vector into the axes. The intro of your example gave me the idea it would be helpful for ggplot, but other answers here are more helpful. – FM Kerckhof Oct 06 '18 at 20:44
  • To be honest I don't quite see how this answers the OP question, which is how you can `paste` a variable value inside an `expression`. In these examples the value is written by hand. This way doesn't work if, say, you have to produce 100 plots with different values through a `for`-loop. – pglpm Jul 01 '23 at 11:54
37

Use substitute instead.

labNames <- c('xLab','yLab')
plot(c(1:10),
     xlab=substitute(paste(nn, x^2), list(nn=labNames[1])),
     ylab=substitute(paste(nn, y^2), list(nn=labNames[2])))
Aaron left Stack Overflow
  • 36,704
  • 7
  • 77
  • 142
12

Very nice example using paste and substitute to typeset both symbols (mathplot) and variables at http://vis.supstat.com/2013/04/mathematical-annotation-in-r/

Here is a ggplot adaptation

library(ggplot2)
x_mean <- 1.5
x_sd <- 1.2
N <- 500

n <- ggplot(data.frame(x <- rnorm(N, x_mean, x_sd)),aes(x=x)) +
    geom_bar() + stat_bin() +
    labs(title=substitute(paste(
             "Histogram of random data with ",
             mu,"=",m,", ",
             sigma^2,"=",s2,", ",
             "draws = ", numdraws,", ",
             bar(x),"=",xbar,", ",
             s^2,"=",sde),
             list(m=x_mean,xbar=mean(x),s2=x_sd^2,sde=var(x),numdraws=N)))

print(n)
WMash
  • 407
  • 4
  • 5
  • Nice. This is insane, but it's the only approach I was able to get to work! Here an example combining unicode symbols with expression! ``title = substitute(paste("n = ", n, ", ", bar(x), " = ", mu, ", ", "\u03C3/\u221An = ", se), list(n = df[["n"]], mu = format(df[["mu"]], digits = 2, nsmall = 2), se = format(df[["se"]], digits = 2, nsmall = 2), sep = ""))``, where ``df`` is a dataframe holding the values to be printed (the sample size ``n``, the sample mean ``mu``and the standard error ``se``). Wow. – PatrickT Dec 01 '18 at 14:46
  • This is also the only solution for ggplot that I could get to work. Note for people like me that routinely use `paste0` over `paste`, use of `paste` is essential here. – quantixed Aug 29 '22 at 06:48
6

If x^2 and y^2 were expressions already given in the variable squared, this solves the problem:

labNames <- c('xLab','yLab')
squared <- c(expression('x'^2), expression('y'^2))

xlab <- eval(bquote(expression(.(labNames[1]) ~ .(squared[1][[1]]))))
ylab <- eval(bquote(expression(.(labNames[2]) ~ .(squared[2][[1]]))))

plot(c(1:10), xlab = xlab, ylab = ylab)

Please note the [[1]] behind squared[1]. It gives you the content of "expression(...)" between the brackets without any escape characters.

daniel.heydebreck
  • 768
  • 14
  • 22