[R] controlling panel.width and panel.height in viewports

Deepayan Sarkar deepayan.sarkar at gmail.com
Sun Mar 25 21:34:41 CEST 2007


On 3/25/07, mike townsley <m.townsley at ucl.ac.uk> wrote:
> Dear all,
>
> I'm trying to get a series of lattice levelplots to appear in
> viewports in a particular way but struggling to exert fine control
> over their appearence.  There are two conditions: (a) I only want the
> levelplot to appear (I don't want axes, colour key, etc) in the
> viewport and (b) I want the levelplot to expand to the maximum
> allowable space in the viewport while observing the aspect ratio of the plot.
>
> Condition (a) is OK, but (b) is giving me trouble.  A toy example is:
>
> library(lattice)
> library(grid)
>
> x <- 1:10
> y <- 1:10
> grid <- expand.grid(x=x, y=y)
> grid$z <- grid$x*grid$y
>
> asp.ratio.1 <- 2
> asp.ratio.2 <- .5
> asp.ratio.3 <- 1
>
> test.1 <- levelplot(z~x*y, grid, cuts = 5, xlab="", axes = FALSE,
>                      aspect = asp.ratio.1, ylab="", main='', sub="",
>                      colorkey = FALSE, region = TRUE, scales =
> list(draw = FALSE))
> test.2 <- levelplot(z~x*y, grid, cuts = 5, xlab="", axes = FALSE,
>                      aspect = asp.ratio.2, ylab="", main='', sub="",
>                      colorkey = FALSE, region = TRUE, scales =
> list(draw = FALSE))
> test.3 <- levelplot(z~x*y, grid, cuts = 5, xlab="", axes = FALSE,
>                      aspect = asp.ratio.3, ylab="", main='', sub="",
>                      colorkey = FALSE, region = TRUE, scales =
> list(draw = FALSE))
>
> # so the three basic types of plot I will have
>
>
> toy.vp <- viewport(width = .8, height = .8, just = 'centre',
>                         name = 'toy')  # this is for my levelplot
>
> X11()
> pushViewport(toy.vp)
> grid.rect(gp = gpar(col = 'grey'))
> print(test.1, newpage = FALSE)
>
> X11()
> pushViewport(toy.vp)
> grid.rect(gp = gpar(col = 'grey'))
> print(test.2, newpage = FALSE)
>
> X11()
> pushViewport(toy.vp)
> grid.rect(gp = gpar(col = 'grey'))
> print(test.3, newpage = FALSE)
>
>
> I want to get rid of the space (margins) around the longest axis for
> each variety of levelplot.  So I tried to capture the viewport height
> and width and print the levelplot within a region which reflects the
> aspect ratio of the plot.  I run into an error message as below:
>
> width.vp <- convertWidth(grobWidth(grid.rect()), 'cm')
> height.vp <- convertWidth(grobHeight(grid.rect()), 'cm')
>
> width.vp;height.vp # this works
>
> if(asp.ratio.1 < 1) {height.vp <-
> unit(as.numeric(height.vp)*asp.ratio.1, "cm")}
> if(asp.ratio.1 > 1) {width.vp <- unit(as.numeric(width.vp)/asp.ratio.1, "cm")}
>
> width.vp;height.vp # this also work (ie returns expected results)
>
> print(test.1, panel.width = list(width.vp), panel.height=list(height.vp))
>
> the above command returns this error message:
>
> Error in Ops.unit(panel.height[[1]], panel.width[[1]]) :
>          Operator '/' not meaningful for units
>
> What have I missed?

The part in ?print.trellis which says:

panel.width, panel.height: lists with 2 components, that should be
          valid 'x' and 'units' arguments to 'unit()'

You are specifying "unit" objects directly, which is not supported.
You probably wanted to do something like the following:

######
toy.vp <- viewport(width = .8, height = .8, just = 'centre',
                   name = 'toy')  # this is for my levelplot

grid.newpage()
pushViewport(toy.vp)
grid.rect(gp = gpar(col = 'grey'))

width.vp <- convertWidth(grobWidth(grid.rect(draw = FALSE)), 'cm',
valueOnly = TRUE)
height.vp <- convertWidth(grobHeight(grid.rect(draw = FALSE)), 'cm',
valueOnly = TRUE)

if(asp.ratio.1 < 1) height.vp <- as.numeric(height.vp) * asp.ratio.1
if(asp.ratio.1 > 1) width.vp <- as.numeric(width.vp)/asp.ratio.1
width.vp;height.vp

print(test.1,
      panel.width = list(width.vp, "cm"),
      panel.height=list(height.vp, "cm"),
      newpage = FALSE)
######

This runs, but doesn't give you what you want (I haven't tried to
figure out why).

I think you are taking the wrong approach to your problem. levelplot()
is a high level function, it's not supposed to be used this way. On
the other hand, you do have the ``low-level'' function
panel.levelplot, which _is_ designed to do things inside a grid
viewport. You could even avoid the necessary setup steps by getting
the relevant information by querying your "trellis" object, e.g.:

######

grid.newpage()

toy.vp <-
    viewport(width = .8, height = .8,
             just = 'centre',
             layout = # necessary to fix aspect ratio
             grid.layout(1, 1,
                         widths = 1,
                         heights = asp.ratio.1,
                         respect = TRUE),
             name = 'toy')

pushViewport(toy.vp)

grid.rect(gp = gpar(col = 'grey'))

pushViewport(viewport(layout.pos.row = 1, layout.pos.col = 1,
                      xscale = test.1$x.limits,
                      yscale = test.1$y.limits))

do.call("panel.levelplot", trellis.panelArgs(test.1, 1))

upViewport(2)

######

Hope that helps,

-Deepayan



More information about the R-help mailing list