移除分组条形图中的NA类别(R语言ggplot2实现)
移除分组条形图中的NA类别条形
问题场景
处理包含250列的调研数据,通过循环遍历所有列生成以sector为x轴、回答占比为y轴、各数据列为填充色的分组条形图,但图表中出现了透明的NA类别条形,尝试scale_fill_discrete(na.translate = FALSE)(仅移除图例NA)、fill = subset(data,!is.na(data[[variable]]))、ggplot(data=na.omit(data[[variable]]))均无效。
示例数据:
q1 <- factor(c("yes",NA,"no","yes",NA,"yes","no","yes")) q2 <- factor(c("Albania","USA","Albania","Albania","UK",NA,"UK","Albania")) q3 <- factor(c(0,1,NA,0,1,1,NA,0)) q4 <- factor(c(0,NA,NA,NA,1,NA,0,0)) q5 <- factor(c("Dont know","Prefer not to answer","Agree","Disagree",NA,"Agree","Agree",NA)) q6 <- factor(c(1,NA,3,5,800,NA,900,2)) sector <- factor(c("Energy","Water","Energy","Other","Other","Water","Transportation","Energy")) data <- data.frame(q1,q2,q3,q4,q5,q6,sector)
原绘图代码:
by_sector <- lapply(names(data), function(variable) { ggplot( data = data, mapping = aes(x=sector,fill = data[[variable]]) ) + geom_bar(aes( y=..count../tapply(..count.., ..x.. ,sum)[..x..]), position="dodge") + labs(x = variable, y = "% of total", fill = "Response", caption = paste("Total =", sum(!is.na(data[[variable]])))) + geom_text(aes( y=..count../tapply(..count.., ..x.. ,sum)[..x..], label=scales::percent(..count../tapply(..count.., ..x.. ,sum)[..x..],accuracy = 0.1) ), stat="count", position=position_dodge(1), vjust=0.5)+ #scale_fill_brewer(palette = "Accent")+ scale_fill_discrete(na.translate = FALSE) + theme_bw() + theme(panel.grid.major.y = element_blank()) + coord_flip() })
解决方案
关键修改是在ggplot()的data参数中,针对当前遍历的变量过滤掉该列含NA的行,而非直接使用完整数据集。修改后的代码如下:
by_sector <- lapply(names(data), function(variable) { # 过滤当前变量列的NA值,保留其他列完整数据 filtered_data <- data[!is.na(data[[variable]]), ] ggplot( data = filtered_data, mapping = aes(x = sector, fill = .data[[variable]]) ) + geom_bar(aes(y = ..count../tapply(..count.., ..x.. , sum)[..x..]), position = "dodge") + labs(x = variable, y = "% of total", fill = "Response", caption = paste("Total =", nrow(filtered_data))) + geom_text(aes(y = ..count../tapply(..count.., ..x.. , sum)[..x..], label = scales::percent(..count../tapply(..count.., ..x.. , sum)[..x..], accuracy = 0.1)), stat = "count", position = position_dodge(1), vjust = 0.5) + scale_fill_discrete(na.translate = FALSE) + theme_bw() + theme(panel.grid.major.y = element_blank()) + coord_flip() })
说明
- 过滤数据逻辑:通过
data[!is.na(data[[variable]]), ]仅移除当前变量列含NA的行,绘图时不会包含NA类别数据,自然不会生成NA条形。 - 规范列访问方式:用
.data[[variable]]替代data[[variable]],这是ggplot推荐的编程式列访问方法,避免潜在的评估问题。 - 更新统计标注:用
nrow(filtered_data)替代原sum(!is.na(data[[variable]])),结果一致但更直观。
之前尝试的方法无效原因:
scale_fill_discrete(na.translate = FALSE)仅控制图例是否显示NA,不会移除绘图数据中的NA;fill = subset(data,!is.na(data[[variable]]))错误地将填充映射到数据框子集,而非当前列的有效值;ggplot(data=na.omit(data[[variable]]))传入的是向量而非完整数据框,ggplot无法识别sector等其他变量。
内容的提问来源于stack exchange,提问作者dryl
相关产品推荐
相关产品推荐

