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

baptiste auguie baptiste.auguie at googlemail.com
Fri Sep 25 10:29:05 CEST 2009


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