Re: [Rd] Re: [R] Problem going back to a viewport with gridBase

From: Gabor Grothendieck <ggrothendieck_at_gmail.com>
Date: Thu 02 Jun 2005 - 21:03:42 GMT

On 6/1/05, Paul Murrell <p.murrell@auckland.ac.nz> wrote:
> Hi
>
>
> Gabor Grothendieck wrote:
> > [moved from r-help to r-devel]
> >
> > On 5/31/05, Paul Murrell <p.murrell@auckland.ac.nz> wrote:
> >
> >
> >>> # mm.row[j] gives the row in the layout of the jth cell
> >>> # mm.col[j] gives the col in the layout of the jth cell
> >>> mm <- matrix(seq(nr*nc), nr, nc)
> >>> mm.row <- c(row(mm))
> >>> mm.col <- c(col(mm))
> >>>
> >>> # go to next cell in the array
> >>> j <- j + 1 # increment position
> >>> pushViewport(viewport(layout.pos.row = mm.row[j], layout.pos.col = mm.col[j]))
> >>>
> >>>Is that how to do it or is there some layout/mfcol-like way?
> >>
> >>
> >>That is how to do it.
> >>
> >>As far as grid is concerned, all viewports are equal and grid has no
> >>idea whether a viewport corresponds to a "plot region" or a "margin" or
> >>whatever, so grid has no concept of which viewport is the "next" one to use.
> >>
> >
> >
> > 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()
> > }
>
>
> 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)
> }
> }
>
>
> > 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)))
>
>
> 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))
> }
> }
>

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 )     )



R-devel@stat.math.ethz.ch mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel Received on Fri Jun 03 07:11:14 2005

This archive was generated by hypermail 2.1.8 : Mon 24 Oct 2005 - 22:26:57 GMT