2

I am trying to set up a nice legend. It should include the greek letter mu, I can do this with expression, some literals, i.e. ":" and "mm", and a coefficient of a model formatted with formatC. What i get running without problems is either to have no greek letter, then I can use simple paste command

leg.txt <- c("Number of Points:"
           ,formatC(length(dist),big.mark=" ")
           ,"Normal distribution"
           ,paste(mu,":",formatC(fit$estimate[1], digits = 3,format = "f"),"mm")
           ,paste(expression(sigma),":",formatC(fit$estimate[2], digits = 3,format = "f"),"mm")
           ,"Density plot"
           ,paste(expression(bar(x)),":",formatC(mean, digits = 3,format = "f"),"mm")
           ,paste("SD:",formatC(sd, digits = 3,format = "f"),"mm")
           )


legend("topleft",  leg.txt
     ,col= c("white","white","blue","white","white","red","white","white")
     ,bty = "n"
     ,lwd = c(2,2)  

)

this leads to something like

(Cannot post picture due to reputation)

mu: 0.283 mm

But as it can be seen, no Greek letters are included. Switching to something like

leg.txt <- c("Number of Points:"
           ,formatC(length(dist),big.mark=" ")
           ,"Normal distribution"
           ,eval(substitute(expression(paste(mu, ":" , c, "mm"),list(c=(formatC(fit$estimate[1], digits = 3,format = "f"))))))
           ,paste(expression(sigma),":",formatC(fit$estimate[2], digits = 3,format = "f"),"mm")
           ,"Density plot"
           ,paste(expression(bar(x)),":",formatC(mean, digits = 3,format = "f"),"mm")
           ,paste("SD:",formatC(sd, digits = 3,format = "f"),"mm")
           )digits = 3,format = "f"))))))

leads to y:cmm (formatC($(fit,estimate)_1,3,f))

I have the problem that after 2 hours of researching I am not able, to make mu either appear as a greek expression, or if I do, then the formatC() will not be evaluated, it will be instead posted like a literal instead of giving a formatted number.

Used all hints from other posts, like bquote etc. but could not make it running.

Edited some "more runnable" examples. This is Code which does not run:

x <- seq(1,100,1)
y <- runif(100)
y2 <- x + y 

fit <- lm(y2~x)
plot(x,y2)
abline(fit, col = "red",lwd = 2)
mu2    <- formatC(fit$coefficients[1], digits = 3,format = "f")
sigma2 <- formatC(fit$coefficients[2], digits = 3,format = "f")
mean <- mean(y2)
sd <- sd(y2)
leg.txt <- c("Number of Points:"
             ,formatC(length(dist),big.mark=" ")
             ,"Normal distribution"
             ,bquote(mu ~ ":" ~ .(mu2) ~ "mm")
             ,bquote(sigma ~ ":" ~ .(sigma2) ~ "mm")
             ,"Density plot"
             ,paste(expression(bar(x)),":",formatC(mean, digits = 3,format = "f"),"mm")
             ,paste("SD:",formatC(sd, digits = 3,format = "f"),"mm")
)
legend("topleft",  leg.txt
       ,col= c("white","white","blue","white","white","red","white","white")
       ,bty = "n"
       ,lwd = c(2,2)  
)

The problem happens when i use bquote the second time.

What runs is

x <- seq(1,100,1)
y <- runif(100)
y2 <- x + y 

fit <- lm(y2~x)
plot(x,y2)
abline(fit, col = "red",lwd = 2)
mu2    <- formatC(fit$coefficients[1], digits = 3,format = "f")
sigma2 <- formatC(fit$coefficients[2], digits = 3,format = "f")
mean <- mean(y2)
sd <- sd(y2)
leg.txt <- c("Number of Points:"
             ,formatC(length(dist),big.mark=" ")
             ,"Normal distribution"
             ,bquote(mu ~ ":" ~ .(mu2) ~ "mm")
             ,expression(paste(sigma,":",eval(formatC(fit$estimate[2], digits = 3,format = "f"))),"mm")
             ,"Density plot"
             ,paste(expression(bar(x)),":",formatC(mean, digits = 3,format = "f"),"mm")
             ,paste("SD:",formatC(sd, digits = 3,format = "f"),"mm")
)
legend("topleft",  leg.txt
       ,col= c("white","white","blue","white","white","red","white","white")
       ,bty = "n"
       ,lwd = c(2,2)  
)

Still I think that bquote is the way to go. In my real data I am fitting a normal distribution, but that should not matter.

Error I get by using bquote two times is: argument legend is missing with no default (translated from german error message, but seems to be right. The legend object gets no txt, though it is in my workspace.

Solution which is now working finally is:

x <- seq(1,100,1)
y <- runif(100)
y2 <- x + y 

fit <- lm(y2~x)
plot(x,y2)
abline(fit, col = "red",lwd = 2)
mu2    <- formatC(fit$coefficients[1], digits = 3,format = "f")
sigma2 <- formatC(fit$coefficients[2], digits = 3,format = "f")
mean <- mean(y2)
sd <- sd(y2)
leg.txt <- c("Number of Points:"
             ,formatC(length(dist),big.mark=" ")
             ,"Normal distribution"
             ,as.expression(bquote(mu ~ ":" ~ .(mu2) ~ "mm"))
             ,as.expression(bquote(sigma ~ ":" ~ .(sigma2) ~ "mm"))
)
legend("topleft",  leg.txt
       ,col= c("white","white","blue","white","white","red","white","white")
       ,bty = "n"
       ,lwd = c(2,2)  
)
BuddhaWithBigBelly
  • 345
  • 1
  • 6
  • 15
  • 1
    I get `Error in paste(mu, ":", ...), : object 'mu' not found` when I run your code. Also `fit` isn't defined. If you can make this reproducible, it will be easier for others to help you. – Aaron left Stack Overflow Jan 23 '14 at 12:52
  • Yeah sorry, your absolutely right, updated the post. – BuddhaWithBigBelly Jan 23 '14 at 13:31
  • You need `legend=leg.txt` to avoid the "legend is missing" message; notice that legend is the third parameter, but you're including it as the second one. – Aaron left Stack Overflow Jan 23 '14 at 15:15
  • Actually, that's not quite right; with two bquotes you have the same issue I had in my answer, where it's not combined properly. That means that it doesn't recognize the second argument as a text or expression so tries to use it as the `y` argument. Making one of the terms into an expression, either as I did, or by using `as.expression`, seems to fix that. – Aaron left Stack Overflow Jan 23 '14 at 15:30

2 Answers2

1

You use substitute to include both "math" and numeric variables, as in ?plotmath. But here there was also something unexpected; the vector of elements for the legend didn't combine properly unless one of them was an expression, so here I just made one of your plain text lines into an expression.

fit <- list(estimate=c(1.35456, 2.63454))
dist <- 1:10
mean <- 10.3456
sd <- 0.1566

leg.txt <- c(paste("Number of Points:",formatC(length(dist),big.mark=" "))
                   ,expression("Normal distribution")
                   ,substitute(paste(mu,": ",x," mm"), 
                        list(x=formatC(fit$estimate[1], digits = 3,format = "f")))
                   ,substitute(paste(sigma,": ",x," mm"), 
                        list(x=formatC(fit$estimate[2], digits = 3,format = "f")))
                   ,"Density plot"
                   ,substitute(paste(bar(x),": ",y," mm"), 
                        list(y=formatC(mean, digits = 3,format = "f")))
                   ,substitute(paste("SD: ",x," mm"), 
                        list(x=formatC(sd, digits = 3,format = "f")))
           )

plot(1:5,1:5)
legend("topleft",  legend=leg.txt
     ,col= c("white","blue","white","white","red","white","white")
     ,bty = "n"
     ,lwd = c(2,2)  
)
IRTFM
  • 258,963
  • 21
  • 364
  • 487
Aaron left Stack Overflow
  • 36,704
  • 7
  • 77
  • 142
  • I thought the insight that one of the elements needed to be an R expression classed object was valuable, because it forced all the the arguments to be elements in an single expression vector. I believe that forced the used of the plotmath `paste` function rather than the base `paste` function. `substitute` doesn't actually return expressions but rather call-objects. – IRTFM Mar 22 '14 at 18:52
  • Interesting thought as to why this happens. From the `plotmath` documentation, though, it looks like this only is called in the `text` arguments to one of the text-drawing functions. Since this happens even before the legend command, it seems likely to me that it's some other mechanism. – Aaron left Stack Overflow Mar 23 '14 at 01:32
  • Please review the code (for `legend`) and then tell us what function is used for the textual portion of the legend operation? – IRTFM Mar 23 '14 at 03:24
  • I should clarify; the `leg.txt` object is different, even before it gets to `legend`. – Aaron left Stack Overflow Mar 23 '14 at 04:05
  • It looks like the parser examines the entire vector and if it finds a single expression makes it an expression vector. I was pointing out that the `paste` function was being applied as the plotmath version. That is happening inside the `text` function. – IRTFM Mar 23 '14 at 16:16
1

This is another approach using an sapply( expr-vector, as.expression) approach that I saw on Rhelp years ago. I cannot remember which of the gurus to thank (probably one of Ligges, Grothendieck, Murdoch, Dalgaard). It allows the use of bquote constructed expressions and avoids the use of plotmath-paste which I see as a major advantage in readablity.

plot(x,y2)
abline(fit, col = "red",lwd = 2)
leg.txt <- sapply( c("Number of Points:"
             ,bquote(.(formatC(length(dist),big.mark=" ")))
             ,"Normal distribution"
             ,bquote(mu ~ ":" ~ .(mu2) ~ mm)
             ,bquote(sigma~":"~.(formatC(fit$estimate[2], digits = 3,format = "f"))~mm)
             ,"Density plot"
             ,bquote(bar(x)*":"*.(formatC(mean, digits = 3,format = "f"))*mm)
             ,bquote(SD*":"*.(formatC( sd, digits = 3,format = "f"))*mm)
), as.expression)


legend("topleft",  legend=leg.txt
       ,col= c("white","blue","white","white","red","white","white")
       ,bty = "n"
       ,lwd = c(2,2)  
)
IRTFM
  • 258,963
  • 21
  • 364
  • 487