不要删除零计数:躲避条形图

47
我正在使用ggplot2制作一个条形图,并且有一组数据的计数为零,我希望能够显示它。我记得以前在HERE上看到过相关内容,所以想到使用scale_x_discrete(drop=F)。然而,在dodged bars中貌似不起作用。那么,如何使零计数的条形也能显示呢?
例如,在下面的代码中,type8~group4没有例子。我仍想让图表显示空的区域来表示零计数,而不是消除这个条形。我该怎么做?

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
6个回答

32

以下是不需要制作摘要表格的操作步骤。
在我的CRAN版本(2.2.1)中它无法正常工作,但在ggplot的最新开发版本(2.2.1.900)中没有任何问题。

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

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


1
preserve = "single" 保住了我的命 ;) - SeGa
2
保留 =“single”非常好用!但是它不会移动条形图标签。当我使用geom_text时,“single”条的标签不会显示在条中间。 - Gustavo A Escobar-Palafox

17

更新 geom_bar()需要stat = "identity"

值得一提的是:上面的计数表dat包含NA。有时,有一个明确的0比较有用;例如,如果下一步是将计数放在柱形图上方。以下代码实现了这一点,尽管它可能不比Joran的简单。它包括两个步骤:使用dcast获取计数的交叉表,然后使用melt融合表格,最后像往常一样使用ggplot()

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)

在此输入图片描述


这样做变得更好了。我已经完成了图形,但是需要一些hackish垃圾,但这解决了那些问题。回应不错。+1 - Tyler Rinker

13

我所知道的唯一方法是预先计算计数并添加一个虚拟行:

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

我认为使用 stat_bin(drop = FALSE,geom = "bar",...) 会起作用,但显然它并没有。


并不像我希望的那样容易,但在搜索中找不到合适的答案,所以我应该意识到需要进行一些重新调整。谢谢Joran。非常有效+1。 - Tyler Rinker
1
@TylerRinker老实说,我觉得stat_bin(drop = FALSE, geom = "bar",position = "dodge",...)应该可以做到这一点;至少文档强烈暗示它可以。我非常想听听邮件列表上更有经验的人为什么不行。 - joran
我现在正在处理一个项目,但稍后我会将其添加到列表中并在此处报告。 - Tyler Rinker

8

我曾经问过同样的问题,但我只想使用data.table,因为它可以更快地处理大型数据集。我在数据上添加了注释,以便那些经验较少并希望理解我所做的事情的人可以轻松地这样做。以下是我如何操作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"

以下是生成该图表的调用代码

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)

它生成了这个图表:

圆柱图

此外,如果存在连续数据,例如 diamonds 数据集(感谢 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]

然后使用 CJ 也会生效。
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")

给我们这张图:

钻石固定


4
使用 dplyr 库中的 countcomplete 函数来完成此操作。
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")

1
非常好... 我怀疑下一个发布到 CRAN 的 ggplot2 版本将包含 @S_BRT 的答案,它似乎是最佳解决方案 https://github.com/tidyverse/ggplot2/blob/master/R/position-dodge.r - Tyler Rinker

0
你可以利用 table() 函数的特性,它可以计算一个因子在 所有 水平上出现的次数。
# 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")


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接