Using grid.layout inside grid.layout with grid package: weird impact of plotting order

392 views Asked by At

I want to plot such an image with some base graphics inside the stacked rectangles.

enter image description here

I have a plotting function to produce the plots with the stacked plots (here rectangles):

stackedplot <- function(main=""){

  top.vp <- viewport(
    layout=grid.layout(5, 2,
                       widths=unit(c(2, 1), c("lines", "null")),
                       heights=unit(c(3, 1, 1, 1, 5), 
                                    c("lines", "null", "null", "null", "lines"))))
  p1 <- viewport(layout.pos.col=2, layout.pos.row=2, name="plot1",
                 default.units="native")
  p2 <- viewport(layout.pos.col=2, layout.pos.row=3, name="plot2",
                 default.units="native")
  p3 <- viewport(layout.pos.col=2, layout.pos.row=4, name="plot3",
                 default.units="native")
  xaxis <- viewport(layout.pos.col=2, layout.pos.row=5, name="xaxis")
  label1 <- viewport(layout.pos.col=1, layout.pos.row=2, name="label1")
  label2 <- viewport(layout.pos.col=1, layout.pos.row=3, name="label2")
  label3 <- viewport(layout.pos.col=1, layout.pos.row=4, name="label3")
  title <- viewport(layout.pos.col=2, layout.pos.row=1, name="title")

  splot <- vpTree(top.vp, vpList(p1,p2,p3,xaxis,label1,label2,label3,title))
  pushViewport(splot)

  seekViewport("plot1")
  # par(plt=gridPLT()) # Needed for plotting base graphics, but not here
  grid.rect(width=unit(0.9, "npc")) # This to be replaced with a base graphics plot in the final version

  seekViewport("plot2")
  # par(plt=gridPLT())
  grid.rect(width=unit(0.9, "npc"))

  seekViewport("plot3")
  # par(plt=gridPLT())
  grid.rect(width=unit(0.9, "npc"))

  seekViewport("xaxis")
  grid.text("X label", y = unit(3, "lines"))

  seekViewport("label1")
  grid.text("1", x = unit(2, "lines"), rot=90)
  seekViewport("label2")
  grid.text("2", x = unit(2, "lines"), rot=90)
  seekViewport("label3")
  grid.text("3", x = unit(2, "lines"), rot=90)

  seekViewport("title")
  grid.text(main, y = unit(1, "lines"), gp = gpar(fontsize = 20))
}

For creating a 2x2 grid with four stacked plots I tried to use the following code:

grid.newpage()
multitop.vp <- viewport(layout=grid.layout(2,2))
pl1 <- viewport(layout.pos.col=1, layout.pos.row=1, name="A")
pl2 <- viewport(layout.pos.col=1, layout.pos.row=2, name="B")
pl3 <- viewport(layout.pos.col=2, layout.pos.row=1, name="C")
pl4 <- viewport(layout.pos.col=2, layout.pos.row=2, name="D")
vpall <- vpTree(multitop.vp, vpList(pl1,pl2,pl3,pl4))
pushViewport(vpall)
seekViewport("A")
stackedplot(main="A")
seekViewport("B")
stackedplot(main="B")
seekViewport("C")
stackedplot(main="C")
seekViewport("D")
stackedplot(main="D")

This does not work as all the plots are plotted in the same cell of the grid.

enter image description here

However, if I plot them in a reversed order, I get the figure I want (1st figure).

seekViewport("D")
stackedplot(main="D")
seekViewport("C")
stackedplot(main="C")
seekViewport("B")
stackedplot(main="B")
seekViewport("A")
stackedplot(main="A")

I tried with different names and found out, that if I plot in reversed alphabetical order, everything works fine. Once I try to plot in a viewport with a name earlier in alphabetical order, all other plots thereafter are plotted in the same cell. Why is this happening?

1

There are 1 answers

0
Satu On BEST ANSWER

After some help from the author of the grid package, I am now answering my own question, in case it would be useful to someone else.

My code creates a hierarchy of viewports, where the viewports plot1 and plot2 appear multiple times. The problem comes with using the seekViewport function in such case. It always starts the search for the requested viewport from the root. Then it goes down and finds the first plot1, which is the one below viewport A. A better option is thus to use functions upViewport and downViewport as in the following code.

stackedplot <- function(main=""){

  top.vp <- viewport(
    layout=grid.layout(5, 2,
                       widths=unit(c(2, 1), c("lines", "null")),
                       heights=unit(c(3, 1, 1, 1, 5), 
                                    c("lines", "null", "null", "null", "lines"))))
  p1 <- viewport(layout.pos.col=2, layout.pos.row=2, name="plot1",
                 default.units="native")
  p2 <- viewport(layout.pos.col=2, layout.pos.row=3, name="plot2",
                 default.units="native")
  p3 <- viewport(layout.pos.col=2, layout.pos.row=4, name="plot3",
                 default.units="native")
  xaxis <- viewport(layout.pos.col=2, layout.pos.row=5, name="xaxis")
  label1 <- viewport(layout.pos.col=1, layout.pos.row=2, name="label1")
  label2 <- viewport(layout.pos.col=1, layout.pos.row=3, name="label2")
  label3 <- viewport(layout.pos.col=1, layout.pos.row=4, name="label3")
  title <- viewport(layout.pos.col=2, layout.pos.row=1, name="title")

  splot <- vpTree(top.vp, vpList(p1,p2,p3,xaxis,label1,label2,label3,title))
  pushViewport(splot)

  upViewport()
  downViewport("plot1")
  grid.rect(width=unit(0.9, "npc"), height=unit(0.9, "npc"))

  upViewport()
  downViewport("plot2")
  grid.rect(width=unit(0.9, "npc"), height=unit(0.9, "npc"))

  upViewport()
  downViewport("plot3")
  grid.rect(width=unit(0.9, "npc"), height=unit(0.9, "npc"))  

  upViewport()
  downViewport("xaxis")
  grid.text("X label", y = unit(3, "lines"))

  upViewport()
  downViewport("label1")
  grid.text("1", x = unit(2, "lines"), rot=90)

  upViewport()
  downViewport("label2")
  grid.text("2", x = unit(2, "lines"), rot=90)

  upViewport()
  downViewport("label3")
  grid.text("3", x = unit(2, "lines"), rot=90)


  upViewport()
  downViewport("title")
  grid.text(main, y = unit(1, "lines"), gp = gpar(fontsize = 20))

  upViewport(2)
}


grid.newpage()
multitop.vp <- viewport(layout=grid.layout(2,2))
pl1 <- viewport(layout.pos.col=1, layout.pos.row=1, name="A")
pl2 <- viewport(layout.pos.col=1, layout.pos.row=2, name="B")
pl3 <- viewport(layout.pos.col=2, layout.pos.row=1, name="C")
pl4 <- viewport(layout.pos.col=2, layout.pos.row=2, name="D")
vpall <- vpTree(multitop.vp, vpList(pl1,pl2,pl3,pl4))
pushViewport(vpall)
upViewport()
downViewport("A")
stackedplot(main="A")
upViewport()
downViewport("B")
stackedplot(main="B")
upViewport()
downViewport("C")
stackedplot(main="C")
upViewport()
downViewport("D")
stackedplot(main="D")
upViewport(2)