左对齐两个图形边缘(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_grid
和 geom_tile
),但未能对齐第三个的高度情节,这是一个树状图(geom_segment
)。但是,cowplot 或 gridExtra::grid.arrange
甚至无法做到前者,所以这是迄今为止效果最好的【参考方案6】:
这是使用 reshape2 包中的melt
和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 的长度恰好相同,但您的实际数据不是这样吗? 两个不同的数据集共享一个变量,所以行数不一样。【参考方案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 将一个图标对齐到左边缘,将另一个图标对齐到右边缘