Зліва вирівняйте два ребра графіка (ggplot)


105

Я використовую ggplot і маю два графіки, які я хочу відображати один над одним. Я використовував grid.arrangeз gridExtra для їх укладання. Проблема полягає в тому, що я хочу, щоб ліві краї графіків вирівнювались так само, як і праві, незалежно від міток осі. (проблема виникає через те, що мітки одного графа короткі, а іншого - довгі).

Питання:
Як я можу це зробити? Я не одружений на 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)

введіть тут опис зображення


2
Ось два можливі варіанти: тут і тут .
Жоран

@Joran Я шукаю ліві осі для вирівнювання. Я не думаю, що це зроблять. Я хотів би помилитися.
Тайлер Рінкер

Відповіді:


132

Спробуйте це,

 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)

Редагувати

Ось більш загальне рішення (працює з будь-якою кількістю сюжетів) з використанням модифікованої версії, rbind.gtableвключеної вgridExtra

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

3
Красиво і справді досить прямо. Дякую за рішення.
Тайлер Рінкер

1
Ідеальне рішення! Я шукав щось подібне, щоб вирівняти кілька окремих сюжетів часових рядів, які я не можу зробити з облицюванням через основні налаштування кожного сюжету.
wahalulu

Чи будете ви настільки люб'язними, щоб надати, який би спосіб було відповідати висоті, якщо у нас є два стовпчики? gA $ висоти [2: 3], здається, не працюють. Чи потрібно вибрати інший елемент могили, ніж 2: 3? Дякую!
Етьєн Лоу-Декарі

4
Дякую за ваше рішення Baptiste. Однак я не змушую це працювати, коли одним із сюжетів є а tableGrob. gtable::cbindДає мені невтішну помилку: nrow(x) == nrow(y) is not TRUE. Будь-які пропозиції?
Габра

2
Це рішення працювало на мене, кажучи, я намагаюся його зрозуміти. Що означає [2:5]підставка?
Хурлікус

38

Я хотів узагальнити це для будь-якої кількості сюжетів. Ось покрокове рішення з використанням підходу Baptiste:

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

зібрати ширину для кожної могили кожної ділянки

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)

призначте максимальну ширину для кожної могили

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

сюжет

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

2
Працює навіть тоді, коли сюжети мають легенди різної ширини - дуже приємно!
Кіт Хугітт


12

На 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'))

2
використовуючи size="first"означає, що вирівнювання не буде виглядати дуже добре, якщо другий сюжет більший за перший
баптист

10

У eggпакеті обручі ggplot об'єкти в стандартизованої 3x3gtable, що дозволяє вирівнювання сюжетних панелей між довільним 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). однак коров'ячий шлунок або gridExtra::grid.arrangeне вдалося зробити навіть колишнього, тому це працює найкраще досі
поглиблюється

8

Ось ще одне можливе рішення за допомогою meltпакета reshape2 та 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 мають однакову довжину, але що ваші фактичні дані не такі?
bdemarest

Це два різних набори даних, що розділяє одну змінну, тому кількість рядків не однакова.
Тайлер Рінкер


0

У кращому випадку це злом:

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

Хоча це і справді неправильно.


-1

Я знаю, що це старий пост і що на нього вже відповіли, але чи можу я запропонувати поєднати підхід @ baptiste з тим, purrrщоб зробити його гарнішим:

library(purrr)
list(A, B) %>% 
  map(ggplotGrob) %>% 
  do.call(gridExtra::gtable_rbind, .) %>% 
  grid::grid.draw()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.