2015-12-10 29 views
11

Próbuję napisać skrypt, który tworzy cztery różne wykresy na jednym obrazie. W szczególności chcę, aby odtworzyć tę grafikę jak najdokładniej:R - jak przydzielić przestrzeń ekranu do złożonych obrazów ggplot

Complex Plot

Mój obecny skrypt tworzy czterech działek podobnych do nich, ale nie mogę dowiedzieć się, w jaki sposób rozdzielić ekranem Nieruchomości odpowiednio. Chcę:

  1. modyfikować wysokość i szerokość działki, tak aby wszystkie cztery mają jednakową szerokość, jedno jest znacznie wyższy niż w innych, które mają jednolitą wysokość wśród nich
  2. określić położenie legendy współrzędnych tak, że mogę korzystać z miejsca na ekranie skutecznie
  3. modyfikować ogólny kształt mojego obrazu wyraźnie, ile potrzeba (być może będzie trzeba go bliżej w kształcie kwadratu w pewnym momencie)

GENERUJ Niektóre dane do wykreślenia

pt_id = c(1:279) # DEFINE PATIENT IDs 
smoke = rbinom(279,1,0.5) # DEFINE SMOKING STATUS 
hpv = rbinom(279,1,0.3) # DEFINE HPV STATUS 
data = data.frame(pt_id, smoke, hpv) # PRODUCE DATA FRAME 

Dodać stronę anatomicznych DANE

data$site = sample(1:4, 279, replace = T) 
data$site[data$site == 1] = "Hypopharynx" 
data$site[data$site == 2] = "Larynx" 
data$site[data$site == 3] = "Oral Cavity" 
data$site[data$site == 4] = "Oropharynx" 
data$site_known = 1 # HACK TO FACILITATE PRODUCING BARPLOTS 

ADD mutacji dane częstotliwości

data$freq = sample(1:1000, 279, replace = F) 

DEF BARPLOT

require(ggplot2) 
require(gridExtra) 
bar = ggplot(data, aes(x = pt_id, y = freq)) + geom_bar(stat = "identity") +  theme(axis.title.x = element_blank(), axis.ticks.x = element_blank(), axis.text.x = element_blank()) + ylab("Number of Mutations") 
# DEFINE BINARY PLOTS 
smoke_status = ggplot(data, aes(x=pt_id, y=smoke, fill = "red")) + geom_bar(stat="identity") + theme(legend.position = "none", axis.title.x = element_blank(), axis.ticks.x = element_blank(), axis.text.x = element_blank()) + ylab("Smoking Status") 
hpv_status = ggplot(data, aes(x=pt_id, y = hpv, fill = "red")) + geom_bar(stat="identity") + theme(legend.position = "none", axis.title.x = element_blank(), axis.ticks.x = element_blank(), axis.text.x = element_blank()) + ylab("HPV Status") 
site_status = ggplot(data, aes(x=pt_id, y=site_known, fill = site)) +  geom_bar(stat="identity") 

wyprodukowali cztery wykresy łącznie

grid.arrange(bar, smoke_status, hpv_status, site_status, nrow = 4) 

Podejrzewam, że funkcje potrzebne do wykonania tych zadań są już zawarte w ggplot2 i gridExtra, ale nie byłem w stanie dowiedzieć się, w jaki sposób. Ponadto, jeśli którykolwiek z moich kodów jest nadmiernie szczegółowy lub istnieje prostszy, bardziej elegancki sposób robienia tego, co już zrobiłem - proszę, skomentuj to również.

+0

W pierwszym pytaniu można określić układ z 6 rzędami, a następnie umieścić górny wykres w pierwszych 3 rzędach. Zobacz funkcję multiplot tutaj dla [http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_(ggplot2)/] – RHA

+3

Tego typu rzeczy zwykle wymagają robienia rzeczy "ręcznie" przy użyciu narzędzi z ** siatki ** pakietu . Zacznę od spojrzenia na 'ggplot_build' i' ggplot_gtable', aby rozłożyć wykresy na groby komponentu, a następnie prawdopodobnie skonstruujesz własny układ ('grid.layout') i narysujesz poszczególne groby w określonych rzutniach. – joran

+0

Możesz również rzucić okiem na wiki '' gtable' (https://github.com/baptiste/gtable/wiki/Description) – Henrik

Odpowiedz

11

Oto kroki, aby uzyskać układ, który opisywać:

1) wypis legendę jako osobny Grob („obiekt graficzny”). Możemy wtedy rozłożyć legendy oddzielnie od fabuły.

2) Wyrównaj do lewej krawędzi czterech działek, tak aby lewa krawędź i skala x układały się prawidłowo. Kod do tego pochodzi z this SO answer. Ta odpowiedź ma funkcję wyrównania dowolnej liczby wątków, ale nie byłem w stanie tego zrobić, gdy chciałem zmienić proporcjonalną przestrzeń przydzieloną do każdego wątku, więc skończyłem robiąc to "długą drogę" przez dostosowywanie każdej działki osobno.

3) Rozłóż wykresy i legendę za pomocą grid.arrange i arrangeGrob. Argument heights przydziela różne proporcje całkowitej pionowej przestrzeni do każdego wykresu. Używamy również argumentu widths, aby przydzielić przestrzeń poziomą do wykresów w jednej szerokiej kolumnie, a legendę w innej wąskiej kolumnie.

4) Wykreśl urządzenie w dowolnym rozmiarze. W ten sposób uzyskujesz określony kształt lub proporcje.

library(gridExtra) 
library(grid) 

# Function to extract the legend from a ggplot graph as a separate grob 
# Source: https://stackoverflow.com/a/12539820/496488 
get_leg = function(a.gplot){ 
    tmp <- ggplot_gtable(ggplot_build(a.gplot)) 
    leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box") 
    legend <- tmp$grobs[[leg]] 
    legend 
} 

# Get legend as a separate grob 
leg = get_leg(site_status) 

# Add a theme element to change the plot margins to remove white space between the plots 
thm = theme(plot.margin=unit(c(0,0,-0.5,0),"lines")) 

# Left-align the four plots 
# Adapted from: https://stackoverflow.com/a/13295880/496488 
gA <- ggplotGrob(bar + thm) 
gB <- ggplotGrob(smoke_status + thm) 
gC <- ggplotGrob(hpv_status + thm) 
gD <- ggplotGrob(site_status + theme(plot.margin=unit(c(0,0,0,0), "lines")) + 
        guides(fill=FALSE)) 

maxWidth = grid::unit.pmax(gA$widths[2:5], gB$widths[2:5], gC$widths[2:5], gD$widths[2:5]) 
gA$widths[2:5] <- as.list(maxWidth) 
gB$widths[2:5] <- as.list(maxWidth) 
gC$widths[2:5] <- as.list(maxWidth) 
gD$widths[2:5] <- as.list(maxWidth) 

# Lay out plots and legend 
p = grid.arrange(arrangeGrob(gA,gB,gC,gD, heights=c(0.5,0.15,0.15,0.21)), 
       leg, ncol=2, widths=c(0.8,0.2)) 

Następnie można określić kształt lub współczynnik kształtu końcowego wydruku, ustawiając parametry urządzenia wyjściowego. (Może być konieczne dostosowanie rozmiarów czcionek podczas tworzenia bazowych wykresów, aby ostateczny układ wyglądał tak, jak tego chcesz.) Wykres wklejony poniżej to png zapisany bezpośrednio w oknie wykresu RStudio. Oto jak można zapisać wykres jako plik PDF (ale istnieje wiele innych „urządzeń” można użyć (na przykład, PNG, JPEG, itd.), Aby zapisać w różnych formatach):

pdf("myPlot.pdf", width=10, height=5) 
p 
dev.off() 

enter image description here

Pytasz również o bardziej efektywny kod. Jedną z rzeczy, którą możesz zrobić, jest utworzenie listy elementów wykresu, których używasz wiele razy, a następnie po prostu dodaj nazwę obiektu listy do każdego wykresu. Na przykład:

my_gg = list(geom_bar(stat="identity", fill="red"), 
      theme(legend.position = "none", 
        axis.title.x = element_blank(), 
        axis.ticks.x = element_blank(), 
        axis.text.x = element_blank()), 
        plot.margin = unit(c(0,0,-0.5,0), "lines")) 

smoke_status = ggplot(data, aes(x=pt_id, y=smoke)) + 
        labs(y="Smoking Status") + 
        my_gg