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

Posted

技术标签:

【中文标题】左对齐两个图形边缘(ggplot)【英文标题】:Left align two graph edges (ggplot) 【发布时间】:2012-10-28 23:57:43 【问题描述】:

我正在使用 ggplot 并有两个要显示在彼此之上的图表。我使用来自 gridExtra 的grid.arrange 来堆叠它们。问题是我希望图表的左边缘和右边缘对齐,而不管轴标签如何。 (问题出现是因为一个图的标签很短,而另一个图的标签很长)。

问题: 我怎样才能做到这一点?我没有嫁给 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)

【问题讨论】:

这里有两个可能的选项:here 和 here。 @Joran 我正在寻找要对齐的左轴。我不认为这些会做到这一点。不过我想错了。 【参考方案1】:

试试这个,

 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)

编辑

这是一个更通用的解决方案(适用于任意数量的地块),使用 gridExtra 中包含的 rbind.gtable 的修改版本

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

【讨论】:

漂亮而且非常直接。感谢您的解决方案。 完美解决方案!我一直在寻找这样的东西来对齐多个单独的时间序列图,由于每个图中的主要自定义,我无法使用分面进行。 如果我们有两列,您能否提供匹配高度的方法? gA$heights[2:3] 似乎不起作用。我是否必须选择 grob 的另一个元素而不是 2:3?谢谢! 感谢您的解决方案 Baptiste。但是,当其中一个情节是tableGrob 时,我无法使用它。 gtable::cbind 给了我一个令人失望的错误:nrow(x) == nrow(y) is not TRUE。有什么建议吗? 这个解决方案对我有用,我试图理解它。 [2:5] 代表什么?【参考方案2】:

我想将这一点推广到任意数量的地块。以下是使用 Baptiste 方法的分步解决方案:

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

收集每个地块的每个 grob 的宽度

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)

为每个 grob 分配最大宽度

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

情节

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

【讨论】:

即使情节有不同宽度的图例也能工作 - 非常好!【参考方案3】:

使用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")

【讨论】:

【参考方案4】:

在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'))

【讨论】:

使用size="first" 意味着如果第二个图比第一个大,对齐看起来不会很好【参考方案5】:

egg 包将 ggplot 对象包装到标准化的 3x3 gtable 中,从而可以在任意 ggplots 之间对齐绘图面板,包括多面的。

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)。但是,cowplot 或 gridExtra::grid.arrange 甚至无法做到前者,所以这是迄今为止效果最好的【参考方案6】:

这是使用 reshape2 包中的meltfacet_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 的长度恰好相同,但您的实际数据不是这样吗? 两个不同的数据集共享一个变量,所以行数不一样。【参考方案7】:

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 package (v0.3.0) 于 2019-12-08 创建

【讨论】:

【参考方案8】:

我知道这是一个旧帖子,并且已经得到了回答,但我可以建议将@baptiste 的方法与purrr 结合起来让它看起来更好看:

library(purrr)
list(A, B) %>% 
  map(ggplotGrob) %>% 
  do.call(gridExtra::gtable_rbind, .) %>% 
  grid::grid.draw()

【讨论】:

【参考方案9】:

充其量这是一个 hack:

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

但感觉真的不对。

【讨论】:

以上是关于左对齐两个图形边缘(ggplot)的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 将一个图标对齐到左边缘,将另一个图标对齐到右边缘

使用 Bootstrap 对齐左边缘时居中列表项

iOS自动布局:将UILabel的左边缘与容器中的水平中心对齐?

如何让ggplot线跑到边缘?

关于align="absmiddle"的说明

如何在 UIButton 的右边缘对齐 UIButton 图像