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.aug...@googlemail.com>: > Dear Paul and others, > > Thanks for the quick response. > > 2009/9/25 Paul Murrell <p.murr...@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@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 >> p...@stat.auckland.ac.nz >> http://www.stat.auckland.ac.nz/~paul/ >> > ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel