zij-aan-zij percelen met GGPLOT2

Ik wil twee percelen naast elkaar plaatsen met behulp van de ggplot2-pakket , dat wil zeggen het equivalent van par(mfrow=c(1,2)).

Ik zou bijvoorbeeld de volgende twee percelen zien show naast elkaar met dezelfde schaal.

x <- rnorm(100)
eps <- rnorm(100,0,.2)
qplot(x,3*x+eps)
qplot(x,2*x+eps)

Moet ik ze in dezelfde gegevens plaatsen. Frame?

qplot(displ, hwy, data=mpg, facets = . ~ year) + geom_smooth()

Antwoord 1, Autoriteit 100%

Alle ggsplots naast elkaar (of n plots op een raster)

De functie grid.arrange()in de gridExtrapakket combineert meerdere percelen; Dit is hoe je twee naast elkaar legt.

require(gridExtra)
plot1 <- qplot(1)
plot2 <- qplot(1)
grid.arrange(plot1, plot2, ncol=2)

Dit is handig wanneer de twee percelen niet op dezelfde gegevens zijn gebaseerd, bijvoorbeeld als u verschillende variabelen wilt plotten zonder opnieuw gebruik van Reshape ().

Hiermee wordt de uitvoer inzet als een bijwerking. Om het bijwerking op een bestand af te drukken, geeft u een apparaatstuurprogramma op (zoals pdf, png, ENC), E.g.

pdf("foo.pdf")
grid.arrange(plot1, plot2)
dev.off()

of, gebruik arrangeGrob()in combinatie met ggsave(),

ggsave("foo.pdf", arrangeGrob(plot1, plot2))

Dit is het equivalent van het maken van twee verschillende plots met par(mfrow=c(1,2)). Dit bespaart niet alleen tijdregistratie van gegevens, het is noodzakelijk wanneer u twee ongelijke plots wilt.


Bijlage: Facetten

gebruiken

Facetten zijn nuttig voor het maken van vergelijkbare plots voor verschillende groepen. Dit wordt hieronder opgemerkt in vele antwoorden hieronder, maar ik wil deze aanpak met voorbeelden die gelijkwaardig zijn aan de bovenstaande percelen benadrukt.

mydata <- data.frame(myGroup = c('a', 'b'), myX = c(1,1))
qplot(data = mydata, 
    x = myX, 
    facets = ~myGroup)
ggplot(data = mydata) + 
    geom_bar(aes(myX)) + 
    facet_wrap(~myGroup)

Update

De plot_gridFunctie in de cowplotis de moeite waard om te bekijken als een alternatief voor grid.arrange. Zie de Antwoord door @ Claus-Wilke hieronder en dit vignet voor een equivalente aanpak; Maar de functie maakt fijnere bedieningselementen op perceel en grootte, gebaseerd op dit vignet .


Antwoord 2, Autoriteit 35%

Eén nadeel van de oplossingen op basis van grid.arrangeis dat ze het moeilijk maken om de percelen te labelen met letters (A, B, etc.), zoals de meeste tijdschriften nodig hebben.

Ik schreef de cowplot pakket om dit op te lossen (en Een paar andere) problemen, met name de functie plot_grid():

library(cowplot)
iris1 <- ggplot(iris, aes(x = Species, y = Sepal.Length)) +
  geom_boxplot() + theme_bw()
iris2 <- ggplot(iris, aes(x = Sepal.Length, fill = Species)) +
  geom_density(alpha = 0.7) + theme_bw() +
  theme(legend.position = c(0.8, 0.8))
plot_grid(iris1, iris2, labels = "AUTO")

Het object dat plot_grid()retourneert is een ander ggplot2-object en u kunt het zoals gewoonlijk opslaan met ggsave():

p <- plot_grid(iris1, iris2, labels = "AUTO")
ggsave("plot.pdf", p)

Als alternatief kunt u de cowplot-functie save_plot()gebruiken, een dunne wikkel rond ggsave()die het gemakkelijk maakt om de juiste afmetingen voor gecombineerde plots te krijgen , bijvoorbeeld:

p <- plot_grid(iris1, iris2, labels = "AUTO")
save_plot("plot.pdf", p, ncol = 2)

(Het argument ncol = 2vertelt save_plot()dat er twee plots naast elkaar zijn, en save_plot()maakt de opgeslagen afbeelding twee keer zo breed.)

Voor een meer diepgaande beschrijving van het rangschikken van plots in een raster, zie dit vignet.Er is ook een vignet waarin wordt uitgelegd hoe u plots kunt maken met een gedeelde legende.

Een veel voorkomend punt van verwarring is dat het cowplot-pakket het standaard ggplot2-thema verandert. Het pakket gedraagt zich zo omdat het oorspronkelijk is geschreven voor intern laboratoriumgebruik en we gebruiken nooit het standaardthema. Als dit problemen veroorzaakt, kunt u een van de volgende drie benaderingen gebruiken om ze te omzeilen:

1. Stel het thema handmatig in voor elke plot.Ik denk dat het een goede gewoonte is om altijd een bepaald thema voor elke plot op te geven, net zoals ik deed met + theme_bw()in het bovenstaande voorbeeld. Als je een bepaald thema opgeeft, maakt het standaardthema niet uit.

2. Zet het standaardthema terug naar de ggplot2-standaard.U kunt dit doen met één regel code:

theme_set(theme_gray())

3. Roep cowplot-functies aan zonder het pakket toe te voegen.U kunt ook niet library(cowplot)of require(cowplot)aanroepen en in plaats daarvan cowplot-functies aanroepen door cowplot::. Het bovenstaande voorbeeld met het standaardthema ggplot2 zou bijvoorbeeld worden:

## Commented out, we don't call this
# library(cowplot)
iris1 <- ggplot(iris, aes(x = Species, y = Sepal.Length)) +
  geom_boxplot()
iris2 <- ggplot(iris, aes(x = Sepal.Length, fill = Species)) +
  geom_density(alpha = 0.7) +
  theme(legend.position = c(0.8, 0.8))
cowplot::plot_grid(iris1, iris2, labels = "AUTO")

Updates:

  • Vanaf cowplot 1.0 is het standaard ggplot2-thema niet meer gewijzigd.
  • Vanaf ggplot2 3.0.0 kunnen plots direct gelabeld worden, zie b.v. hier.

Antwoord 3, autoriteit 9%

U kunt de volgende multiplot-functie gebruiken van Winston Chang’s R kookboek

multiplot(plot1, plot2, cols=2)

multiplot <- function(..., plotlist=NULL, cols) {
    require(grid)
    # Make a list from the ... arguments and plotlist
    plots <- c(list(...), plotlist)
    numPlots = length(plots)
    # Make the panel
    plotCols = cols                          # Number of columns of plots
    plotRows = ceiling(numPlots/plotCols) # Number of rows needed, calculated from # of cols
    # Set up the page
    grid.newpage()
    pushViewport(viewport(layout = grid.layout(plotRows, plotCols)))
    vplayout <- function(x, y)
        viewport(layout.pos.row = x, layout.pos.col = y)
    # Make each plot, in the correct location
    for (i in 1:numPlots) {
        curRow = ceiling(i/plotCols)
        curCol = (i-1) %% plotCols + 1
        print(plots[[i]], vp = vplayout(curRow, curCol ))
    }
}

Antwoord 4, autoriteit 9%

Met behulp van het patchworkpakket, kunt u eenvoudig de +operator:

library(ggplot2)
library(patchwork)
p1 <- ggplot(mtcars) + geom_point(aes(mpg, disp))
p2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))
p1 + p2

Andere exploitanten zijn onder meer /om plots te stappen om percelen naast elkaar te plaatsen, en ()naar groepselementen. U kunt bijvoorbeeld een bovenste rij van 3 percelen en een onderste rij van één plot configureren met (p1 | p2 | p3) /p. Zie voor meer voorbeelden de pakketdocumentatie .


Antwoord 5, Autoriteit 3%

Ja, methinks, u moet uw gegevens op de juiste manier regelen. Een manier zou dit zijn:

X <- data.frame(x=rep(x,2),
                y=c(3*x+eps, 2*x+eps),
                case=rep(c("first","second"), each=100))
qplot(x, y, data=X, facets = . ~ case) + geom_smooth()

Ik weet zeker dat er betere trucs zijn in PLYR of Reshape – ik ben nog steeds niet echt op de hoogte
op al deze krachtige pakketten door Hadley.


Antwoord 6, Autoriteit 3%

Gebruik van het reshape-pakket dat u zoiets kunt doen.

library(ggplot2)
wide <- data.frame(x = rnorm(100), eps = rnorm(100, 0, .2))
wide$first <- with(wide, 3 * x + eps)
wide$second <- with(wide, 2 * x + eps)
long <- melt(wide, id.vars = c("x", "eps"))
ggplot(long, aes(x = x, y = value)) + geom_smooth() + geom_point() + facet_grid(.~ variable)

Antwoord 7, Autoriteit 2%

Er is ook Multipanelfigure-pakket dat is de moeite waard om te noemen. Zie ook dit antwoord .

library(ggplot2)
theme_set(theme_bw())
q1 <- ggplot(mtcars) + geom_point(aes(mpg, disp))
q2 <- ggplot(mtcars) + geom_boxplot(aes(gear, disp, group = gear))
q3 <- ggplot(mtcars) + geom_smooth(aes(disp, qsec))
q4 <- ggplot(mtcars) + geom_bar(aes(carb))
library(magrittr)
library(multipanelfigure)
figure1 <- multi_panel_figure(columns = 2, rows = 2, panel_label_type = "none")
# show the layout
figure1

figure1 %<>%
  fill_panel(q1, column = 1, row = 1) %<>%
  fill_panel(q2, column = 2, row = 1) %<>%
  fill_panel(q3, column = 1, row = 2) %<>%
  fill_panel(q4, column = 2, row = 2)
figure1

# complex layout
figure2 <- multi_panel_figure(columns = 3, rows = 3, panel_label_type = "upper-roman")
figure2

figure2 %<>%
  fill_panel(q1, column = 1:2, row = 1) %<>%
  fill_panel(q2, column = 3, row = 1) %<>%
  fill_panel(q3, column = 1, row = 2) %<>%
  fill_panel(q4, column = 2:3, row = 2:3)
figure2

Gemaakt op 2018-07-06 door het reprex-pakket(v0.2.0.9000).


Antwoord 8, autoriteit 2%

ggplot2 is gebaseerd op rasterafbeeldingen, die een ander systeem bieden voor het rangschikken van plots op een pagina. De opdracht par(mfrow...)heeft geen direct equivalent, aangezien rasterobjecten (genaamd grobs) niet noodzakelijk onmiddellijk worden getekend, maar kunnen worden opgeslagen en gemanipuleerd als gewone R-objecten voordat ze worden geconverteerd naar een grafische uitvoer. Dit maakt meer flexibiliteit mogelijk dan het draw this nowmodel van basisafbeeldingen, maar de strategie is noodzakelijkerwijs een beetje anders.

Ik heb grid.arrange()geschreven om een eenvoudige interface te bieden die zo dicht mogelijk bij par(mfrow)ligt. In zijn eenvoudigste vorm zou de code er als volgt uitzien:

library(ggplot2)
x <- rnorm(100)
eps <- rnorm(100,0,.2)
p1 <- qplot(x,3*x+eps)
p2 <- qplot(x,2*x+eps)
library(gridExtra)
grid.arrange(p1, p2, ncol = 2)

Meer opties worden gedetailleerd beschreven in dit vignet.

Een veelgehoorde klacht is dat plots niet noodzakelijk uitgelijnd zijn, b.v. wanneer ze aslabels van verschillende grootte hebben, maar dit is zo ontworpen: grid.arrangedoet geen poging om ggplot2-objecten in speciale gevallen te plaatsen, en behandelt ze gelijk aan andere grobs (roosterplots, bijvoorbeeld). Het plaatst alleen grobs in een rechthoekige lay-out.

Voor het speciale geval van ggplot2-objecten heb ik een andere functie geschreven, ggarrange, met een vergelijkbare interface, die probeert plotpanelen (inclusief gefacetteerde plots) uit te lijnen en probeert de beeldverhoudingen te respecteren wanneer deze zijn gedefinieerd door de gebruiker.

library(egg)
ggarrange(p1, p2, ncol = 2)

Beide functies zijn compatibel met ggsave(). Voor een algemeen overzicht van de verschillende opties, en een historische context, dit Vignet biedt aanvullende informatie .


Antwoord 9, Autoriteit 2%

update: Dit antwoord is erg oud. gridExtra::grid.arrange()is nu de aanbevolen aanpak.
Ik laat dit hier in het geval dat het nuttig kan zijn.


Stephen Turner Geplaatst de arrange()FUNCTION op Getting Genetics Gereed blog (zie bericht voor toepassingsinstructies)

vp.layout <- function(x, y) viewport(layout.pos.row=x, layout.pos.col=y)
arrange <- function(..., nrow=NULL, ncol=NULL, as.table=FALSE) {
 dots <- list(...)
 n <- length(dots)
 if(is.null(nrow) & is.null(ncol)) { nrow = floor(n/2) ; ncol = ceiling(n/nrow)}
 if(is.null(nrow)) { nrow = ceiling(n/ncol)}
 if(is.null(ncol)) { ncol = ceiling(n/nrow)}
        ## NOTE see n2mfrow in grDevices for possible alternative
grid.newpage()
pushViewport(viewport(layout=grid.layout(nrow,ncol) ) )
 ii.p <- 1
 for(ii.row in seq(1, nrow)){
 ii.table.row <- ii.row 
 if(as.table) {ii.table.row <- nrow - ii.table.row + 1}
  for(ii.col in seq(1, ncol)){
   ii.table <- ii.p
   if(ii.p > n) break
   print(dots[[ii.table]], vp=vp.layout(ii.table.row, ii.col))
   ii.p <- ii.p + 1
  }
 }
}

Antwoord 10

Gebruik tidyverse:

x <- rnorm(100)
eps <- rnorm(100,0,.2)
df <- data.frame(x, eps) %>% 
  mutate(p1 = 3*x+eps, p2 = 2*x+eps) %>% 
  tidyr::gather("plot", "value", 3:4) %>% 
  ggplot(aes(x = x , y = value)) + 
    geom_point() + 
    geom_smooth() + 
    facet_wrap(~plot, ncol =2)
df


Antwoord 11

De bovenstaande oplossingen zijn mogelijk niet efficiënt als u meerdere ggplot-plots wilt plotten met behulp van een lus (bijvoorbeeld zoals hier gevraagd: Meerdere plots maken in ggplot met verschillende Y-as-waarden met behulp van een lus), wat een gewenste stap is bij het analyseren van het onbekende (of grote) datasets (bijv. als je Tellingen van alle variabelen in een dataset wilt plotten).

De onderstaande code laat zien hoe je dat kunt doen met de hierboven genoemde ‘multiplot()’, waarvan de bron hier staat: http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_(ggplot2):

plotAllCounts <- function (dt){   
  plots <- list();
  for(i in 1:ncol(dt)) {
    strX = names(dt)[i]
    print(sprintf("%i: strX = %s", i, strX))
    plots[[i]] <- ggplot(dt) + xlab(strX) +
      geom_point(aes_string(strX),stat="count")
  }
  columnsToPlot <- floor(sqrt(ncol(dt)))
  multiplot(plotlist = plots, cols = columnsToPlot)
}

Voer nu de functie uit – om tellingen voor alle variabelen afgedrukt te krijgen met ggplot op één pagina

dt = ggplot2::diamonds
plotAllCounts(dt)

Een ding om op te merken is dat:
met behulp van aes(get(strX)), die u normaal gesproken in lussen zou gebruiken bij het werken met ggplot, in de bovenstaande code in plaats van aes_string(strX)zal NIET de gewenste plots tekenen. In plaats daarvan zal het de laatste plot vele malen plotten. Ik heb niet ontdekt waarom – het kan zijn dat de aesen aes_stringworden aangeroepen in ggplot.

Anders hoop ik dat je de functie nuttig vindt.


Antwoord 12

In mijn ervaring werkt gridExtra:grid.arrange perfect, als je plots in een lus probeert te genereren.

Kort codefragment:

gridExtra::grid.arrange(plot1, plot2, ncol = 2)

** Deze opmerking bijwerken om te laten zien hoe u grid.arrange()binnen een for-lus gebruikt om plots te genereren voor verschillende factoren van een categorische variabele.

for (bin_i in levels(athlete_clean$BMI_cat)) {
plot_BMI <- athlete_clean %>% filter(BMI_cat == bin_i) %>% group_by(BMI_cat,Team) %>% summarize(count_BMI_team = n()) %>% 
          mutate(percentage_cbmiT = round(count_BMI_team/sum(count_BMI_team) * 100,2)) %>% 
          arrange(-count_BMI_team) %>% top_n(10,count_BMI_team) %>% 
          ggplot(aes(x = reorder(Team,count_BMI_team), y = count_BMI_team, fill = Team)) +
            geom_bar(stat = "identity") +
            theme_bw() +
            # facet_wrap(~Medal) +
            labs(title = paste("Top 10 Participating Teams with \n",bin_i," BMI",sep=""), y = "Number of Athletes", 
                 x = paste("Teams - ",bin_i," BMI Category", sep="")) +
            geom_text(aes(label = paste(percentage_cbmiT,"%",sep = "")), 
                      size = 3, check_overlap = T,  position = position_stack(vjust = 0.7) ) +
            theme(axis.text.x = element_text(angle = 00, vjust = 0.5), plot.title = element_text(hjust = 0.5), legend.position = "none") +
            coord_flip()
plot_BMI_Medal <- athlete_clean %>% 
          filter(!is.na(Medal), BMI_cat == bin_i) %>% 
          group_by(BMI_cat,Team) %>% 
          summarize(count_BMI_team = n()) %>% 
          mutate(percentage_cbmiT = round(count_BMI_team/sum(count_BMI_team) * 100,2)) %>% 
          arrange(-count_BMI_team) %>% top_n(10,count_BMI_team) %>% 
          ggplot(aes(x = reorder(Team,count_BMI_team), y = count_BMI_team, fill = Team)) +
            geom_bar(stat = "identity") +
            theme_bw() +
            # facet_wrap(~Medal) +
            labs(title = paste("Top 10 Winning Teams with \n",bin_i," BMI",sep=""), y = "Number of Athletes", 
                 x = paste("Teams - ",bin_i," BMI Category", sep="")) +
            geom_text(aes(label = paste(percentage_cbmiT,"%",sep = "")), 
                      size = 3, check_overlap = T,  position = position_stack(vjust = 0.7) ) +
            theme(axis.text.x = element_text(angle = 00, vjust = 0.5), plot.title = element_text(hjust = 0.5), legend.position = "none") +
            coord_flip()
gridExtra::grid.arrange(plot_BMI, plot_BMI_Medal, ncol = 2)
}

Een van de voorbeeldplots uit de bovenstaande for-lus is hieronder opgenomen.
De bovenstaande lus zal meerdere plots produceren voor alle niveaus van de BMI-categorie.

Voorbeeldafbeelding

Als je een uitgebreider gebruik van grid.arrange()binnen forloops wilt zien, ga dan naar https://rpubs.com/Mayank7j_2020/olympic_data_2000_2016


Antwoord 13

Het pakket cowplotgeeft je een mooie manier om dit te doen, op een manier die past bij publicatie.

x <- rnorm(100)
eps <- rnorm(100,0,.2)
A = qplot(x,3*x+eps, geom = c("point", "smooth"))+theme_gray()
B = qplot(x,2*x+eps, geom = c("point", "smooth"))+theme_gray()
cowplot::plot_grid(A, B, labels = c("A", "B"), align = "v")

Other episodes