# [Rd] substitute and expression

Peter Dalgaard P.Dalgaard at biostat.ku.dk
Tue Jul 17 17:39:50 CEST 2007

Deepayan Sarkar wrote:
> On 7/16/07, Peter Dalgaard <p.dalgaard at biostat.ku.dk> wrote:
>
>> Deepayan Sarkar wrote:
>>
>>> Hi,
>>>
>>> I'm trying to understand whether the use of substitute() is
>>> appropriate/documented for plotmath annotation. The following two
>>> calls give the same results:
>>>
>>>
>>>
>>>> plot(1:10, main = expression(alpha == 1))
>>>> do.call(plot, list(1:10, main = expression(alpha == 1)))
>>>>
>>>>
>>> But not these two:
>>>
>>>
>>>
>>>> plot(1:10, main = substitute(alpha == a, list(a = 2)))
>>>> do.call(plot, list(1:10, main = substitute(alpha == a, list(a = 2))))
>>>>
>>>>
>>>
>>> (as a consequence, xyplot(..., main = substitute(alpha)) doesn't
>>> currently work.)
>>>
>>> On the other hand, this works:
>>>
>>>
>>>
>>>> foo <- function(x) plot(1, main = x)
>>>> foo(substitute(alpha))
>>>>
>>>>
>>> I'm not sure how to interpret ?plotmath; it says
>>>
>>>      If the 'text' argument to one of the text-drawing functions
>>>      ('text', 'mtext', 'axis', 'legend') in R is an expression, the
>>>      argument is interpreted as a mathematical expression...
>>>
>>> and uses substitute() in its examples, but
>>>
>>>
>>>
>>>> is.expression(substitute(alpha == a, list(a = 1)))
>>>>
>>>>
>>> [1] FALSE
>>>
>>>
>> I think you need to take plotmath out of the equation and study the
>> difference between objects of mode "call" and those of mode
>> "expression". Consider this:
>>
>>  > f <- function(...)match.call()
>>  > do.call(f, list(1:10, main = substitute(alpha == a, list(a = 2))))
>> function(...)match.call()
>> (1:10, main = alpha == 2)
>>  > do.call(list, list(1:10, main = substitute(alpha == a, list(a = 2))))
>> Error in do.call(list, list(1:10, main = substitute(alpha == a, list(a =
>> 2)))) :
>>
>> The issue is that function ends up with an argument  alpha == 2 which it
>> proceeds to evaluate (lazily), where a direct call sees
>> substitute(.....). It is a general problem with the do.call mechanism
>> that it effectively pre-evaluates the argument list, which can confuse
>> functions that rely on accessing the original argument expression. Try,
>> e.g., do.call(plot, list(airquality\$Wind, airquality\$Ozone)) and watch
>> the axis labels.
>>
>
> Right. Lazy evaluation was the piece I was missing.
>
>
>> Does it work if you use something like
>>
>>  main = substitute(quote(alpha == a), list(a = 2))?
>>
>
> Not for xyplot, though I haven't figured out why. Turns out this also
> doesn't work:
>
>
>> plot(y ~ x, data = list(x = 1:10, y = 1:10), main = substitute(alpha))
>>
>
> I'll take this to mean that the fact that substitute() works sometimes
> (for plotmath) is an undocumented side effect of the implementation
> that should not be relied upon.
>
Probably the correct solution is to use expression objects. More or less
the entire reason for their existence is this sort of surprises.

plot(y ~ x, data = list(x = 1:10, y = 1:10), main =
as.expression(substitute(alpha==a, list(a=2))))

I'm not going to investigate why this is necessary in connection with
plot(), but the core issue is probably

> e <- quote(f(x)) ; e[[2]] <- quote(2+2)
> e
f(2 + 2)
> f <- quote(f(2+2))
> identical(e,f)
[1] TRUE

notice that since the two calls are identical, there is no way for e to
detect that it was called with x replaced by an object of mode "call".
Or put differently, objects of mode call tend to lose their
"personality" in connection with computing on the language.

--
O__  ---- Peter Dalgaard             Øster Farimagsgade 5, Entr.B
c/ /'_ --- Dept. of Biostatistics     PO Box 2099, 1014 Cph. K
(*) \(*) -- University of Copenhagen   Denmark          Ph:  (+45) 35327918
~~~~~~~~~~ - (p.dalgaard at biostat.ku.dk)                  FAX: (+45) 35327907