如何在ggplot堆叠条形图中添加符号作为第三变量
问题描述
现有一个基于两个变量的ggplot堆叠条形图,希望将第三个变量circumstances_bite_avoidability以符号/图形元素的形式添加到图中(效果为在每个物种条形的右侧添加代表「可避免/不可避免」的区分符号)。
当前使用的代码:
sur %>% filter(!(species_broad %in% c("Monkey", "Cattle"))) %>% drop_na(circumstances_bite_broad_intended) %>% add_count(species_broad) %>% mutate(y_species_broad = reorder( factor(paste0(species_broad, "\n", "(n = ", n, ")")), as.numeric(species_broad) )) %>% ggplot(mapping=aes(y= y_species_broad, fill=circumstances_bite_broad_intended)) + geom_bar(colour="black" , position = "fill")+ scale_x_continuous (labels=c("0","25%","50%","75%","100%")) + labs (x="Proportion of responses",y="Animal species" , fill="Circumstances")+ # "fill" to change the legend title ggtitle ("Circumstances of bite in different animal species")+ scale_fill_manual( values =c ("Threatening Engagement" = "darkred" , "Friendly Engagement" = "red" , "Practical Engagement" = "#EC7979" , "Unintentional Human Engagement" = "lightblue" , "Apparently unprovoked" = "darkblue"))
使用的数据集:
structure(list(species = structure(c(1L, 1L, 3L, 5L, 1L, 2L, 7L, 2L, 2L, 1L, 3L, 1L, 2L, 3L, 1L, 2L, 1L, 4L, 4L, 7L, 2L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 3L, 2L, 1L, 1L, 1L, 6L, 7L, 9L), levels = c("Pet dog", "Unowned dog", "Dog (unknown status)", "Pet cat", "Unowned cat", "Cat (unknown status)", "Rat/rodent", "Monkey", "Cattle"), class = "factor"), circumstances_bite_avoidability = structure(c(1L, 2L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 1L, 2L, 1L, 2L, 2L, 2L, 1L, 2L, 2L, 1L, 2L, 2L, 1L, 2L, 1L, 1L, 2L, 2L, 1L, 1L, 2L, 1L, 2L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 1L, 2L, 2L, 1L, 1L, 2L, 2L, 1L, 1L, 2L, NA), levels = c("Avoidable", "Unavoidable"), class = "factor"), circumstances_bite_broad_intended = structure(c(2L, 4L, 1L, 3L, 4L, 4L, 4L, 5L, 5L, 3L, 5L, 1L, 4L, 5L, 5L, 1L, 5L, 5L, 2L, 5L, 4L, 3L, 5L, 2L, 2L, 5L, 4L, 3L, 3L, 5L, 1L, 5L, 1L, 1L, 5L, 5L, 4L, 4L, 5L, 1L, 5L, 5L, 1L, 1L, 5L, 5L, 2L, 3L, 5L, NA), levels = c("Threatening Engagement", "Friendly Engagement", "Practical Engagement", "Unintentional Human Engagement", "Apparently unprovoked"), class = "factor")), row.names = c(NA, 50L), class = "data.frame")
解决方案
要实现需求,需要先对第三个变量做汇总统计,再将符号添加到堆叠条形的右侧,具体步骤如下:
1. 数据预处理
先补全原代码中缺失的species_broad变量逻辑,同时统计每个物种的「可避免/不可避免」相关数据:
library(tidyverse) sur_processed <- sur %>% # 生成species_broad分组(对齐原代码逻辑) mutate(species_broad = case_when( str_detect(species, "dog|Dog") ~ "Dog", str_detect(species, "cat|Cat") ~ "Cat", species == "Rat/rodent" ~ "Rat/rodent", TRUE ~ as.character(species) )) %>% filter(!(species_broad %in% c("Monkey", "Cattle"))) %>% drop_na(circumstances_bite_broad_intended, circumstances_bite_avoidability) %>% # 统计每个物种总样本数 add_count(species_broad, name = "total_n") %>% # 统计每个物种下可避免/不可避免的数量 group_by(species_broad, circumstances_bite_avoidability) %>% mutate(avoid_count = n()) %>% ungroup() %>% # 生成y轴标签(和原代码一致) mutate(y_species_broad = reorder( factor(paste0(species_broad, "\n", "(n = ", total_n, ")")), as.numeric(species_broad) )) %>% # 去重,保留每个物种+避免性的唯一行用于添加符号 distinct(species_broad, y_species_broad, circumstances_bite_avoidability, avoid_count, total_n)
2. 绘制带符号的堆叠条形图
在原有绘图逻辑基础上,添加geom_text放置区分符号,同时扩展x轴范围容纳符号:
ggplot(sur_processed, aes(y = y_species_broad)) + # 绘制原堆叠条形图(还原原始行数保证比例正确) geom_bar(data = sur_processed %>% select(-circumstances_bite_avoidability, -avoid_count) %>% uncount(total_n), aes(fill = circumstances_bite_broad_intended), colour = "black", position = "fill") + # 添加符号:对勾代表可避免,叉号代表不可避免 geom_text(aes(x = 1.05, label = ifelse(circumstances_bite_avoidability == "Avoidable", "✔", "✖"), color = circumstances_bite_avoidability), size = 5, position = position_dodge(0.8)) + # 坐标轴设置:扩展x轴范围 scale_x_continuous(labels = c("0","25%","50%","75%","100%"), limits = c(0, 1.2)) + # 颜色映射(保留原配色) scale_fill_manual(values = c( "Threatening Engagement" = "darkred", "Friendly Engagement" = "red", "Practical Engagement" = "#EC7979", "Unintentional Human Engagement" = "lightblue", "Apparently unprovoked" = "darkblue" )) + scale_color_manual(values = c("Avoidable" = "green", "Unavoidable" = "darkred")) + # 标签设置 labs(x = "Proportion of responses", y = "Animal species", fill = "Circumstances", color = "Avoidability", title = "Circumstances of bite in different animal species") + theme_minimal() + theme(plot.title = element_text(hjust = 0.5))
补充说明
- 如果不想用文本符号,可替换为
geom_point,通过shape参数设置不同图形(比如shape=16代表实心圆,shape=1代表空心圆)区分类别。 - 扩展x轴范围
limits = c(0, 1.2)是为了防止符号超出绘图区域。 - 若需要展示「可避免/不可避免」的比例,可将符号位置或大小绑定到
avoid_count/total_n变量。
内容的提问来源于stack exchange,提问作者Rakesh Chand
相关产品推荐
相关产品推荐

