Problema com ggplot2, geom_bar e position = “dodge”: o stacked tem valores y corretos, dodged não

Estou tendo bastante tempo compreendendo geom_bar() e position="dodge" . Eu estava tentando fazer alguns charts de barras ilustrando dois grupos. Originalmente, os dados eram de dois frameworks de dados separados. Por essa pergunta , eu coloquei meus dados em formato longo. Meu exemplo:

 test <- data.frame(names=rep(c("A","B","C"), 5), values=1:15) test2 <- data.frame(names=c("A","B","C"), values=5:7) df <- data.frame(names=c(paste(test$names), paste(test2$names)), num=c(rep(1, nrow(test)), rep(2, nrow(test2))), values=c(test$values, test2$values)) 

Eu uso esse exemplo como é semelhante ao exemplo de gasto versus orçamento. Os gastos têm muitas linhas por nível de fator de names , enquanto o orçamento tem apenas um (um valor de orçamento por categoria).

Para um gráfico de barras empilhadas, isso funciona muito bem:

 ggplot(df, aes(x=factor(names), y=values, fill=factor(num))) + geom_bar(stat="identity") 

lote empilhado

Em particular, observe o valor y maxes. São as sums dos dados do test com os valores do test2 mostrados em azul na parte superior.

Com base em outras perguntas que li, eu simplesmente preciso adicionar position="dodge" para torná-lo um gráfico lado a lado versus um gráfico empilhado:

 ggplot(df, aes(x=factor(names), y=values, fill=factor(num))) + geom_bar(stat="identity", position="dodge") 

esquivado

Parece ótimo, mas observe os novos valores max y. Parece que ele está apenas tomando o valor máximo de y de cada nível de fator de nomes do test para o valor de y. Não está mais resumindo.

Por algumas outras perguntas (como esta e esta , eu também tentei adicionar a opção group= sem sucesso (produz o mesmo esquema dodged como acima):

 ggplot(df, aes(x=factor(names), y=values, fill=factor(num), group=factor(num))) + geom_bar(stat="identity", position="dodge") 

Eu não entendo porque o stacked funciona muito bem e o dodged não apenas os coloca lado a lado ao invés de no topo.


ETA: Eu encontrei uma pergunta recente sobre isso no grupo do google ggplot com a sugestão de adicionar alpha=0.5 para ver o que está acontecendo. Não é que ggplot esteja tirando o valor máximo de cada agrupamento; na verdade, há um excesso de plotagem de barras uma sobre a outra para cada valor.

Parece que ao usar position="dodge" , ggplot espera apenas um y por x. Eu entrei em contato com Winston Chang, um desenvolvedor ggplot sobre isso para confirmar, bem como para saber se isso pode ser alterado, pois não vejo uma vantagem.

Parece que stat="identity" deve dizer ao ggplot para calcular y=val passado dentro de aes() invés de contagens individuais que acontecem sem stat="identity" e ao passar nenhum valor de y.

Por enquanto, a solução alternativa parece ser (para o original df acima) agregar, portanto, há apenas um y por x:

 df2 <- aggregate(df$values, by=list(df$names, df$num), FUN=sum) p <- ggplot(df2, aes(x=Group.1, y=x, fill=factor(Group.2))) p <- p + geom_bar(stat="identity", position="dodge") p 

corrigir

Eu acho que o problema é que você quer empilhar dentro dos valores do grupo num , e evitar entre valores de num . Pode ajudar a ver o que acontece quando você adiciona um contorno às barras.

 library(ggplot2) set.seed(123) df <- data.frame( id = 1:18, names = rep(LETTERS[1:3], 6), num = c(rep(1, 15), rep(2, 3)), values = sample(1:10, 18, replace=TRUE) ) 

Por padrão, há muitas barras empilhadas - você simplesmente não vê que elas estão separadas, a menos que você tenha um esboço:

 # Stacked bars ggplot(df, aes(x=factor(names), y=values, fill=factor(num))) + geom_bar(stat="identity", colour="black") 

Barras empilhadas

Se você esquivar, você obtém barras que são esquivadas entre valores de num , mas pode haver várias barras dentro de cada valor de num :

 # Dodged on 'num', but some overplotted bars ggplot(df, aes(x=factor(names), y=values, fill=factor(num))) + geom_bar(stat="identity", colour="black", position="dodge", alpha=0.1) 

Dodged on num

Se você também adicionar id como um agrupamento var, ele irá desviar de todos eles:

 # Dodging with unique 'id' as the grouping var ggplot(df, aes(x=factor(names), y=values, fill=factor(num), group=factor(id))) + geom_bar(stat="identity", colour="black", position="dodge", alpha=0.1) 

Esquivar todas as barras

Eu acho que o que você quer é esquivar e empilhar, mas você não pode fazer as duas coisas. Então, o melhor é resumir os dados por conta própria.

 library(plyr) df2 <- ddply(df, c("names", "num"), summarise, values = sum(values)) ggplot(df2, aes(x=factor(names), y=values, fill=factor(num))) + geom_bar(stat="identity", colour="black", position="dodge") 

Resumido de antemão