Упорядочить общую ширину участка с граненым ggplot 2.0.0 и gridExtra

Так как я обновил ggplot2 2.0.0, я не могу организовать диаграммы с помощью gridExtra. Проблема в том, что граненые диаграммы будут сжаты, а другие будут расширяться. Ширины в основном перепутаны. Я хочу упорядочить их так же, как эти одиночные грани: выровнять по левому краю два графа графа (ggplot)

Я помещаю воспроизводимый код

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)

Как вы увидите, верхняя диаграмма, первая грань расширяется, а остальные 2 сжимаются справа. Нижняя диаграмма не охватывает всю ширину.

Может ли быть, что новая версия ggplot2 возится с ширинами gtable?

Кто-нибудь знает обходное решение?

Большое спасибо

EDIT: добавлено изображение графика

Я ищу что-то вроде:

4 ответа

один из вариантов состоит в том, чтобы массировать каждый график в 3 × 3-мерный, где центральная ячейка обертывает все панели сюжетов.

Используя пример из @SandyMuspratt

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

преимущество состоит в том, что однажды в этом стандартизованном формате графики могут быть объединены в различные макеты намного легче, независимо от количества панелей, легенд, осей, полос и т.д.

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


Я не уверен, что вы все еще ищете решение, но это довольно общее. Я использую ggplot 2.1.0 (теперь на CRAN). Он основан на этом решении. Я разбиваю проблему на две части. Во-первых, я рассматриваю левую часть сюжетов, следя за тем, чтобы ширина для материала оси была одинаковой. Это уже сделали другие, и на SO есть решения. Но я не думаю, что результат выглядит хорошо. Я бы предпочел, чтобы панели тоже выровнялись с правой стороны. Во-вторых, процедура гарантирует, что ширина столбцов справа от панелей одинакова. Он делает это, добавляя столбец соответствующей ширины справа от каждого из графиков. (Возможно, более простые способы сделать это. Существует - см. Решение @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 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))


Снимая эти две строки и сохраняя все остальное, он работал нормально.

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

Вероятно, это ограничивало их ширину.


Это некрасиво, но если вы находитесь под давлением времени, этот хак будет работать (не обобщаемый и не зависящий от размера окна графика). В основном сделайте верхний участок 2 столбца с пустым графиком справа и угадайте ширину.

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

licensed under cc by-sa 3.0 with attribution.