Вот одна из возможностей: запросить высоту таблицы (фиксированное число, продиктованное содержимым) и оставить оставшуюся часть для графика. Обратите внимание, что paper = "a4" вводит свои собственные особенности, я бы это исключил.
library(ggplot2)
library(gridExtra)
library(grid)
library(gtable)
library(maggritr)
df <- iris[1:10,]
pp <- ggplot(iris, aes(x = Sepal.Length)) + geom_histogram(binwidth = 0.2)
tTitle <- textGrob(paste("Title line 1","\n", "Line 2", "\n", "Line 3"),
gp=gpar(fontsize=15))
padding <- unit(3,"line")
tt <- tableGrob(df, rows = NULL, theme = ttheme_minimal()) %>%
gtable_add_rows(heights = grobHeight(tTitle) + padding, pos = 0) %>%
gtable_add_grob(list(tTitle), t=1, l=1, r=ncol(tt)) %>%
gtable_add_grob(rectGrob(gp=gpar(fill=NA,col="red")),
t=1, l=1, r=ncol(tt),b=nrow(tt))
th <- sum(tt$heights)
pg <- arrangeGrob(tt, pp, heights = unit.c(th, unit(1,"npc")-th))
pdf("Demo.pdf", width=21/2.54,height=27.7/2.54)
grid.draw(pg)
dev.off()
Обратите внимание, что при таком подходе ggplot будет расширяться, чтобы заполнить оставшееся пространство. Если вы этого не хотите, вам следует назначить фиксированную высоту, например,
# 10 cm or remaining space on the page if smaller than that
cappedheight = unit.pmin(unit(1,"npc"), unit(10, "cm"))
# wrap plot in a grobTree to assign a viewport (centered in remaining space)
pp1 <- grobTree(ggplotGrob(pp), vp=viewport(height=cappedheight))
pg <- arrangeGrob(tt, pp1, heights = unit.c(th, unit(1,"npc")-th))