usando stat_function e facet_wrap juntos em ggplot2 em R

Estou tentando plotar dados do tipo de rede com ggplot2 e, em seguida, sobrepondo uma distribuição normal sobre os dados de amostra para ilustrar o quão fora do normal os dados subjacentes estão. Eu gostaria de ter o normal dist no topo para ter a mesma média e stdev como o painel.

aqui está um exemplo:

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) 

Isso tudo funciona muito bem e produz um bom gráfico de três painéis dos dados. Como eu adiciono a dist normal no topo? Parece que eu usaria stat_function, mas isso falha:

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

Parece que a function stat não está se dando bem com o recurso facet_wrap. Como obtenho esses dois para jogar bem?

————EDITAR———

Tentei integrar idéias de duas das respostas abaixo e ainda não estou lá:

usando uma combinação de ambas as respostas eu posso hackear isso:

 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) 

o que é realmente próximo … exceto que algo está errado com a representação gráfica normal:

insira a descrição da imagem aqui

O que estou fazendo de errado aqui?

stat_function é projetado para sobrepor a mesma function em cada painel. (Não há uma maneira óbvia de combinar os parâmetros da function com os diferentes painéis).

Como Ian sugere, a melhor maneira é gerar as curvas normais e traçá-las como um dataset separado (é aí que você estava errando antes – mesclar simplesmente não faz sentido para este exemplo e, se você olhar com cuidado, você Veja que é por isso que você está obtendo o padrão estranho dente de serra).

Aqui está como eu resolvo o 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) 

insira a descrição da imagem aqui

Eu acho que você precisa fornecer mais informações. Isso parece funcionar:

  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 

Estamos fornecendo o mesmo parâmetro mean e sd para cada painel. Obter médias específicas do painel e desvios padrão é deixado como um exercício para o leitor *;)

'*' Em outras palavras, não tenho certeza de como isso pode ser feito ...

Eu acho que sua melhor aposta é desenhar a linha manualmente com 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 você não quiser gerar o gráfico de linhas de distribuição normal “à mão”, ainda use stat_function e mostre charts lado a lado – então você pode considerar usar a function “multiplot” publicada no “Cookbook for R” como uma alternativa para facet_wrap. Você pode copiar o código multiplot para o seu projeto daqui .

Depois de copiar o código, faça o seguinte:

 # 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) 

insira a descrição da imagem aqui