为数据框选中列生成带百分比柱状图时的异常问题排查
解决ggplot2生成百分比柱状图的异常问题
问题场景
你有如下示例数据:
library(dplyr) library(tidyr) # example data frame df <- data.frame( col1 = c("A;B;C", "A;B", "B;C", "A;C", "B", "A;B;C;D"), col2 = c("X;Y;Z", "X;Y", "Y;Z", "X;Z", "Z", "W;X;Y;Z"), col3 = c("1;2", "1", "2;3", "3", "4;5;6", "7"), col4 = c(1, 2, 3, 4, 5, 6), col5 = c(TRUE, FALSE, TRUE, FALSE, TRUE, FALSE) ) # select columns to separate selected_cols <- c("col1", "col2", "col3", "col4", "col5")
原本生成计数柱状图的代码是:
library(ggplot2) library(tidyr) lapply(c("col1", "col2"), function(col) { separate_rows(df, all_of(col), sep = ";") |> ggplot(aes(.data[[col]])) + geom_bar(aes(fill = .data[[col]])) })
你修改为百分比柱状图的代码后出现异常,修改后的代码:
lapply(c("col1", "col2"), function(col) { separate_rows(df, all_of(col), sep = ";") |> ggplot(aes(.data[[col]])) + geom_bar(aes(fill = .data[[col]])) + stat_count(aes(y = (..count..)/sum(..count..)), position = "identity") + scale_y_continuous(labels = scales::percent) })
错误原因
你的代码同时调用了geom_bar()和stat_count(),而geom_bar()默认就是使用stat_count()来计算并绘制计数柱状图的。这相当于在同一个图表上叠加了两层柱子:一层是原始计数高度的柱子,另一层是百分比高度的柱子,两者叠加导致图形异常。
修正方案
方案1:直接修改geom_bar的y轴映射
无需额外调用stat_count(),直接在geom_bar()的aes里定义百分比计算逻辑:
library(ggplot2) library(tidyr) library(scales) # 加载scales包以使用百分比标签 lapply(c("col1", "col2"), function(col) { separate_rows(df, all_of(col), sep = ";") |> ggplot(aes(.data[[col]])) + geom_bar(aes(y = (..count..)/sum(..count..), fill = .data[[col]])) + scale_y_continuous(labels = percent) })
方案2:先预处理数据计算百分比(推荐)
这种方式更直观,提前在数据层面计算好百分比,避免依赖ggplot内部的..count..变量,也更容易排查数据问题:
library(ggplot2) library(tidyr) library(dplyr) library(scales) lapply(c("col1", "col2"), function(col) { separate_rows(df, all_of(col), sep = ";") |> # 统计每个类别出现的次数 count(.data[[col]]) |> # 计算每个类别占总数的百分比 mutate(pct = n / sum(n)) |> ggplot(aes(x = .data[[col]], y = pct, fill = .data[[col]])) + geom_col() + # 使用geom_col而非geom_bar,因为y轴是已计算好的值 scale_y_continuous(labels = percent) })
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

