Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ggplot grobs align with tableGrob

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

like image 546
yuskam Avatar asked Oct 26 '16 14:10

yuskam


2 Answers

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

like image 38
baptiste Avatar answered Sep 20 '22 08:09

baptiste


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

like image 186
Nicholas G Reich Avatar answered Sep 19 '22 08:09

Nicholas G Reich