Grid.layout does not like respectful and compound units

Using unit.pmax as the default width / height comparison in gtable is more complicated than I had hoped; after hours of scratching my head, I narrowed it down to this situation:

 library(grid) w <- list(unit(1,"null"), unit(1,"null")) class(w) <- c("unit.list", "unit") h <- unit(1, "in") gl1 <- grid.layout(1, 2, widths = w, heights = h, respect = TRUE) grid.newpage() grid.show.layout(gl1) # fine w2 <- w w2[[1]] <- unit.pmax(unit(1,"null"), unit(1,"null")) gl2 <- grid.layout(1, 2, widths = w2, heights = h, respect = FALSE) grid.newpage() grid.show.layout(gl2)# fine gl3 <- grid.layout(1, 2, widths = w2, heights = h, respect = TRUE) grid.newpage() grid.show.layout(gl3) ## Error in grid.Call.graphics(L_setviewport, vp, TRUE) : ## non-finite location and/or size for viewport 

so the combination of unit.pmax(unit(1,"null"), unit(1,"null")) and respect = TRUE makes the grid complain. If you are interested, this situation would occur in ggplot2 with facet_grid and theme(aspect.ratio = ...) .

I can vaguely imagine that unit.pmax() should simplify null units before trying to use the respect parameter, but I really don't know what all this means. In practice, however, this prevents me from improving the gtable cbind / rbind.

Any workaround?

Edit: I'm not sure how to provide a minimal ggplot2 example ggplot2 than installing my plug and running

 ggplot(data.frame(x=1:8, y=1:8, f=gl(2,4)), aes(x, y)) + geom_point() + facet_grid(f~.) + theme(aspect.ratio=3) # Error in grid.Call.graphics(L_setviewport, vp, TRUE) : # non-finite location and/or size for viewport 

therefore unit.pmax() fails in this case, while the current comparison method compare.unit(,,pmax) fails in other situations, for example,

 p1 = qplot(1, 1); p2 = qplot(1,1) cbind(ggplotGrob(p1), ggplotGrob(p2), size="max") # Error in mmm < each : comparison of these types is not implemented 
+7
r ggplot2 r-grid gtable
source share
2 answers

Solving the problem with Paul Merrell at R-devel @ r65845 seems to solve the problem. Unfortunately, this means that upgrading to gtable should wait at least for the next R version (and possibly much longer, since ggplot2 dev usually takes a conservative approach to supporting older versions).

+2
source share

This is not optimal, but if all else fails, you can simply rewrite unit.pmax so that it does what you want.

The following function acts just like unit.pmax() , except that whenever it requests the maximum maximum of two or more unit objects, all in units of "null" , it returns its value of "largest", not the expression forms max(x,y,...) . (See second code example below).

 unit.pmax2 <- function (...) { select.i <- function(unit, i) { unit[i, top = FALSE] } x <- list(...) numargs <- length(x) if (numargs == 0L) stop("no arguments where at least one expected") maxlength <- 0L for (i in seq_len(numargs)) if (length(x[[i]]) > maxlength) maxlength <- length(x[[i]]) ## result <- max(unit.list.from.list(lapply(x, select.i, 1L))) UL <- grid:::unit.list.from.list(lapply(x, select.i, 1L)) ## result <- if(all(sapply(UL, attr, "unit")=="null")) { ## UL[which.max(UL)]} else {max(UL)} ## if (maxlength > 1L) for (i in 2L:maxlength) { ## result <- unit.c(result, max(unit.list.from.list(lapply(x, ## select.i, i)))) UL <- grid:::unit.list.from.list(lapply(x, select.i, i)) ## temp <- if(all(sapply(UL, attr, "unit")=="null")) { ## UL[which.max(UL)]} else {max(UL)} ## result <- unit.c(result, temp) ## } result } 

To see the difference between unit.pmax() and unit.pmax2() , compare:

 A <- list(unit(1,"null"), unit(1,"null"), unit(1,"null")) B <- list(unit(1,"null"), unit(4,"null"), unit(1,"null")) C <- list(unit(1,"null"), unit(2,"null"), unit(1,"inch")) class(A) <- class(B) <- class(C) <- c("unit.list", "unit") unit.pmax(A, B, C) # [1] max(1null, 1null, 1null) max(1null, 4null, 2null) max(1null, 1null, 1inch) unit.pmax2(A, B, C) # [1] 1null 4null max(1null, 1null, 1inch) 

Testing showed that it works. (Note that you also need to replace w2[[1]] <- ... with w2[1] <- ... to avoid a complaint if respect = TRUE .)

 library(grid) w2 <- list(unit(1,"null"), unit(1,"null")) class(w2) <- c("unit.list", "unit") h <- unit(1, "in") w2[1] <- unit.pmax2(unit(1,"null"), unit(1,"null")) ## w2[[1]] <- unit.pmax(unit(1,"null"), unit(1,"null")) ## For comparison gl3 <- grid.layout(1, 2, widths = w2, heights = h, respect = TRUE) grid.newpage() grid.show.layout(gl3) 

enter image description here

+2
source share

All Articles