mike townsley
2007-Mar-25 12:24 UTC
[R] controlling panel.width and panel.height in viewports
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? Thanks in advance, MT ------------------------------------------------------------ Dr Michael Townsley Senior Research Fellow Jill Dando Institute of Crime Science University College London Second Floor, Brook House London, WC1E 7HN Phone: 020 7679 0820 Fax: 020 7679 0828 Email: m.townsley at ucl.ac.uk
Deepayan Sarkar
2007-Mar-25 19:34 UTC
[R] controlling panel.width and panel.height in viewports
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