Search code examples
rplot

How get three base plots with miniplot inside on one panel with different widths?


Using layout, I can easily create panels.

op <- par(no.readonly = TRUE)
layout(matrix(1:3, nrow=1), widths=c(.8, 1.1, .8))
plot(1:20, 1:20, pch=19, cex=2, col=colfunc(20))
plot(1:20, 1:20, pch=19, cex=2, col=colfunc(20))
plot(1:20, 1:20, pch=19, cex=2, col=colfunc(20))
par(op)

enter image description here

However, when creating a plot with miniplot inside, such as a gradient,

plotfun <- \() {
  colfunc <- colorRampPalette(c("red", "blue"))
  plot(1:20, 1:20, pch=19, cex=2, col=colfunc(20))
  fig. <- c(grconvertX(c(.1, 5), from="user", to="ndc"), 
            grconvertY(c(8, 19), from="user", to="ndc"))
  op <- par(fig=fig., mar=c(1, 1, 1, 1), new=TRUE)
  plot.window(c(0, 1), c(0, 1))
  rasterImage(as.raster(matrix(colfunc(20), ncol=1)), 0, 0, 1, 1)
  lbsq <- seq.int(0, 1, l=5)
  axis(4, at=lbsq, pos=0, labels=FALSE, col=0, col.ticks=1, tck=-.1)
  mtext(lbsq, 4, .5, at=lbsq, las=2, cex=.6)
  mtext('foo', 3, 0, cex=.6, adj=.5, font=2)
  par(op)
}

it leaves the layout.

op <- par(no.readonly=TRUE)
layout(matrix(1:3, nrow=1), widths=c(.8, 1.1, .8))
plotfun()
plotfun()
plotfun()
par(op)

enter image description here

I'm aware that layout is "totally incompatible with ... par(mfrow)". But I already tried par() which also didn't work. Anyway I need something like layout since I have different widths. Any clues, how to do it?


Solution

  • We can use split.screen() with a matrix in the figs= argument. To obtain similar segmentation as in layout, we calculate the cumsum of the widths=, that we first precede with a zero and normalize to get "nfc',

    > c(0, c(.8, 1.1, .8)) |> cumsum() |> normalize() |> round(1)
    [1] 0.0 0.3 0.7 1.0
    

    and make a matrix out of it, as nicely explained in this answer.

    > split.screen(matrix(c(0, .3, .7, 
    +                       .3, .7, 1, 
    +                       0, 0, 0, 
    +                       1, 1, 1), 3))
    [1] 7 8 9
    > screen(1)
    > plotfun()
    > screen(2)
    > plotfun()
    > screen(3)
    > plotfun()
    

    enter image description here

    We can still use things like par(mar=) in the individual plots.