60

我有几个不同的类别要绘制。这些是不同的类别,每个类别都有自己的一组标签,但在文档中组合在一起是有意义的。下面给出了一些简单的堆积条形图示例:

df <- data.frame(x=c("a", "b", "c"),
                 y=c("happy", "sad", "ambivalent about life"))
ggplot(df, aes(x=factor(0), fill=x)) + geom_bar()
ggplot(df, aes(x=factor(0), fill=y)) + geom_bar()

\subfigure问题是使用不同的标签,图例有不同的宽度,这意味着图有不同的宽度,如果我制作一个表格或元素,这会导致事情看起来有点傻。我怎样才能解决这个问题?

有没有办法明确设置绘图或图例的宽度(绝对或相对)?

图 1 基于 x(更宽) 图表 2 基于 y(较窄)

4

6 回答 6

43

编辑: 非常容易使用egg

# install.packages("egg")

library(egg)

p1 <- ggplot(data.frame(x=c("a","b","c"),
                        y=c("happy","sad","ambivalent about life")),
             aes(x=factor(0),fill=x)) + 
      geom_bar()
p2 <- ggplot(data.frame(x=c("a","b","c"),
                        y=c("happy","sad","ambivalent about life")),
             aes(x=factor(0),fill=y)) + 
      geom_bar()

ggarrange(p1,p2, ncol = 1)

原始更新至 ggplot2 2.2.1

这是一个使用包中的函数的解决方案gtable,并专注于图例框的宽度。(可以在这里找到更通用的解决方案。)

library(ggplot2)   
library(gtable)    
library(grid)
library(gridExtra) 

# Your plots
p1 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=x)) + geom_bar()
p2 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=y)) + geom_bar()

# Get the gtables
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)

# Set the widths
gA$widths <- gB$widths

# Arrange the two charts.
# The legend boxes are centered
grid.newpage()
grid.arrange(gA, gB, nrow = 2)

如果另外,图例框需要左对齐,并从这里借用@Julius编写的一些代码

p1 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=x)) + geom_bar()
p2 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=y)) + geom_bar()

# Get the widths
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)

# The parts that differs in width
leg1 <- convertX(sum(with(gA$grobs[[15]], grobs[[1]]$widths)), "mm")
leg2 <- convertX(sum(with(gB$grobs[[15]], grobs[[1]]$widths)), "mm")

# Set the widths
gA$widths <- gB$widths

# Add an empty column of "abs(diff(widths)) mm" width on the right of 
# legend box for gA (the smaller legend box)
gA$grobs[[15]] <- gtable_add_cols(gA$grobs[[15]], unit(abs(diff(c(leg1, leg2))), "mm"))

# Arrange the two charts
grid.newpage()
grid.arrange(gA, gB, nrow = 2)

在此处输入图像描述

替代解决方案软件包中 有用于将 grobs 组合成一个 grobrbindcbind功能。gtable对于此处的图表,应使用 设置宽度size = "max",但 CRAN 版本的gtable会引发错误。

一种选择:很明显,第二个情节中的图例更宽。因此,使用该size = "last"选项。

# Get the grobs
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)

# Combine the plots
g = rbind(gA, gB, size = "last")

# Draw it
grid.newpage()
grid.draw(g)

左对齐图例:

# Get the grobs
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)

# The parts that differs in width
leg1 <- convertX(sum(with(gA$grobs[[15]], grobs[[1]]$widths)), "mm")
leg2 <- convertX(sum(with(gB$grobs[[15]], grobs[[1]]$widths)), "mm")

# Add an empty column of "abs(diff(widths)) mm" width on the right of 
# legend box for gA (the smaller legend box)
gA$grobs[[15]] <- gtable_add_cols(gA$grobs[[15]], unit(abs(diff(c(leg1, leg2))), "mm"))

# Combine the plots
g = rbind(gA, gB, size = "last")

# Draw it
grid.newpage()
grid.draw(g)

第二种选择是rbind从 Baptiste 的gridExtra包中使用

# Get the grobs
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)

# Combine the plots
g = gridExtra::rbind.gtable(gA, gB, size = "max")

# Draw it
grid.newpage()
grid.draw(g)

左对齐图例:

# Get the grobs
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)

# The parts that differs in width
leg1 <- convertX(sum(with(gA$grobs[[15]], grobs[[1]]$widths)), "mm")
leg2 <- convertX(sum(with(gB$grobs[[15]], grobs[[1]]$widths)), "mm")

# Add an empty column of "abs(diff(widths)) mm" width on the right of 
# legend box for gA (the smaller legend box)
gA$grobs[[15]] <- gtable_add_cols(gA$grobs[[15]], unit(abs(diff(c(leg1, leg2))), "mm"))

# Combine the plots
g = gridExtra::rbind.gtable(gA, gB, size = "max")

# Draw it
grid.newpage()
grid.draw(g)
于 2013-04-28T00:40:15.843 回答
17

cowplot软件包还具有align_plots用于此目的的功能(未显示输出),

both2 <- align_plots(p1, p2, align="hv", axis="tblr")
p1x <- ggdraw(both2[[1]])
p2x <- ggdraw(both2[[2]])
save_plot("cow1.png", p1x)
save_plot("cow2.png", p2x)

并且还将plot_grid绘图保存到同一文件中。

library(cowplot)
both <- plot_grid(p1, p2, ncol=1, labels = c("A", "B"), align = "v")
save_plot("cow.png", both)

在此处输入图像描述

于 2017-08-10T14:34:59.960 回答
9

正如@hadley 建议的那样,rbind.gtable应该能够处理这个问题,

  grid.draw(rbind(ggplotGrob(p1), ggplotGrob(p2), size="last"))

然而,理想的布局宽度应该是size="max",这不能很好地处理某些类型的网格单元。

于 2013-04-29T15:13:39.073 回答
4

偶然地,我注意到他在评论中建议的 Arun 的解决方案尚未被采纳。我觉得他的简单有效的方法确实值得说明。

Arun 建议将图例移到顶部或底部:

ggplot(df, aes(x=factor(0), fill=x)) + geom_bar() + theme(legend.position = "bottom")
ggplot(df, aes(x=factor(0), fill=y)) + geom_bar() + theme(legend.position = "bottom")

在此处输入图像描述 在此处输入图像描述

现在,这些图的宽度与请求的宽度相同。此外,两种情况下的地块面积大小相同。

如果有更多因素甚至更长的标签,则可能有必要使用图例,例如,将图例显示在两行或更多行中。theme()并且guide_legend()有几个参数来控制图例的位置和外观ggplot2

于 2017-01-14T10:03:30.660 回答
2

我根据@Sandy 的回答创建了一个小函数。

same.size.ggplot <- function(vector.string.graph, # a vector of strings which correspond to Robject ggplot graphs
                             reference.string.graph, # a string of a  Robject ggplot graphs where height and/or height will be taken for reference
                             width = T, # if you wanna adapat only the width
                             height = F # if you wanna adapat only the height
) {

  # example: same.size.ggplot(p0rep(c("a", "b"), thre), "a30") 


  which(vector.string.graph %in% reference.string.graph)

  newref <- ggplotGrob(get(reference.string.graph))
  ref.width <- newref$widths
  ref.height <- newref$heights

  assign(reference.string.graph, newref, env = parent.frame(1))

  for(i in seq_along(vector.string.graph)) {
    if(vector.string.graph[i] != reference.string.graph) {
      new <- ggplotGrob(get(vector.string.graph[i]))
      if( width ) {
        new$widths <- ref.width
      }
      if( height ) {
        new$heights <- ref.height
      }
      assign(vector.string.graph[i], new, env = parent.frame(1))
    }
  }
}
p1 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=x)) + geom_bar()
p2 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=y)) + geom_bar()
p3 <- ggplot(data.frame(x=c("a","b","c"),y=c("Crazy happy","sad","Just follow the flow")),aes(x=factor(0),fill=y)) + geom_bar()

grid.arrange(p1, p2, p3, ncol = 1)

same.size.ggplot(c("p1", "p2", "p3"), "p2") # same as same.size.ggplot(c("p2", "p3"), "p1") 

grid.arrange(p1, p2, p3, ncol = 1)

在此处输入图像描述

在此处输入图像描述

于 2019-08-21T15:17:07.580 回答
1

您也可以为此使用patchwork -package:

require(ggplot2)
require(patchwork)
# data
df = data.frame(x = c("a", "b", "c"),
                y = c("happy", "sad", "ambivalent about life"))
p1 = ggplot(df, aes(x=factor(0), fill=x)) + geom_bar()
p2 = ggplot(df, aes(x=factor(0), fill=y)) + geom_bar()

# Patchwork 1: Does it automatically
p1 / p2

# Patchwork 2: Create a list
l = patchwork::align_patches(p1, p2)
于 2022-02-10T14:08:31.453 回答