Wyrównaj obszary wykresu w ggplot

Próbuję użyć siatki.zorganizuj wyświetlanie wielu wykresów na tej samej stronie wygenerowanych przez ggplot. Wykresy używają tych samych danych x, ale z różnymi zmiennymi y. Wykresy wychodzą z różnych wymiarów ze względu na Y-dane o różnych skalach.

Próbowałem użyć różnych opcji motywu w ggplot2, aby zmienić rozmiar wykresu i przenieść Etykietę osi Y, ale żadna nie zadziałała, aby wyrównać wykresy. Chcę, aby działki ułożone były w kwadracie 2 x 2 tak, aby każda działka była tej samej wielkości i / align = "left" /

Oto kilka danych testowych:

A <- c(1,5,6,7,9)
B <- c(10,56,64,86,98)
C <- c(2001,3333,5678,4345,5345)
D <- c(13446,20336,24333,34345,42345)
L <- c(20,34,45,55,67)
M <- data.frame(L, A, B, C, D)

I Kod, którego używam do wykreślenia:

x1 <- ggplot(M, aes(L, A,xmin=10,ymin=0)) + geom_point() + stat_smooth(method='lm')
x2 <- ggplot(M, aes(L, B,xmin=10,ymin=0)) + geom_point() + stat_smooth(method='lm')
x3 <- ggplot(M, aes(L, C,xmin=10,ymin=0)) + geom_point() + stat_smooth(method='lm')
x4 <- ggplot(M, aes(L, D,xmin=10,ymin=0)) + geom_point() + stat_smooth(method='lm')
grid.arrange(x1,x2,x3,x4,nrow=2)

Jeśli uruchomisz ten kod, zobaczysz, że dwie dolne działki mają mniejszy obszar działki ze względu na większą długość jednostek osi Y.

Jak sprawić, by rzeczywiste okna działkowe były takie same?

 21
Author: zx8754, 2012-12-01

5 answers

Użyłbym fasetowania do tego problemu:

library(reshape2)
dat <- melt(M,"L") # When in doubt, melt!

ggplot(dat, aes(L,value)) + 
geom_point() + 
stat_smooth(method="lm") + 
facet_wrap(~variable,ncol=2,scales="free")

Przykład

Uwaga: laik może nie zauważyć, że skale różnią się między aspektami.

 9
Author: Brandon Bertelsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-01 05:55:28

Edit

Prostsze rozwiązania to: 1) użyj pakietu cowplot (Zobacz odpowiedź tutaj); lub 2) Użyj pakietu egg dostępnego na GitHubie.

# devtools::install_github("baptiste/egg")
library(egg)
library(grid)

g = ggarrange(x1, x2, x3, x4, ncol = 2)
grid.newpage()
grid.draw(g)

Oryginalny

Minor edit: Aktualizacja kodu.

Jeśli chcesz zachować etykiety osi, to z pewnymi modyfikacjami i zapożyczeniem kodu z tutaj , to wystarczy.

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

# Get the widths
gA <- ggplotGrob(x1)
gB <- ggplotGrob(x2)
gC <- ggplotGrob(x3)
gD <- ggplotGrob(x4)
maxWidth = unit.pmax(gA$widths[2:3], gB$widths[2:3], 
                     gC$widths[2:3], gD$widths[2:3])

# Set the widths
gA$widths[2:3] <- maxWidth
gB$widths[2:3] <- maxWidth
gC$widths[2:3] <- maxWidth
gD$widths[2:3] <- maxWidth

# Arrange the four charts
grid.arrange(gA, gB, gC, gD, nrow=2)

Tutaj wpisz opis obrazka

ALTERNATYWNE ROZWIĄZANIA: Istnieją funkcje rbind i cbind w gtable pakiet do łączenia grobów w jeden grob. Dla Wykresów tutaj, szerokości powinny być ustawione za pomocą size = "max", ale wersja CRAN gtable rzuca błąd.

Jedną z opcji jest sprawdzenie wykresu grid.arrange, a następnie użycie opcji size = "first" lub size = "last":

# Get the ggplot grobs
gA <- ggplotGrob(x1)  
gB <- ggplotGrob(x2)
gC <- ggplotGrob(x3)
gD <- ggplotGrob(x4)

# Arrange the four charts
grid.arrange(gA, gB, gC, gD, nrow=2)

# Combine the plots   
g = cbind(rbind(gA, gC, size = "last"), rbind(gB, gD, size = "last"), size = "first")

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

Drugą opcją jest bind ing funkcji z gridExtra pakietu.

# Get the ggplot grobs
gA <- ggplotGrob(x1)  
gB <- ggplotGrob(x2)
gC <- ggplotGrob(x3)
gD <- ggplotGrob(x4)

# Combine the plots
g = cbind.gtable(rbind.gtable(gA, gC, size = "max"), rbind.gtable(gB, gD, size = "max"), size = "max")

# Draw it
grid.newpage()
grid.draw(g)
 21
Author: Sandy Muspratt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:00:34

To jest dokładnie ten rodzaj problemu, dla którego napisałem cowplot Pakiet. Można to zrobić w jednej linii w tym pakiecie:

require(cowplot) # loads ggplot2 as dependency
# re-create the four plots
A <- c(1,5,6,7,9)
B <- c(10,56,64,86,98)
C <- c(2001,3333,5678,4345,5345)
D <- c(13446,20336,24333,34345,42345)
L <- c(20,34,45,55,67)
M <- data.frame(L, A, B, C, D)
x1 <- ggplot(M, aes(L, A,xmin=10,ymin=0)) + geom_point() + stat_smooth(method='lm')
x2 <- ggplot(M, aes(L, B,xmin=10,ymin=0)) + geom_point() + stat_smooth(method='lm')
x3 <- ggplot(M, aes(L, C,xmin=10,ymin=0)) + geom_point() + stat_smooth(method='lm')
x4 <- ggplot(M, aes(L, D,xmin=10,ymin=0)) + geom_point() + stat_smooth(method='lm')

# arrange into grid and align
plot_grid(x1, x2, x3, x4, align='vh')

Oto wynik: Tutaj wpisz opis obrazka (Zauważ, że cowplot zmienia domyślny motyw ggplot2. Możesz odzyskać szarą, jeśli naprawdę chcesz.)

Jako bonus Możesz również dodać etykiety wykresu w lewym górnym rogu każdego wykresu:

plot_grid(x1, x2, x3, x4, align='vh', labels=c('A', 'B', 'C', 'D'))

Wynik: Tutaj wpisz opis obrazka

Używam opcji labels na praktycznie każdym grafie wieloczęściowym I make.

 8
Author: Claus Wilke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-04 06:24:00

Patchwork {[3] } to nowy pakiet, który ułatwia formatowanie i układ wielu ggplotów. Jedną z najlepszych rzeczy jest to, że automatycznie wyrównuje obszary działki. Dodatkowo składnia jest naprawdę łatwa.

devtools::install_github("thomasp85/patchwork")
library(patchwork)
x1 + x2 + x3 + x4 + plot_layout(ncol = 2)

Tutaj wpisz opis obrazka

Sprawdź stronę GitHub, aby uzyskać więcej przykładów: https://github.com/thomasp85/patchwork

 3
Author: Michael Harper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-10 22:53:16

Jeśli używasz RMarkdown i knitting do PDF, mam alternatywne podejście. Knitr oferuje funkcjonalność subfigurki wykresu podczas tworzenia pliku PDF, co pozwala na umieszczenie wielu figur na wykresie, z których każda ma własny podpis.

Aby to zadziałało, każda fabuła musi być wyświetlona osobno. Łącząc ze sobą kilka funkcji z pakietu cowplot, stworzyłem następującą funkcję, która wyrównuje wykresy, zachowując je jako oddzielne obiekty:

plot_grid_split <- function(..., align = "hv", axis= "tblr"){
  aligned_plots <- cowplot::align_plots(..., align=align, axis=axis)
  plots <- lapply(1:length(aligned_plots), function(x){
    cowplot::ggdraw(aligned_plots[[x]])
  })
  invisible(capture.output(plots))
}

Tutaj jest przykładem, porównując układ normalnie vs używając funkcji:

---
output: pdf_document
header-includes:
   - \usepackage{subfig}
---

```{r}
plot_grid_split <- function(..., align = "hv", axis= "tblr"){
  aligned_plots <- cowplot::align_plots(..., align=align, axis=axis)
  plots <- lapply(1:length(aligned_plots), function(x){
    cowplot::ggdraw(aligned_plots[[x]])
  })
  invisible(capture.output(plots))
}
```

```{r fig-sub, fig.cap='Four Plots Not Aligned', fig.subcap=c('Plot One', 'Plot Two', 'Plot Three', 'Plot Four'), out.width='.49\\linewidth', fig.asp=1, fig.ncol = 2}  
library(ggplot2) 
plot <- ggplot(iris, aes(Sepal.Length, Sepal.Width, colour = Species)) +
  geom_point()

plot + labs(title = "A nice title")
plot + labs(caption = "A sample caption")
plot + theme(legend.position = "none")
plot + theme(legend.position = "top")
```  

```{r fig-sub-2, fig.cap='Four Plots Aligned', fig.subcap=c('Plot One', 'Plot Two', 'Plot Three', 'Plot Four'), out.width='.49\\linewidth', fig.asp=1, fig.ncol = 2}

x1 <- plot + labs(title = "A nice title")
x2 <- plot + labs(caption = "A sample caption")
x3 <- plot + theme(legend.position = "none")
x4 <- plot + theme(legend.position = "top")

plot_grid_split(x1, x2, x3, x4)
```

Tutaj wpisz opis obrazka

 0
Author: Michael Harper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-08 13:36:25