Skip to content

Problem going back to a viewport with gridBase

4 messages · Paul Murrell, Gabor Grothendieck

#
[moved from r-help to r-devel]
On 5/31/05, Paul Murrell <p.murrell@auckland.ac.nz> wrote:

            
OK. Thanks.  One suggestion.  Maybe the cells in a layout could have
an order to them and there could be an optional argument that takes a linear
index directly allowing easy linear traversals:

for(i in seq(nr*nc)) {
   pushViewport(viewport(i)) # might need different syntax here
   xyplot(seq(i) ~ seq(i))
   popViewport()
}

and taking it one further perhaps 'with' could have a viewport method 
that automatically pushes the viewport on entry and pops or moves
up one level on exit reducing the above to:

for(i in seq(nr*nc)) with(viewport(i), xyplot(seq(i) ~ seq(i)))
#
Hi
Gabor Grothendieck wrote:
I think this sort of thing can easily be built on top rather than into 
the existing system.  For example, here's a function that pushes all of 
the basic cells in a layout using a simple naming convention:

layoutVPname <- function(i, j) {
   paste("layoutViewport", i, ",", j, sep="")
}

layoutVPpath <- function(i, j, name="layout") {
   vpPath(name, layoutVPname(i, j))
}

pushLayout <- function(nr, nc, name="layout") {
   pushViewport(viewport(layout=grid.layout(nr, nc),
                         name=name))
   for (i in 1:nr) {
     for (j in 1:nc) {
       pushViewport(viewport(layout.pos.row=i,
                             layout.pos.col=j,
                             name=layoutVPname(i, j)))
       upViewport()
     }
   }
   upViewport()
}

And here's a use of the function to push lots of layout cells, then draw 
lattice plots in different cells using downViewport() to go to the cell 
with the appropriate name.  In this case, we use cells by column, but 
simply reverse the order of the loops to use cells by row.

pushLayout(2, 3)
for (i in 1:2) {
   for (j in 1:3){
     depth <- downViewport(layoutVPpath(i, j))
     print(xyplot(seq(i*j) ~ seq(i*j)), newpage=FALSE)
     upViewport(depth)
   }
}
The raw grid functions have a 'vp' argument for this purpose.  It would 
be nice if lattice functions had something similar (or maybe just 
print.trellis).  Here's your example using the 'vp' argument to 
grid.text() (and using the layout that was pushed above) ...

for (i in 1:2) {
   for (j in 1:3){
     grid.text(i*j, vp=layoutVPpath(i, j))
   }
}

Paul
#
On 6/1/05, Paul Murrell <p.murrell@auckland.ac.nz> wrote:
Thanks, again.   I'll try modifying your example to fit my specific
application (which requires a linear column-wise traversal ending 
at the nth cell where n may be less than the number of cells in the
matrix).
#
On 6/1/05, Paul Murrell <p.murrell@auckland.ac.nz> wrote:
The following includes an implementation of 'with.vpPath'.
I got some strange results but by trial and error seem
to have circumvented them yet I am still not sure that I have
the real solution:

1. If I delete the indicated line with the comments
which special-cases ROOT then it gives the error also
shown in the comments.  Why do I have to handle ROOT specially?

2. If I know a viewport how can I find out its vpPath?

3. Will identical code to my with.vpPath work with
viewports if I relabel the name to with.viewport?
Will seekViewport work with viewport too?  The
docs say seekViewport takes a name but it seems
it at least works on a vpPath too. I would like to
be able to hand to 'with' any reasonable
grid object (vpPath, name, viewport, any other objects?)
and have it work as expected.

4. Given a viewport how can one find its vpPath?
its children? its parent?
vp <- current.viewport()
vp$name # this gets name but I want entire vpPath

5. How can I pop everything I have created?  Do
I have to keep track of every viewport and then
visit each one and pop it?

Most of the code below is taken from your post
to me but 'with.vpPath' onward are new.

Thanks.


library(lattice)
library(grid)

layoutVPname <- function(i, j) {
  paste("layoutViewport", i, j, sep= ".")
}

layoutVPpath <- function(i, j, name="layout") {
  vpPath(name, layoutVPname(i, j))
}

pushLayout <- function(nr, nc, name="layout") {
  pushViewport(viewport(layout=grid.layout(nr, nc), name=name))
  for (i in 1:nr) {
    for (j in 1:nc) {
      pushViewport(viewport(layout.pos.row=i,
                            layout.pos.col=j,
                            name=layoutVPname(i, j)))
      upViewport()
    }
  }
  upViewport()
}

with.vpPath <- function(data, expr, ...) {  # modified from drawInVP
   cur <- current.viewport()
   seekViewport(data)
   result <- eval.parent(substitute(expr))
   # if I comment out next line I get this error:
   # Error in downViewport.vpPath(vpPathDirect(name), strict,
recording = recording) :
   #  Viewport 'viewport[ROOT]' was not found
   if (cur$name == "ROOT") upViewport(0) else
   seekViewport(cur)
   invisible(result)
}

grid.newpage()

# specify number of cells to fill and number of rows
n <- 5; nr <- 3

nc <- ceiling(n/nr)
pushLayout(nr, nc)

# each row of coords is a row/col coord for successive cells. i.e.
# traversal of the layout is done by iterating over rows of coords.
coords <- split(expand.grid(row = 1:nr, col = 1:nc)[1:n,], 1:n)

for(k in coords)
    with(layoutVPpath(k$row, k$col),
      print( xyplot(v ~ v, list(v = 1:prod(k))), newpage = FALSE )
    )