简体   繁体   English

使用facetted ggplot 2.0.0和gridExtra排列公共绘图宽度

[英]Arrange common plot width with facetted ggplot 2.0.0 & gridExtra

Since I have updated to ggplot2 2.0.0, I cannot arrange charts propperly using gridExtra. 由于我已经更新到ggplot2 2.0.0,我无法使用gridExtra正确排列图表。 The issue is that the faceted charts will get compressed while other will expand. 问题是分面图表会被压缩,而其他图表会扩展。 The widths are basically messed up. 宽度基本搞砸了。 I want to arrange them similar to the way these single facet plots are: left align two graph edges (ggplot) 我想安排它们类似于这些单面图的方式: 左对齐两个图形边(ggplot)

I put a reproducible code 我把一个可重现的代码

library(grid) # for unit.pmax()
library(gridExtra)

plot.iris <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) + 
  geom_point() + 
  facet_grid(. ~ Species) + 
  stat_smooth(method = "lm")

plot.mpg <- ggplot(mpg, aes(x = cty, y = hwy, colour = factor(cyl))) + 
  geom_point(size=2.5)

g.iris <- ggplotGrob(plot.iris) # convert to gtable
g.mpg <- ggplotGrob(plot.mpg) # convert to gtable

iris.widths <- g.iris$widths # extract the first three widths, 
mpg.widths <- g.mpg$widths # same for mpg plot
max.widths <- unit.pmax(iris.widths, mpg.widths)

g.iris$widths <- max.widths # assign max. widths to iris gtable
g.mpg$widths <- max.widths # assign max widths to mpg gtable

grid.arrange(g.iris,g.mpg,ncol=1)

在此输入图像描述

As you will see, the top chart, the first facet is expanded while the other 2 get compressed at the right. 正如您将看到的,顶部图表,第一个方面被扩展,而另外两个方面被压缩。 Bottom chart does not cover all width. 底部图表未涵盖所有宽度。

Could it be that the new ggplot2 version is messing with the gtable widths? 是不是新的ggplot2版本搞乱了gtable的宽度?

Anyone know a workaround? 有人知道解决方法吗?

Thank you very much 非常感谢你

EDIT: Added picture of chart 编辑:添加图表的图片

I'm looking for something like: 我正在寻找类似的东西:

在此输入图像描述

one option is to massage each plot into a 3x3 gtable, where the central cell wraps all the plot panels. 一种选择是将每个地块按摩成3x3 gtable,其中中央细胞包裹所有的情节面板。

Using the example from @SandyMuspratt 使用@SandyMuspratt中的示例

# devtools::install_github("baptiste/egg") 
grid.draw(egg::ggarrange(plots=plots, ncol=1))

在此输入图像描述

the advantage being that once in this standardised format, plots may be combined in various layouts much more easily, regardless of number of panels, legends, axes, strips, etc. 优点是,一旦采用这种标准化格式,无论面板,图例,轴,条带等的数量如何,绘图都可以更容易地组合成各种布局。

grid.newpage()
grid.draw(ggarrange(plots=list(p1,  p4, p2, p3), widths = c(2,1), debug=TRUE))

在此输入图像描述

I'm not sure if you're still looking for a solution, but this is fairly general. 我不确定你是否还在寻找解决方案,但这是相当普遍的。 I'm using ggplot 2.1.0 (now on CRAN). 我正在使用ggplot 2.1.0(现在在CRAN上)。 It's based on this solution . 它基于这个解决方案 I break the problem into two parts. 我将问题分成两部分。 First, I deal with the left side of the plots, making sure the widths for the axis material are the same. 首先,我处理图的左侧,确保轴材料的宽度相同。 This has already been done by others, and there are solutions on SO. 这已经由其他人完成,并且有SO的解决方案。 But I don't think the result looks good. 但我不认为结果看起来不错。 I would prefer the panels to align on the right side as well. 我更喜欢面板也在右侧对齐。 So second, the procedure makes sure the widths of the columns to the right of the panels are the same. 第二,该过程确保面板右侧的列宽度相同。 It does this by adding a column of appropriate width to the right of each of the plots. 它通过在每个图的右侧添加适当宽度的列来实现。 (There's possibly neater ways to do it. There is - see @baptiste solution.) (可能有更简洁的方法去做。有 - 见@baptiste解决方案。)

library(grid)    # for pmax
library(gridExtra) # to arrange the plots
library(ggplot2)   # to construct the plots
library(gtable)   # to add columns to gtables of plots without legends

mpg$g = "Strip text"  

# Four fairly irregular plots: legends, faceting, strips
p1 <- ggplot(mpg, aes(displ, 1000*cty)) + 
  geom_point() + 
  facet_grid(. ~ drv) + 
  stat_smooth(method = "lm")

p2 <- ggplot(mpg, aes(x = hwy, y = cyl, colour = factor(cyl))) + 
  geom_point() + 
  theme(legend.position=c(.8,.6),
        legend.key.size = unit(.3, "cm"))

p3 <- ggplot(mpg, aes(displ, cty, colour = factor(drv))) + 
  geom_point() + 
  facet_grid(. ~ drv) 


p4 <- ggplot(mpg, aes(displ, cty, colour = factor(drv))) + 
  geom_point() + 
  facet_grid(g ~ .) 

# Sometimes easier to work with lists, and it generalises nicely
plots = list(p1, p2, p3, p4)

# Convert to gtables
g = lapply(plots, ggplotGrob) 

# Apply the un-exported unit.list function for grid package to each plot
g.widths = lapply(g, function(x) grid:::unit.list(x$widths)) 


## Part 1: Make sure the widths of left axis materials are the same across the plots
# Get first three widths from each plot
g3.widths <- lapply(g.widths, function(x) x[1:3])

# Get maximum widths for first three widths across the plots
g3max.widths <- do.call(unit.pmax, g3.widths)

# Apply the maximum widths to each plot
for(i in 1:length(plots)) g[[i]]$widths[1:3] = g3max.widths

# Draw it
do.call(grid.arrange, c(g, ncol = 1))


## Part 2: Get the right side of the panels aligned
# Locate the panels
panels <- lapply(g, function(x) x$layout[grepl("panel", x$layout$name), ])

# Get the position of right most panel
r.panel  = lapply(panels, function(x) max(x$r)) # position of right most panel

# Get the number of columns to the right of the panels
n.cols = lapply(g.widths, function(x) length(x)) # right most column

# Get the widths of these columns to the right of the panels
r.widths  <- mapply(function(x,y,z) x[(y+1):z], g.widths, r.panel, n.cols)

# Get the sum of these widths
sum.r.widths <- lapply(r.widths, sum)

# Get the maximum of these widths
r.width = do.call(unit.pmax, sum.r.widths)

# Add a column to the right of each gtable of width 
# equal to the difference between the maximum
# and the width of each gtable's columns to the right of the panel. 
for(i in 1:length(plots)) g[[i]] = gtable_add_cols(g[[i]], r.width - sum.r.widths[[i]], -1)

# Draw it
do.call(grid.arrange, c(g, ncol = 1))

在此输入图像描述

Taking off these two lines and keeping the rest, it worked just fine. 取下这两条线并保留其余部分,它工作得很好。

g.iris$widths <- max.widths # assign max. widths to iris gtable
g.mpg$widths <- max.widths # assign max widths to mpg gtable

在此输入图像描述

Probably it was limiting the width of them. 可能它限制了它们的宽度。

This is ugly but if you're under a time pressure this hack will work (not generalizable and dependent upon plot window size). 这很难看,但是如果你在时间压力下这个黑客会起作用(不可推广并且取决于绘图窗口大小)。 Basically make the top plot 2 columns with a blank plot on the right and guess at the widths. 基本上在顶部绘制2列,右边是空白图,并猜测宽度。

grid.arrange(
    grid.arrange(plot.iris, ggplot() + theme_minimal(),ncol=2, widths = c(.9, .1)),
    plot.mpg, 
    ncol=1
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM