[Rd] substitute and expression (Peter Dalgaard)

John Maindonald john.maindonald at anu.edu.au
Thu Jul 19 12:15:59 CEST 2007


In this connection, note the following

 > a4 <- 4
 > plotThis <- bquote(alpha==.(a), list(a=a4))
 > do.call(plot, list(1:10, main=do.call(expression, c(plotThis))))
 > do.call(plot, list(1:10, main=do.call(expression, plotThis)))
Error in do.call(expression, plotThis) : second argument must be a list

 > ## Whereas plotThis has class "call", c(plotThis) has class "list"
 > class(plotThis)
[1] "call"
 > class(c(plotThis))
[1] "list"

 > ## Thus, the following is possible:
 > do.call(plot, list(1:10, main=do.call(expression, list(plotThis))))


Marc Schwartz pointed out to me., some considerable time ago,
that one could use bquote() and .() to create the elements of a
list object whose elements can be plotted in parallel as required,
e.g., for axis labels, thus:

 > plot(1:2, 1:2, xaxt="n")
 > arg1 <- bquote(""< .(x), list(x=1.5))
 > arg2 <- bquote("">= .(x), list(x=1.5))
 > axis(1, at=1:2, labels=do.call(expression, list(arg1, arg2)))

For a unified approach to use of do.call(expression, ...), maybe
one should use bquote() and .()?

John Maindonald             email: john.maindonald at anu.edu.au
phone : +61 2 (6125)3473    fax  : +61 2(6125)5549
Centre for Mathematics & Its Applications, Room 1194,
John Dedman Mathematical Sciences Building (Building 27)
Australian National University, Canberra ACT 0200.


On 18 Jul 2007, at 8:00 PM, r-devel-request at r-project.org wrote:

> From: Peter Dalgaard <P.Dalgaard at biostat.ku.dk>
> Date: 18 July 2007 1:39:50 AM
> To: Deepayan Sarkar <deepayan.sarkar at gmail.com>
> Cc: R Development Mailing List <r-devel at stat.math.ethz.ch>
> Subject: Re: [Rd] substitute and expression
>
>
> 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))))
>>>>>
>>>>>
>>>> Error in as.graphicsAnnot(main) : object "alpha" not found
>>>>
>>>> (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)))) :
>>>         object "alpha" not found
>>>
>>> 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))
>>>
>> Error in as.graphicsAnnot(main) : object "alpha" not found
>>
>> 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



More information about the R-devel mailing list