[R] packGrob and dynamic resizing

baptiste auguie baptiste.auguie at googlemail.com
Fri Sep 25 14:55:52 CEST 2009


Thank you Paul, I was convinced I tried this option but I obviously didn't!

In ?packGrob, the user is warned that packing grobs can be slow. In
order to quantify this, I made the following comparison of 3
functions,

- table1 uses frameGrob and packGrob
- table2 uses frameGrob but calculates the sizes manually and uses placeGrob
- table3 creates a grid.layout and draws the grobs in the different viewports.

The three functions have (almost) the same output, but the timing does
differ quite substantially !

 system.time(table1(content))
#   user  system elapsed
# 126.733   2.414 135.450
system.time(table2(content))
#   user  system elapsed
# 22.387   0.508  24.457
 system.time(table3(content))
#   user  system elapsed
#  4.868   0.124   5.695

A few questions:

- why should the placeGrob approach of table2 be 5 times slower than
table3 (pushing viewports) ?

- if so, what are the merits of using a frameGrob over creating a
layout "manually"?

- can one add some padding to the content placed with a placeGrob approach?


Best regards,

baptiste

The code follows below,

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

############### code starts #######
library(grid)

# a few helping functions

rowMax.units <- function(u, nrow){ # rowMax with a fake matrix of units
  matrix.indices <- matrix(seq_along(u), nrow=nrow)
  do.call(unit.c, lapply(seq(1, nrow), function(ii) {
   max(u[matrix.indices[ii, ]])
  }))
}

colMax.units <- function(u, ncol){ # colMax with a fake matrix of units
  matrix.indices <- matrix(seq_along(u), ncol=ncol)
  do.call(unit.c, lapply(seq(1, ncol), function(ii) {
   max(u[matrix.indices[, ii]])
  }))
}


textii <- function(d, gp=gpar(), name="row-label-"){
  function(ii)
textGrob(label=d[ii], gp=gp, name=paste(name, ii, sep=""))
}

# create a list of text grobs from a data.frame
makeContent <- function(d){
content <- as.character(unlist(c(d)))

 makeOneLabel <- textii(d=content, gp=gpar(col="blue"), name="content-label-")
 lg <- lapply(seq_along(content), makeOneLabel)

list(lg=lg, nrow=nrow(d), ncol=ncol(d))
}

#### the comparison starts here ####

## table1 uses grid.pack
table1 <- function(content){

  	gcells = frameGrob(name="table.cells",
		layout = grid.layout(content$nrow, content$ncol))
		
   label.ind <- 1   # index running accross labels
	
	for (ii in seq(1, content$ncol, 1)) {
		for (jj in seq(1, content$nrow, 1)) {
		gcells = packGrob(gcells, content$lg[[label.ind]], row=jj, col=ii,
dynamic=TRUE)
                label.ind <- label.ind + 1
              }
            }
        grid.draw(gTree(children=gList(gcells)))
}

## table2 uses grid.place
table2 <- function(content){

padding <- unit(4, "mm")
 lg <- content$lg
 ## retrieve the widths and heights of all textGrobs (including some zeroGrobs)
  wg <- lapply(lg, grobWidth) # list of grob widths
  hg <- lapply(lg, grobHeight) # list of grob heights

 ## concatenate this units
  widths.all <- do.call(unit.c, wg) # all grob widths
  heights.all <- do.call(unit.c, hg)    #all grob heights

 ## matrix-like operations on units to define the table layout
  widths <- colMax.units(widths.all, content$ncol)  # all column widths
  heights <- rowMax.units(heights.all, content$nrow)  # all row heights

  	gcells = frameGrob(name="table.cells",
		layout = grid.layout(content$nrow, content$ncol,
                  width=widths+padding, height=heights+padding))
		
   label.ind <- 1   # index running accross labels
	
	for (ii in seq(1, content$ncol, 1)) {
		for (jj in seq(1, content$nrow, 1)) {
		gcells = placeGrob(gcells, content$lg[[label.ind]], row=jj, col=ii)
                label.ind <- label.ind + 1
              }
            }
        grid.draw(gTree(children=gList(gcells)))

}

## table3 uses grid.layout
table3 <- function(content){

padding <- unit(4, "mm")
 lg <- content$lg
 ## retrieve the widths and heights of all textGrobs (including some zeroGrobs)
  wg <- lapply(lg, grobWidth) # list of grob widths
  hg <- lapply(lg, grobHeight) # list of grob heights

 ## concatenate this units
  widths.all <- do.call(unit.c, wg) # all grob widths
  heights.all <- do.call(unit.c, hg)    #all grob heights

 ## matrix-like operations on units to define the table layout
  widths <- colMax.units(widths.all, content$ncol)  # all column widths
  heights <- rowMax.units(heights.all, content$nrow)  # all row heights

  cells = viewport(name="table.cells", layout =
    grid.layout(content$nrow, content$ncol,
                width=widths+padding, height=heights+padding) )

  pushViewport(cells)

   label.ind <- 1   # index running accross labels

  ## loop over columns and rows
  for (ii in seq(1, content$ncol, 1)) {
    for (jj in seq(1, content$nrow, 1)) {
      ## push a viewport for cell (ii,jj)
     pushViewport(vp=viewport( layout.pos.row=jj, layout.pos.col=ii))
     grid.draw( lg[[label.ind]])       # draw the text
     upViewport()

     label.ind <- label.ind + 1
    }
  }
  upViewport()
}

content <- makeContent(head(iris))
# uncomment for timing
# content <- makeContent(iris)

 pdf("test-layout.pdf", height=45)
 system.time(table1(content))
#   user  system elapsed
# 126.733   2.414 135.450
grid.newpage()
system.time(table2(content))
#   user  system elapsed
# 22.387   0.508  24.457
 grid.newpage()
 system.time(table3(content))
#   user  system elapsed
#  4.868   0.124   5.695
 dev.off()


############### code ends #######
#system("open test-layout.pdf")





2009/9/25 Paul Murrell <p.murrell at auckland.ac.nz>:
> Hi
>
>
> baptiste auguie wrote:
>>
>> Dear all,
>>
>> I'm trying to follow an old document to use Grid frames,
>>
>> Creating Tables of Text Using grid
>> Paul Murrell
>> July 9, 2003
>>
>>  As a minimal example, I wrote this,
>>
>> gf <- grid.frame(layout = grid.layout(1, 1), draw = TRUE)
>>  label1 <- textGrob("test", x = 0, just = "left", name="test")
>>
>> gf=placeGrob(gf, rectGrob(), row = 1, col = 1)
>> gf=packGrob(gf, label1, row = 1, col = 1)
>
>
> You need 'dynamic=TRUE' in the call to packGrob() if you want the automatic
> updating.
>
> Paul
>
>
>> grid.draw(gf)
>>
>> grid.edit("test", label = "longer text", grep=T)
>>
>> I'm a bit lost here, as I was expecting the frame to be automatically
>> adjusted to fit the new text.
>>
>> Can anyone point me in the right direction?
>>
>> Best regards,
>>
>> baptiste
>>
>> ______________________________________________
>> R-help at r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-help
>> PLEASE do read the posting guide
>> http://www.R-project.org/posting-guide.html
>> and provide commented, minimal, self-contained, reproducible code.
>
> --
> 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-help mailing list