No dejes caer la cuenta cero: barra de barras esquivada

Estoy haciendo una barra de barras esquivada en ggplot2 y una agrupación tiene un recuento de cero que quiero mostrar. Recordé haber visto esto en AQUÍ hace un tiempo y pensé que scale_x_discrete(drop=F) funcionaría. No parece funcionar con barras esquivas. ¿Cómo puedo hacer que se muestren los recuentos cero?

Por ejemplo, (código a continuación) en el siguiente diagtwig, escriba 8 ~ group4 no tiene ejemplos. Me gustaría que la ttwig muestre el espacio vacío para el conteo cero en lugar de eliminar la barra. ¿Cómo puedo hacer esto?

enter image description here

 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 

La única forma que conozco es precomputar los recuentos y agregar una fila ficticia:

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

enter image description here

Pensé que usar stat_bin(drop = FALSE,geom = "bar",...) lugar funcionaría, pero aparentemente no es así.

Actualizado geom_bar() necesita stat = "identity"

Por lo que vale: La tabla de conteos, dat, arriba contiene NA. A veces, es útil tener un 0 explícito en su lugar; por ejemplo, si el siguiente paso es poner conteos por encima de las barras. El siguiente código hace precisamente eso, aunque probablemente no sea más simple que el de Joran. Implica dos pasos: obtener una tabla de dcast de recuentos usando dcast , luego fundir la tabla con melt , seguido de ggplot() como de costumbre.

 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) 

enter image description here

Hice esta misma pregunta, pero solo quería usar data.table , ya que es una solución más rápida para conjuntos de datos mucho más grandes. Incluí notas sobre los datos para que los que tienen menos experiencia y quieren entender por qué hice lo que hice puedan hacerlo fácilmente. Así es como mtcars el conjunto de datos 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" 

Y aquí está la llamada que produjo el 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) 

Y produce este gráfico:

Gráfico de cilindros

Además, si hay datos continuos, como los del conjunto de datos de diamonds (gracias a 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] 

Entonces, usar CJ también funcionaría.

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

Dándonos este gráfico:

Diamantes arreglados

Así es cómo puede hacerlo sin hacer tablas de resumen primero.
No funcionó en mi versión de CRAN (2.2.1), pero en la última versión de desarrollo de ggplot (2.2.1.900) no tuve problemas.

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

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

Usa count y complete desde dplyr para hacer esto.

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

Puede aprovechar la función de la table() , que calcula el número de apariciones de un factor para todos sus niveles

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