Search code examples
rknitrr-markdowngridextragtable

How can I top align these tables in gtable using grid.arrange?


I have a markdown document using a bit of LaTeX to produce a .pdf with the following chunk:

grid.arrange(
  grobs = list(
    gtable_combine(
      gtable_add_grob(
        tableGrob(mtcars[1:3, 1:2], rows = NULL),
        grobs = segmentsGrob(y1 = unit(0, "npc"),
        gp = gpar(fill = NA, lwd = 2)),
        t = 1,
        l = 1,
        r = ncol(mtcars[1:3, 1:2])
        ),
      gtable_add_grob(
        tableGrob(mtcars[1:3, 1:2], rows = NULL),
        grobs = segmentsGrob(y1 = unit(0, "npc"),
        gp = gpar(fill = NA, lwd = 2)),
        t = 1,
        l = 1,
        r = ncol(mtcars[1:3, 1:2])
        ),
        along = 2), 
    gtable_add_grob(
      tableGrob(mtcars[1:8, 1:2], rows = NULL),
      grobs = segmentsGrob(y1 = unit(0, "npc"),
                           gp = gpar(fill = NA, lwd = 2)),
      t = 1,
      l = 1,
      r = ncol(mtcars[1:8, 1:2])
      )
    ),
  ncol = 2
  )

The output is centre aligned, and I would like it aligned at the top. My sticking point is that the left hand side is two combined tables already, and I seem to be unable to nest the output of that function into another cal to gtable_combine(). I also haven't had any luck using the layout_matrix= argument in gridExtra, as this adds a huge amount of space between the left two tables.

How can I have the left two tables very close (adjoined is fine), and also have the top of the top-most left table and the top of the right table horizontally aligned?


Solution

  • I've located an answer from this prior SO post. It appears to me that the padding of the output of the two shorter tables gtable_combine(...) differs from the output of the longer table as the top padding is by default a function of the length of the table, and here the two tables, even when combined, will differ in length. The function @baptiste outlines in his answer solves this problem by fixing that padding value. Implementing it in my use case looks like this:

    justify <- function(x, hjust="center", vjust="top", draw=FALSE){
      w <- sum(x$widths)
      h <- sum(x$heights)
      xj <- switch(
        hjust,
        center = 0.5,
        left = 0.5 * w,
        right = unit(1, "npc") - 0.5 * w
        )
      yj <- switch(
        vjust,
        center = 0.5,
        bottom = 0.5 * h,
        top = unit(1, "npc") - 0.5 * h
        )
      x$vp <- viewport(x=xj, y=yj)
      if(draw) grid.draw(x)
      return(x)
    }
    
    grid.arrange(
      justify(
        gtable_combine(
          gtable_add_grob(
            tableGrob(mtcars[1:3, 1:2], rows = NULL),
            grobs = segmentsGrob(y1 = unit(0, "npc"),
                                 gp = gpar(fill = NA, lwd = 2)),
            t = 1,
            l = 1,
            r = ncol(mtcars[1:3, 1:2])
            ),
          gtable_add_grob(
          tableGrob(mtcars[1:3, 1:2], rows = NULL),
          grobs = segmentsGrob(y1 = unit(0, "npc"),
                               gp = gpar(fill = NA, lwd = 2)),
          t = 1,
          l = 1,
          r = ncol(mtcars[1:3, 1:2])
          ),
          along = 2
          )
        ), 
      justify(
        gtable_add_grob(
          tableGrob(mtcars[1:8, 1:2], rows = NULL),
          grobs = segmentsGrob(y1 = unit(0, "npc"),
                               gp = gpar(fill = NA, lwd = 2)),
          t = 1,
          l = 1,
          r = ncol(mtcars[1:3, 1:2])
          )
        ),
      ncol = 2
      )