ggplot grobs align with tableGrob
Asked Answered
B

2

6

I'm having difficulty to find solution for aligning ggplot grob and table grob. I tried to follow the instruction here but still didn't give the results I wanted.

library(grid)
library(gridExtra)
library(ggplot2)
library(tibble)
library(gtable)
dat <- tibble::rownames_to_column(mtcars, "car") #convert rownames to first col

plot1 <- ggplot(dat, aes(car, mpg)) +
    geom_bar(stat = "identity") +
    coord_flip()

g1 <- ggplotGrob(plot1)
tb1 <- tableGrob(dat$cyl)
g1 <- gtable_add_cols(g1, unit(0.2, "npc"))
g1 <- gtable_add_grob(g1, grobs = tb1, t=3, l=ncol(g1), b=6, r=ncol(g1))

grid.newpage()
grid.draw(g1)

I would like that each cell in the table be aligned to related bar in histogram, but still couldn't understand how the t,l,b,r be implemented from the layout.This is the output I got

enter image description here

Bisector answered 26/10, 2016 at 14:51 Comment(0)
P
10

I had a similar question as above when trying to make something like a forestplot in R using ggplot2 and didn't find any of the other solutions fit my needs. The answer above didn't work for me - the table didn't show up. So I hacked together a codewise not that pretty solution, but I actually kind of like the cleanliness visual output.

The things I like about this solution are:

  • I aligned a set of custom text not in a table, but just in a figure on the right, where the alignment matched for each text entry and each label in the figure.
  • I used a centered ggtitle to align a "column heading" above each set of text. These could be strings of any kind (in my actual use, I had point estimates and confidence intervals).
library(gridExtra)
library(ggplot2)

dat <- data.frame(
    label = c("A", "B", "C"),
    point_est = c(1,2,3),
    lb_ci = c(.5, 1.5, 2.5),
    ub_ci = c(1.5, 2.5, 3.5),
    n = c(50, 100, 150),
    total = c(75, 150, 200)
)

plot1 <- ggplot(dat, aes(x=point_est, y=label)) +
    geom_point() +
    geom_errorbarh(aes(xmin=lb_ci, xmax=ub_ci), height=.5) +
    ggtitle("Some measure") +
    ylab(NULL) + xlab("some effect estimate")

tab_base <- ggplot(dat, aes(y=label)) +
    ylab(NULL) + xlab("  ") + 
    theme(plot.title = element_text(hjust = 0.5, size=12), ## centering title on text
        axis.text.x=element_text(color="white"), ## need text to be printed so it stays aligned with figure but white so it's invisible
        axis.line=element_blank(),
        axis.text.y=element_blank(),axis.ticks=element_blank(),
        axis.title.y=element_blank(),legend.position="none",
        panel.background=element_blank(),panel.border=element_blank(),panel.grid.major=element_blank(),
        panel.grid.minor=element_blank(),plot.background=element_blank())

tab1 <- tab_base + 
    geom_text(aes(x=1, label=n)) + 
    ggtitle("n")

tab2 <- tab_base +
    geom_text(aes(x=1, label=total)) + 
    ggtitle("total")

lay <-  matrix(c(1,1,1,1,1,1,2,3), nrow=1)
grid.arrange(plot1, tab1, tab2, layout_matrix = lay)

enter image description here

Ploce answered 8/6, 2019 at 2:14 Comment(2)
Thanks for the alternative solution!Bisector
Just wanted to thank you for posting this solution @Nicholas G Reich. I spent hours looking for a solution for a table that aligned perfectly with the graph. So grateful for this!Brutality
J
3

By default the cell heights have absolute sizes to accommodate the text, but you can change them to relative units so that they scale with the plot panel,

library(grid)
library(gridExtra)
library(ggplot2)
library(tibble)
library(gtable)
dat <- tibble::rownames_to_column(mtcars, "car") #convert rownames to first col

plot1 <- ggplot(dat, aes(car, mpg)) +
  geom_bar(stat = "identity") +
  coord_flip()

g1 <- ggplotGrob(plot1)
tb1 <- tableGrob(dat$cyl, theme = ttheme_default(10))
tb1$heights = unit(rep(1/(nrow(tb1)), nrow(tb1)), "npc")
tb1$widths = unit.pmax(tb1$widths, unit(2, "lines"))
g1 <- gtable_add_cols(g1, sum(tb1$widths))
g1 <- gtable_add_grob(g1, grobs = tb1, t=6, l=ncol(g1), b=6, r=ncol(g1))

grid.newpage()
grid.draw(g1)

enter image description here

Johppah answered 26/10, 2016 at 18:45 Comment(4)
Thanks for the guidence, but I still don't understand why t=6 and b=6. When I look at the layout with gtable_show_layout(g1) the cell is (3,6)Bisector
I see now that you didn't use the same plot1 figure I'm using which gives different layout. Thanks again for explanationBisector
Do you mind to share your code for plot1 with axis title x on top? I have difficulty to replicate the solution with axis title and ticks on the bottom og the plot.Bisector
When I run this code, I get a blank space on the RHS of the plot, unlike the plot shown above. Perhaps some update to one of the packages has made this not work anymore?Ploce

© 2022 - 2025 — McMap. All rights reserved.