左对齐两个图形边缘(ggplot)


105

我正在使用ggplot,并且有两个图形要彼此叠加显示。我使用grid.arrangegridExtra来堆叠它们。问题是我希望图形的左边缘与右边缘对齐,而与轴标签无关。(出现问题是因为一个图形的标签较短而另一个图形的标签较长)。

问题:
我该怎么做?我没有嫁给grid.arrange,但ggplot2是必须的。

我尝试过的方法:
我尝试使用宽度和高度以及ncol和nrow来制作2 x 2网格,并将视觉效果放置在相对的角上,然后使用宽度进行播放,但是我无法在相对的角落获得视觉效果。

require(ggplot2);require(gridExtra)
A <- ggplot(CO2, aes(x=Plant)) + geom_bar() +coord_flip() 
B <- ggplot(CO2, aes(x=Type)) + geom_bar() +coord_flip() 
grid.arrange(A, B, ncol=1)

在此处输入图片说明


2
这里有两个可能的选择:herehere
joran 2012年

@Joran我正在寻找要对齐的左轴。我认为这些不会做到。不过我想错了。
泰勒·林克

Answers:


132

试试这个,

 gA <- ggplotGrob(A)
 gB <- ggplotGrob(B)
 maxWidth = grid::unit.pmax(gA$widths[2:5], gB$widths[2:5])
 gA$widths[2:5] <- as.list(maxWidth)
 gB$widths[2:5] <- as.list(maxWidth)
 grid.arrange(gA, gB, ncol=1)

编辑

这是一个更通用的解决方案(可处理任意数量的地块),rbind.gtable其中包含gridExtra

gA <- ggplotGrob(A)
gB <- ggplotGrob(B)
grid::grid.newpage()
grid::grid.draw(rbind(gA, gB))

3
漂亮,非常漂亮。谢谢您的解决方案。
泰勒·林克

1
完美的解决方案!我一直在寻找类似这样的方法来对齐多个单独的时间序列图,这些图由于多方面的定制而无法用刻面实现。
wahalulu

如果我们有两列,您是否愿意提供匹配高度的方法?gA $ heights [2:3]似乎无效。我是否必须选择2:3以外的grob元素?谢谢!
EtienneLow-Décarie13年

4
感谢您的解决方案Baptiste。但是,当其中一个图是时,我无法使它正常工作tableGrob。这gtable::cbind给了我一个令人失望的错误:nrow(x) == nrow(y) is not TRUE。有什么建议?
加布拉(Gabra)2015年

2
这个解决方案对我有用,请让我努力理解它。代表什么[2:5]
Hurlikus

38

我想将其推广到任何数量的地块。这是使用Baptiste的方法的分步解决方案:

plots <- list(A, B, C, D)
grobs <- list()
widths <- list()

收集每个情节的每个组的宽度

for (i in 1:length(plots)){
    grobs[[i]] <- ggplotGrob(plots[[i]])
    widths[[i]] <- grobs[[i]]$widths[2:5]
}

使用do.call获得最大宽度

maxwidth <- do.call(grid::unit.pmax, widths)

将最大宽度分配给每个组

for (i in 1:length(grobs)){
     grobs[[i]]$widths[2:5] <- as.list(maxwidth)
}

情节

do.call("grid.arrange", c(grobs, ncol = 1))

2
即使情节具有不同宽度的图例也可以使用-非常好!
基思·休吉特

30

使用Cowplot软件包:

A <- ggplot(CO2, aes(x=Plant)) + geom_bar() +coord_flip() 
B <- ggplot(CO2, aes(x=Type)) + geom_bar() +coord_flip() 

library(cowplot)
plot_grid(A, B, ncol=1, align="v")

在此处输入图片说明


12

http://rpubs.com/MarkusLoew/13295上,有一个非常简单的解决方案(最后一项)适用于此问题:

require(ggplot2);require(gridExtra)
A <- ggplot(CO2, aes(x=Plant)) + geom_bar() +coord_flip() 
B <- ggplot(CO2, aes(x=Type)) + geom_bar() +coord_flip() 
grid.draw(rbind(ggplotGrob(A), ggplotGrob(B), size="first"))

您也可以将其用于宽度和高度:

require(ggplot2);require(gridExtra)
A <- ggplot(CO2, aes(x=Plant)) + geom_bar() +coord_flip() 
B <- ggplot(CO2, aes(x=Type)) + geom_bar() +coord_flip() 
C <- ggplot(CO2, aes(x=conc)) + geom_bar() +coord_flip()
D <- ggplot(CO2, aes(x=uptake)) + geom_bar() +coord_flip() 
grid.draw(cbind(
            rbind(ggplotGrob(A), ggplotGrob(B), size="first"),
            rbind(ggplotGrob(C), ggplotGrob(D), size="first"),
            size='first'))

2
使用size="first"意味着如果第二个情节比第一个情节大,对齐方式看起来就不会很好
baptiste 2014年

10

egg软件包将ggplot对象包装到标准化3x3gtable中,从而使绘图面板在任意ggplot(包括多面图)之间对齐。

library(egg) # devtools::install_github('baptiste/egg')
library(ggplot2)

p1 <- ggplot(mtcars, aes(mpg, wt, colour = factor(cyl))) +
  geom_point() 

p2 <- ggplot(mtcars, aes(mpg, wt, colour = factor(cyl))) +
  geom_point() + facet_wrap( ~ cyl, ncol=2, scales = "free") +
  guides(colour="none") +
  theme()

ggarrange(p1, p2)

在此处输入图片说明


对我来说,这可能正常水平安排一个简单的热图(geom_tile),在底部的传说和多方面的热图(facet_gridgeom_tile),但未能对齐第三情节的高度,这是一个树状图(geom_segment)。但是,牛图还是gridExtra::grid.arrange不能做到,所以到目前为止效果最好
deeenes

8

这是使用meltreshape2包中的另一个可能的解决方案,并且facet_wrap

library(ggplot2)
library(reshape2)

dat = CO2[, c(1, 2)]
dat$id = seq(nrow(dat))
mdat = melt(dat, id.vars="id")

head(mdat)
#   id variable value
# 1  1    Plant   Qn1
# 2  2    Plant   Qn1
# 3  3    Plant   Qn1
# 4  4    Plant   Qn1
# 5  5    Plant   Qn1
# 6  6    Plant   Qn1

plot_1 = ggplot(mdat, aes(x=value)) + 
         geom_bar() + 
         coord_flip() +
         facet_wrap(~ variable, nrow=2, scales="free", drop=TRUE)

ggsave(plot=plot_1, filename="plot_1.png", height=4, width=6)

在此处输入图片说明


此解决方案假定每列中的行数相等。在我的MRWE中,这是事实,但实际上并非如此。
泰勒·林克

我不确定我是否理解:您是说CO2 $ Plant和CO2 $ Type的长度是相同的,但是您的实际数据不是这样吗?
bdemarest 2012年

共享一个变量的是两个不同的数据集,因此行数不相同。
泰勒·林克

2

默认情况下,patchwork软件包会处理此问题:

library(ggplot2)
library(patchwork)

A <- ggplot(CO2, aes(x = Plant)) + geom_bar() + coord_flip() 
B <- ggplot(CO2, aes(x = Type)) + geom_bar() + coord_flip() 

A / B

reprex软件包(v0.3.0)创建于2019-12-08


0

充其量是一个hack:

library(wq)
layOut(list(A, 1, 2:16),  list(B, 2:3, 1:16))

不过,这确实感觉不对。


-1

我知道这是一篇旧文章,并且已经得到答复,但是我建议将@baptiste的方法与之结合使用purrr以使其看起来更好:

library(purrr)
list(A, B) %>% 
  map(ggplotGrob) %>% 
  do.call(gridExtra::gtable_rbind, .) %>% 
  grid::grid.draw()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.