Search code examples
rgridextracowplot

Aligning pairs of tableGrobs with uneven numbers of rows within and between subplots


I would like to make a figure containing several subplots. Some of these subplots I would like to be tables. However, the problem I have been facing is that I cannot get the tables to align with each other. I would like each table to be aligned to the "top" of each subplot.

I have tried using the following code:

## Reprex 
library(ggplot2)
library(gridExtra)
library(cowplot)
library(ggpubr)

#Data

dataA <- data.frame("A" = rep("A", 3),"B" = rep("B", 3),"C" = rep("C", 3))
dataB <- data.frame("A" = rep("A", 4),"B" = rep("B", 4),"C" = rep("C", 4))
dataC <- data.frame("A" = rep("A", 5),"B" = rep("B", 5),"C" = rep("C", 5))
dataD <- data.frame("A" = rep("A", 3),"B" = rep("B", 3),"C" = rep("C", 3))

#Convert to Grob


fig_subplotA <- arrangeGrob(tableGrob(dataA, rows = NULL),
                     tableGrob(dataB, rows = NULL), ncol = 2)

fig_subplotB <- arrangeGrob(tableGrob(dataC, rows = NULL), 
                     tableGrob(dataD, rows = NULL), ncol = 2)


# Make final plot 

g <- list(fig_subplotA, fig_subplotB)

p.final <- arrangeGrob(grobs=g, ncol = 2)

p <- as_ggplot(p.final)+
        draw_plot_label(label = c("a", "b"), x = c(0, 0.5))
p

#Export 

ggsave(filename = "FigureExample.png", p, width = 4, height = 3)

The output looks like:

Output

and I would like something like:

Goal

Thanks a lot for any input!


Solution

  • As far as I can tell, there is no vertical justification method for tableGrob, so this requires calculating the correct viewport position based on the grob heights, which is a bit long-winded, and probably best wrapped in a function:

    justify <- function(x, just = 1) {
      height <- as.numeric(grid::convertHeight(sum(x$heights), 'npc'))
      x$vp <- grid::viewport(y = just + height * (0.5 - just))
      x
    }
    

    This allows:

    A <- tableGrob(dataA, rows = NULL)
    B <- tableGrob(dataB, rows = NULL) 
    subplotA <- arrangeGrob(justify(A), justify(B), ncol = 2)
    
    C <- tableGrob(dataC, rows = NULL)
    D <- tableGrob(dataD, rows = NULL) 
    subplotB <- arrangeGrob(justify(C), justify(D), ncol = 2)
    
    arrangeGrob(grobs = list(subplotA, subplotB), ncol = 2) |>
      as_ggplot() +
      draw_plot_label(label = c("a", "b"), x = c(0, 0.5))
    

    enter image description here