如何用ggplot基于多个不等长数据框绘制共享配色堆叠条形图
问题描述
我有多个数据框(实际场景数量远多于2个),现有回答未解决我的问题,示例数据如下:
sex <- data.frame(sex = c("M", "F") ,n = c(25, 30)) age <- data.frame(age = c("20-40","40-60","60-80") ,n = c(18, 30, 25))
我需要生成单张堆叠条形图,同时展示所有数据框的信息。我最初考虑过先合并长度不等的数据框、将缺失行填充为NA,但我核心需求是绘图实现而非数据合并方法,要找到无需提前合并数据框的ggplot2实现方案。
补充要求
- 所有条形共享同一套配色方案
- 不对具体配色做强要求,配色本身不承载数据含义;实际场景条形数量更多,不需要为每个类别分配独有色(避免出现40余种不同配色的情况)
- 不需要显示图例,直接在每个条形区块上标注对应类别文本,保证配色复用、无图例的情况下图表依然清晰可读
实现方案
不需要提前合并所有数据框,直接在ggplot构建图层时逐个传入对应数据框即可,配合列表传参可以适配任意数量的输入数据框,代码如下:
library(ggplot2) # 先把所有需要绘图的数据框整理进列表,实际使用时直接往里加新数据框就行 df_list <- list( # 每个列表元素包含:数据框、分类列名、x轴对应的分组名 list(data = sex, cat_col = "sex", x_label = "Sex"), list(data = age, cat_col = "age", x_label = "Age group") ) # 选一套可复用的配色,比如Set2的8个色,后续自动循环复用 palette <- scales::brewer_pal(palette = "Set2")(8) # 初始化画布 p <- ggplot() + # 统一x轴为分类变量,范围覆盖所有分组名 scale_x_discrete(limits = sapply(df_list, function(x) x$x_label)) + # 全局隐藏图例 theme(legend.position = "none") # 循环给每个数据框加堆叠条形图层和文本标注图层 for (i in seq_along(df_list)) { current_df <- df_list[[i]]$data cat_col <- df_list[[i]]$cat_col x_pos <- df_list[[i]]$x_label # 计算每个堆叠块的y轴中心位置,用于放文本标注 current_df$ypos <- cumsum(current_df$n) - current_df$n/2 # 给每个块循环分配预设色板的颜色 current_df$fill_col <- palette[((1:nrow(current_df))-1) %% length(palette) + 1] # 添加堆叠条形图层 p <- p + geom_bar( data = current_df, aes(x = x_pos, y = n, fill = I(fill_col)), stat = "identity", color = "white" # 加白边区分相邻同色块 ) # 添加块内类别文本标注 p <- p + geom_text( data = current_df, aes(x = x_pos, y = ypos, label = .data[[cat_col]]), size = 3.5 ) } # 输出图表 print(p)
代码说明
- 全程不需要提前把不同长度的数据框做NA填充合并,所有数据处理都在绘图环节按单个数据框独立完成
- 配色自动循环复用预设色板,哪怕有几十个分类块也不会出现几十种颜色,块之间加白色描边区分相邻同色块
- 自动计算每个堆叠块的中心位置标注类别名,完全不需要图例就能识别每个块的含义
- 后续新增数据框只需要在
df_list里加对应条目即可,不用修改其他绘图逻辑
内容的提问来源于stack exchange,提问作者Wera
相关产品推荐
相关产品推荐

