usando stat_function e facet_wrap insieme in ggplot2 in R

Sto cercando di tracciare i dati di tipo reticolo con ggplot2 e quindi sovrapporre una distribuzione normale sui dati di esempio per illustrare quanto lontano siano normali i dati sottostanti. Mi piacerebbe avere il dist normale in cima per avere la stessa media e stdev del pannello.

ecco un esempio:

library(ggplot2) #make some example data dd<-data.frame(matrix(rnorm(144, mean=2, sd=2),72,2),c(rep("A",24),rep("B",24),rep("C",24))) colnames(dd) <- c("x_value", "Predicted_value", "State_CD") #This works pg <- ggplot(dd) + geom_density(aes(x=Predicted_value)) + facet_wrap(~State_CD) print(pg) 

Tutto funziona alla grande e produce un bel grafico a tre riquadri dei dati. Come aggiungo il dist normale alla parte superiore? Sembra che userei stat_function, ma questo fallisce:

 #this fails pg <- ggplot(dd) + geom_density(aes(x=Predicted_value)) + stat_function(fun=dnorm) + facet_wrap(~State_CD) print(pg) 

Sembra che stat_function non stia andando d’accordo con la funzione facet_wrap. Come faccio a far giocare bene questi due?

————MODIFICARE———

Ho cercato di integrare le idee di due delle risposte qui sotto e io ancora non ci sono:

usando una combinazione di entrambe le risposte posso fare a pezzi insieme questo:

 library(ggplot) library(plyr) #make some example data dd<-data.frame(matrix(rnorm(108, mean=2, sd=2),36,2),c(rep("A",24),rep("B",24),rep("C",24))) colnames(dd) <- c("x_value", "Predicted_value", "State_CD") DevMeanSt <- ddply(dd, c("State_CD"), function(df)mean(df$Predicted_value)) colnames(DevMeanSt) <- c("State_CD", "mean") DevSdSt <- ddply(dd, c("State_CD"), function(df)sd(df$Predicted_value) ) colnames(DevSdSt) <- c("State_CD", "sd") DevStatsSt <- merge(DevMeanSt, DevSdSt) pg <- ggplot(dd, aes(x=Predicted_value)) pg <- pg + geom_density() pg <- pg + stat_function(fun=dnorm, colour='red', args=list(mean=DevStatsSt$mean, sd=DevStatsSt$sd)) pg <- pg + facet_wrap(~State_CD) print(pg) 

che è molto vicino … eccetto che qualcosa non va nel normale diagramma dist:

inserisci la descrizione dell'immagine qui

cosa sto facendo di sbagliato qui?

stat_function è progettato per sovrapporre la stessa funzione in ogni pannello. (Non esiste un modo ovvio per abbinare i parametri della funzione con i diversi pannelli).

Come suggerisce Ian, il modo migliore è generare da soli le curve normali e tracciarle come set di dati separati (questo è il punto in cui avevi sbagliato in precedenza: la fusione non ha senso per questo esempio e se guardi attentamente vedi perché stai ricevendo lo strano motivo a dente di sega).

Ecco come andrei a risolvere il problema:

 dd < - data.frame( predicted = rnorm(72, mean = 2, sd = 2), state = rep(c("A", "B", "C"), each = 24) ) grid <- with(dd, seq(min(predicted), max(predicted), length = 100)) normaldens <- ddply(dd, "state", function(df) { data.frame( predicted = grid, density = dnorm(grid, mean(df$predicted), sd(df$predicted)) ) }) ggplot(dd, aes(predicted)) + geom_density() + geom_line(aes(y = density), data = normaldens, colour = "red") + facet_wrap(~ state) 

inserisci la descrizione dell'immagine qui

Penso che tu debba fornire più informazioni. Questo sembra funzionare:

  pg < - ggplot(dd, aes(Predicted_value)) ## need aesthetics in the ggplot pg <- pg + geom_density() ## gotta provide the arguments of the dnorm pg <- pg + stat_function(fun=dnorm, colour='red', args=list(mean=mean(dd$Predicted_value), sd=sd(dd$Predicted_value))) ## wrap it! pg <- pg + facet_wrap(~State_CD) pg 

Stiamo fornendo lo stesso parametro medio e sd per ogni pannello. Ottenere mezzi specifici del pannello e deviazioni standard è lasciato come esercizio al lettore *;)

'*' In altre parole, non sono sicuro di come possa essere fatto ...

Penso che la soluzione migliore sia disegnare manualmente la linea con geom_line.

 dd< -data.frame(matrix(rnorm(144, mean=2, sd=2),72,2),c(rep("A",24),rep("B",24),rep("C",24))) colnames(dd) <- c("x_value", "Predicted_value", "State_CD") dd$Predicted_value<-dd$Predicted_value*as.numeric(dd$State_CD) #make different by state ##Calculate means and standard deviations by level means<-as.numeric(by(dd[,2],dd$State_CD,mean)) sds<-as.numeric(by(dd[,2],dd$State_CD,sd)) ##Create evenly spaced evaluation points +/- 3 standard deviations away from the mean dd$vals<-0 for(i in 1:length(levels(dd$State_CD))){ dd$vals[dd$State_CD==levels(dd$State_CD)[i]]<-seq(from=means[i]-3*sds[i], to=means[i]+3*sds[i], length.out=sum(dd$State_CD==levels(dd$State_CD)[i])) } ##Create normal density points dd$norm<-with(dd,dnorm(vals,means[as.numeric(State_CD)], sds[as.numeric(State_CD)])) pg <- ggplot(dd, aes(Predicted_value)) pg <- pg + geom_density() pg <- pg + geom_line(aes(x=vals,y=norm),colour="red") #Add in normal distribution pg <- pg + facet_wrap(~State_CD,scales="free") pg 

Se non vuoi generare il normale grafico a linee di distribuzione “a mano”, usa ancora stat_function e mostra i grafici fianco a fianco – allora potresti prendere in considerazione l’uso della funzione “multiplot” pubblicata su “Cookbook for R” in alternativa a facet_wrap. Da qui puoi copiare il codice multiplot nel tuo progetto.

Dopo aver copiato il codice, effettuare le seguenti operazioni:

 # Some fake data (copied from hadley's answer) dd < - data.frame( predicted = rnorm(72, mean = 2, sd = 2), state = rep(c("A", "B", "C"), each = 24) ) # Split the data by state, apply a function on each member that converts it into a # plot object, and return the result as a vector. plots <- lapply(split(dd,dd$state),FUN=function(state_slice){ # The code here is the plot code generation. You can do anything you would # normally do for a single plot, such as calling stat_function, and you do this # one slice at a time. ggplot(state_slice, aes(predicted)) + geom_density() + stat_function(fun=dnorm, args=list(mean=mean(state_slice$predicted), sd=sd(state_slice$predicted)), color="red") }) # Finally, present the plots on 3 columns. multiplot(plotlist = plots, cols=3) 

inserisci la descrizione dell'immagine qui