Não deixe cair a contagem zero: barplot esquivado

Eu estou fazendo um barplot esquivado em ggplot2 e um agrupamento tem uma contagem zero que eu quero exibir. Lembrei-me de ver isso aqui há algum tempo e percebi que o scale_x_discrete(drop=F) iria funcionar. Não parece funcionar com barras desviadas. Como posso mostrar as contagens zero?

Por exemplo, (código abaixo) no gráfico abaixo, type8 ~ group4 não tem exemplos. Eu ainda gostaria que a trama exibisse o espaço vazio para a contagem zero em vez de eliminar a barra. Como posso fazer isso?

insira a descrição da imagem aqui

 mtcars2 <- data.frame(type=factor(mtcars$cyl), group=factor(mtcars$gear)) m2 <- ggplot(mtcars2, aes(x=type , fill=group)) p2 <- m2 + geom_bar(colour="black", position="dodge") + scale_x_discrete(drop=F) p2 

A única maneira que conheço é pré-calcular as contagens e adicionar uma linha fictícia:

 dat <- rbind(ddply(mtcars2,.(type,group),summarise,count = length(group)),c(8,4,NA)) ggplot(dat,aes(x = type,y = count,fill = group)) + geom_bar(colour = "black",position = "dodge",stat = "identity") 

insira a descrição da imagem aqui

Eu pensei que usar stat_bin(drop = FALSE,geom = "bar",...) funcionaria, mas aparentemente não funciona.

geom_bar() atualizado precisa de stat = "identity"

Por que vale a pena: A tabela de contagens, dat, acima contém NA. Às vezes, é útil ter um 0 explícito; por exemplo, se o próximo passo é colocar contagens acima das barras. O código a seguir faz exatamente isso, embora provavelmente não seja mais simples que o de Joran. Ele envolve duas etapas: obter uma dcast cruzada das contagens usando dcast , depois derreter a tabela usando o método de melt , seguido por ggplot() como de costume.

 library(ggplot2) library(reshape2) mtcars2 = data.frame(type=factor(mtcars$cyl), group=factor(mtcars$gear)) dat = dcast(mtcars2, type ~ group, fun.aggregate = length) dat.melt = melt(dat, id.vars = "type", measure.vars = c("3", "4", "5")) dat.melt ggplot(dat.melt, aes(x = type,y = value, fill = variable)) + geom_bar(stat = "identity", colour = "black", position = position_dodge(width = .8), width = 0.7) + ylim(0, 14) + geom_text(aes(label = value), position = position_dodge(width = .8), vjust = -0.5) 

insira a descrição da imagem aqui

Fiz essa mesma pergunta, mas só queria usar data.table , pois é uma solução mais rápida para conjuntos de dados muito maiores. Incluí notas sobre os dados para que aqueles que são menos experientes e queiram entender por que fiz o que fiz, possam fazê-lo facilmente. Aqui está como eu manipulei o dataset mtcars :

 library(data.table) library(scales) library(ggplot2) mtcars <- data.table(mtcars) mtcars$Cylinders <- as.factor(mtcars$cyl) # Creates new column with data from cyl called Cylinders as a factor. This allows ggplot2 to automatically use the name "Cylinders" and recognize that it's a factor mtcars$Gears <- as.factor(mtcars$gear) # Just like above, but with gears to Gears setkey(mtcars, Cylinders, Gears) # Set key for 2 different columns mtcars <- mtcars[CJ(unique(Cylinders), unique(Gears)), .N, allow.cartesian = TRUE] # Uses CJ to create a completed list of all unique combinations of Cylinders and Gears. Then counts how many of each combination there are and reports it in a column called "N" 

E aqui está a chamada que produziu o gráfico

 ggplot(mtcars, aes(x=Cylinders, y = N, fill = Gears)) + geom_bar(position="dodge", stat="identity") + ylab("Count") + theme(legend.position="top") + scale_x_discrete(drop = FALSE) 

E isso produz este gráfico:

Gráfico de cilindros

Além disso, se houver dados contínuos, como no dataset de diamonds (graças ao mnel):

 library(data.table) library(scales) library(ggplot2) diamonds <- data.table(diamonds) # I modified the diamonds data set in order to create gaps for illustrative purposes setkey(diamonds, color, cut) diamonds[J("E",c("Fair","Good")), carat := 0] diamonds[J("G",c("Premium","Good","Fair")), carat := 0] diamonds[J("J",c("Very Good","Fair")), carat := 0] diamonds <- diamonds[carat != 0] 

Então, usar o CJ também funcionaria.

 data <- data.table(diamonds)[,list(mean_carat = mean(carat)), keyby = c('cut', 'color')] # This step defines our data set as the combinations of cut and color that exist and their means. However, the problem with this is that it doesn't have all combinations possible data <- data[CJ(unique(cut),unique(color))] # This functions exactly the same way as it did in the discrete example. It creates a complete list of all possible unique combinations of cut and color ggplot(data, aes(color, mean_carat, fill=cut)) + geom_bar(stat = "identity", position = "dodge") + ylab("Mean Carat") + xlab("Color") 

Nos dando este gráfico:

Diamantes Fixo

Veja como você pode fazer isso sem criar tabelas de resumo primeiro.
Ele não funcionou na versão CRAN (2.2.1), mas na última versão de desenvolvimento do ggplot (2.2.1.900) eu não tive problemas.

 ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) + geom_bar(position = position_dodge(preserve = "single")) 

http://ggplot2.tidyverse.org/reference/position_dodge.html

Use count e complete de dplyr para fazer isso.

 library(tidyverse) mtcars %>% mutate( type = as.factor(cyl), group = as.factor(gear) ) %>% count(type, group) %>% complete(type, group, fill = list(n = 0)) %>% ggplot(aes(x = type, y = n, fill = group)) + geom_bar(colour = "black", position = "dodge", stat = "identity") 

Você pode explorar o recurso da function table() , que calcula o número de ocorrências de um fator para todos os seus níveis

 # load plyr package to use ddply library(plyr) # compute the counts using ddply, including zero occurrences for some factor levels df <- ddply(mtcars2, .(group), summarise, types = as.numeric(names(table(type))), counts = as.numeric(table(type))) # plot the results ggplot(df, aes(x = types, y = counts, fill = group)) + geom_bar(stat='identity',colour="black", position="dodge")