[R] grid(Base): How to avoid "Figure region too small and/or viewport too large" by specifying 'relative' units?

Marius Hofert marius.hofert at math.ethz.ch
Fri Oct 19 12:18:53 CEST 2012

Dear grid-expeRts,

The goal: 
I would like to construct a plot (matrix) with grid and gridBase,
which consists of four "sub-plots". The sub-plots should have a square plotting
region as one would force with par(pty="s") in base graphics.

The problem: 
I don't get a square plotting region, not even by specifying
pty="s" in par(). Indeed, if you display the grid layout by commenting in
"grid.show.layout(gl)" below, you'll see that the grid layout is fine, but the
plot does not seem to respect the layout measurements.

The initial quick-and-dirty hack: 
Use absolute measurements, i.e., specify all
units in inches. This worked perfectly fine for me initially. However, when the
device width and height are not set accordingly (and one can never know what
others specify here -- indeed the problem arose this way), this produces errors
of type "Error in gridPLT() : Figure region too small and/or viewport too

I also found this issue in this post
(https://stat.ethz.ch/pipermail/r-help/2008-December/181993.html), but I am
wondering what's the correct approach towards this problem / how can one specify
"relative" units but guarantee that the grid layout is respected when plotting
is done? [We use this plot in a quite complicated setup and the quick solution
to specify inches and a large enough width/height for the device fails.]




## setup
strg <- LETTERS[1:2] # row variables
t <- c(0.2, 0.8) # column variables

## plot variables (spaces)
pspc <- c(3,3)
spc <- c(0.3, 0.3)
axlabspc <- c(1.2, 0.75)
labspc <- c(0.3, 0.3)

## save plot settings
par. <- par(no.readonly=TRUE)

## set up the grid layout
nx <- 2 # number of sub-plots per column
nx. <- 5 # number of grid rectangles per column
ny <- 2 # number of sub-plots per row
ny. <- 5 # number of grid rectangles per row
plot.new() # start (empty) new page with 'graphics'
gl <- grid.layout(nx., ny., # "2 x 2" grid together with spaces => 5 x 5 grid
                  widths=c(axlabspc[1], rep(c(pspc[1], spc[1]), nx-1), pspc[1], labspc[1]),
                  heights=c(labspc[2], rep(c(pspc[2], spc[2]), ny-1), pspc[2], axlabspc[2]))
## grid.show.layout(gl) # display the layout; use this to see that the sub-plots do not match the layout specification
pushViewport(viewport(layout=gl)) # use this layout in a viewport

## generate dummy data to plot in the four sub-plots
n <- 10
x <- array(NA, dim=c(nx, ny, n))
for(i in 1:2) for(j in 1:2) x[i,j,] <- rep(i,n)+rep(j,n)+runif(n)

## go through the "panels"
for(i in 1:nx) { # rows
    i. <- 2*i # column index in layout (for jumping over gaps)
    yran <- range(x[i,,]) # for forcing the same y-axis within a row
    for(j in 1:ny) { # columns
        j. <- 2*j # row index in layout (for jumping over gaps)
        pushViewport(viewport(layout.pos.row=i., layout.pos.col=j.))

        ## plot
        par(plt=gridPLT()) # start a 'graphics' plot
        par(new=TRUE) # always do this before each new 'graphics' plot
        plot(range(1:n), yran, type="n", ann=FALSE, axes=FALSE) # set up coordinate axes
        points(1:n, x[i,j,], type="b") # actual plot

        ## axes
        if(i==nx) axis(1) # x axis
        if(j==1) axis(2) # y axes

        ## column labels
            pushViewport(viewport(layout.pos.row=1, layout.pos.col=j.))
            grid.text(t[j], x=0.5, y=0.5)

        ## row labels
            pushViewport(viewport(layout.pos.row=i., layout.pos.col=nx.))
            grid.text(strg[i], x=0.5, y=0.5, rot=-90)

## x axis label
pushViewport(viewport(layout.pos.row=ny., layout.pos.col=2:(ny.-1)))
grid.text(expression(gamma), y=unit(0.5, "null"))

## y axis label
pushViewport(viewport(layout.pos.row=2:(nx.-1), layout.pos.col=1))
grid.text(expression(f[gamma]), rot=90, x=unit(0.5, "null"))

## restore plot settings

More information about the R-help mailing list