[Rd] unexpected behavior of `[<-` method for class unit.arithmetic

baptiste auguie baptiste.auguie at googlemail.com
Fri Sep 25 16:09:52 CEST 2009


Further to my previous message, I just dug this in lattice/R/layout.R :


rearrangeUnit <- function(x, pos, u)
{
    lx <- length(x)
    if (lx == 1)
        u
    else if (pos == 1)
        unit.c(u, x[(pos+1):lx])
    else if (pos == lx)
        unit.c(x[1:(pos-1)], u)
    else
        unit.c(x[1:(pos-1)], u, x[(pos+1):lx])
}


w = unit.c(unit(1, "in"), unit(2, "in"))
w2 = w + unit(1, "mm")

rearrangeUnit(w2, 2, unit(0, "mm"))

Definitely a much prettier trick than mine.


Best,

baptiste




2009/9/25 baptiste auguie <baptiste.auguie at googlemail.com>:
> Dear Paul and others,
>
> Thanks for the quick response.
>
> 2009/9/25 Paul Murrell <p.murrell at auckland.ac.nz>:
>> Hi
>>
>> The bit you found that says ...
>>
>> # Write "[<-.unit" methods too ??
>>
>> ... is the crucial bit.
>>
>
> When I figured that, I had already written up my email so I thought
> I'd ask anyway from a naive user point of view (in this regard,
> perhaps the help page of unit.c could mention what common methods are
> not available). The results I got can be quite surprising at first.
>
>
>> Would it be possible to add such a method?
>>
>> Almost certainly, it just needs someone to repeatedly bug the person who can
>> make the change :)   Thanks for the suggestion for code BTW;  I'll take a
>> look at that.
>
> I'm afraid I won't be of much help here, I merely copied and pasted
> the "[.unit" method with a minimal change that seemed to make it work
> for illustrative purposes. I don't really understand unit.arithmetic
> and unit in general.
>
>> In the meantime, the fact that this has only come up once before, while
>> surprising, suggests that people may have written code in a different style.
>
> Either that or people have struggled to find their own workaround
> every time. I've recently hacked a fake matrix of unit objects, where
> perhaps a proper implementation would find other grateful users.
> (Given a list of grobs, I needed to compute rowMax and colMax of their
> size in a rectangular arrangement -- see example below, also as a
> recent post on r-help).
>
>>  Can you give a succinct example that demonstrates a situation where you
>> want to assign to a subset of a unit (rather than, say, calculating values,
>> setting some to 0, then building a unit from the values) ?
>>
>
> Though not as succinct as I'd like, I think the drawDetails method of
> tableGrob[*] might present the problem:
>
> drawDetails.table <- function(x, recording=TRUE){
>
> # makeTableGrobs returns lists of grobs, and their width and height in
> a rectangular layout
>  lg <- with(x, makeTableGrobs(as.character(as.matrix(d)), rows, cols,
>         nrow(d), ncol(d),
>         equal.width = equal.width, equal.height = equal.height,
>         gpar.content = gpar.content,
>         gpar.col = gpar.col,
>         gpar.row = gpar.row,
>         gpar.fill = gpar.fill,
>         gpar.rowfill = gpar.rowfill,
>         gpar.colfill = gpar.colfill )  )
>
> # now I need to add some horizontal and vertical padding to each cells,
> # EXCEPT for the rownames and colnames if they are not to be shown
> # whereby I convert everything to raw values, use normal vector indexing,
> # and convert back to unit
>
>  widthsv <- convertUnit(lg$widths + x$padding.h, "mm", valueOnly=TRUE)
>  heightsv <- convertUnit(lg$heights + x$padding.v, "mm", valueOnly=TRUE)
>
>  widthsv[1] <- widthsv[1] * as.numeric(x$show.rownames)
>  widths <- unit(widthsv, "mm")
>
>  heightsv[1] <- heightsv[1] * as.numeric(x$show.colnames)
>  heights <- unit(heightsv, "mm")
>
> # once this is done, I can create the layout
>  cells = viewport(name="table.cells", layout =
>    grid.layout(lg$nrow+1, lg$ncol+1, width=widths, height=heights) )
>
> # and place the elements
>  pushViewport(cells)
>  tg <- arrangeTableGrobs(lg$lgt, lg$lgf, lg$nrow, lg$ncol, lg$widths,
> lg$heights,
>          padding.h = x$padding.h, padding.v = x$padding.v,
>          separator=x$separator, show.box=x$show.box,
>          show.csep=x$show.csep, show.rsep=x$show.rsep)
>  upViewport()
> }
>
> Of course I could make the calculation of adding padding to the cells
> earlier in the chain (in makeTableGrobs) but it's not really its
> place.
>
> Best,
>
> baptiste
>
> [*]: http://code.google.com/p/gridextra/source/browse/trunk/R/tableGrob.r
>
> to be run as,
> either,
>
> library(grid)
> source("http://gridextra.googlecode.com/svn/trunk/R/grob-utils.r")
> source("http://gridextra.googlecode.com/svn/trunk/R/tableGrob.r")
>
> grid.table(head(iris))
>
> or simply,
>
> Install http://gridextra.googlecode.com/files/gridextra_0.3.tar.gz
>
> library(gridextra)
> example(tableGrob)
>
>> Paul
>>
>>
>> baptiste auguie wrote:
>>>
>>> Dear list,
>>>
>>> Consider the following,
>>>
>>> library(grid)
>>>
>>> w = unit.c(unit(1, "in"), unit(2, "in"))
>>> w2 = w + unit(1, "mm")
>>>
>>> w[2] <- 0
>>> w2[2] <- 0
>>>
>>> convertUnit(w, "mm")
>>> #[1] 25.4mm 0mm
>>> convertUnit(w2, "mm")
>>> #Error in grid.Call("L_convert", x, as.integer(whatfrom),
>>> as.integer(whatto),  :
>>> #  INTEGER() can only be applied to a 'integer', not a 'NULL'
>>>
>>> The last line fails, as the naive replacement has destroyed the
>>> structure of w2 instead of having assigned a value of 0 to the second
>>> unit element.
>>>
>>> I've also tried,
>>>
>>> w = unit.c(unit(1, "in"), unit(2, "in"))
>>> w2 = w + unit(1, "mm")
>>> w2[[2]][2] <- 0
>>>
>>> but this time, if the structure is licit, it's the result that's not
>>> as I intended:
>>>
>>> convertUnit(w2,"mm")
>>> #[1] 26.4mm 1mm
>>>
>>> My limited understanding is that an object of class unit.arithmetic is
>>> waiting until the last moment to actually perform its operation,
>>> stored in a tree-like structure. With this premise, I can't think of a
>>> good way to modify one element of a list of unit elements.
>>>
>>> As a workaround, I can only think of the following hack where the
>>> objects are forced to be evaluated,
>>>
>>> w = unit.c(unit(1, "in"), unit(2, "in"))
>>> w2 = convertUnit(w + unit(1, "mm"), "mm", valueOnly=TRUE)
>>> w2[2] <- 0
>>> w2 <- unit(w2, "mm")
>>>
>>> but it clearly isn't a very desirable route.
>>>
>>> What is the recommended way to modify one element of a unit vector?
>>>
>>> Digging in grid/R/unit.R , I found the following comment,
>>>
>>> # Write "[<-.unit" methods too ??
>>>
>>> which probably explains the above. Would it be possible to add such a
>>> method,
>>>
>>> "[<-.unit.list" <- function(x, index, value, top=TRUE, ...) {
>>>  this.length <- length(x)
>>>    index <- (1L:this.length)[index]
>>>
>>>  if (top && any(index > this.length))
>>>    stop("Index out of bounds (unit list subsetting)")
>>>  cl <- class(x)
>>>  result <- unclass(x)
>>>  result[(index - 1) %% this.length + 1] <- value
>>>  class(result) <- cl
>>>  result
>>> }
>>>
>>> a = unit.c(unit(1,"mm"),unit(2,"in"))
>>> a[2] <- unit(3,"in")
>>> a
>>>
>>> but for unit.arithmetic also?
>>>
>>> Regards,
>>>
>>> baptiste
>>>
>>> sessionInfo()
>>> R version 2.9.2 (2009-08-24)
>>> i386-apple-darwin8.11.1
>>>
>>> locale:
>>> en_GB.UTF-8/en_GB.UTF-8/C/C/en_GB.UTF-8/en_GB.UTF-8
>>>
>>> attached base packages:
>>> [1] stats     graphics  grDevices utils     datasets  grid      methods
>>> [8] base
>>>
>>> ______________________________________________
>>> R-devel at r-project.org mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>> --
>> Dr Paul Murrell
>> Department of Statistics
>> The University of Auckland
>> Private Bag 92019
>> Auckland
>> New Zealand
>> 64 9 3737599 x85392
>> paul at stat.auckland.ac.nz
>> http://www.stat.auckland.ac.nz/~paul/
>>
>



More information about the R-devel mailing list