如何为ggplot中不同响应变量的sex设置不同颜色刻度?
解决思路与代码实现
问题需求
为变量sex设置不同的颜色刻度,区分对应响应变量n(物种计数)和avg_weight(平均体重)的折线,避免当前图中同一性别颜色同时对应两条线导致的混淆。
现有代码
yearly_sex_weight = surveys_complete %>% group_by(year, sex, species_id) %>% summarise( avg_weight = mean(weight) ) yearly_sex_species_counts = surveys_complete %>% count(year, sex, species_id) yearly_sex_weight_count = full_join(yearly_sex_weight, yearly_sex_species_counts) myplot = ggplot( data = yearly_sex_weight_count, mapping = aes(x = year) ) myplot + geom_line(aes(y = avg_weight, group = sex, color = sex)) + geom_line(aes(y = n, color = sex)) + scale_color_manual( values = c(M = "blue", F = "pink") ) + facet_wrap(vars(species_id)) + theme_bw()
解决方案
方案1:转换数据为长格式(推荐)
将宽格式数据转为长格式,新增指标类型列,通过sex与指标的组合映射颜色,实现同一性别对应两种不同颜色区分指标。
library(tidyr) # 转换数据为长格式,区分指标类型 yearly_sex_long = yearly_sex_weight_count %>% pivot_longer( cols = c(avg_weight, n), names_to = "metric", # 标记是平均体重还是计数 values_to = "value" # 对应数值 ) # 绘图 ggplot(data = yearly_sex_long, aes(x = year, y = value, color = interaction(sex, metric))) + geom_line() + scale_color_manual( name = "性别 & 指标", values = c( "M_avg_weight" = "darkblue", "M_n" = "lightblue", "F_avg_weight" = "darkmagenta", "F_n" = "lightpink" ) ) + facet_wrap(vars(species_id)) + theme_bw() + labs(y = "数值")
方案2:使用双颜色刻度(需额外包)
借助ggnewscale包添加第二个颜色刻度,分别为两个指标的sex设置独立颜色映射,生成两个图例。
# 安装依赖包(首次使用需执行) # install.packages("ggnewscale") library(ggnewscale) myplot + # 第一条折线:平均体重,对应性别颜色 geom_line(aes(y = avg_weight, group = sex, color = sex)) + scale_color_manual( name = "平均体重(性别)", values = c(M = "darkblue", F = "darkmagenta") ) + # 开启新的颜色刻度 new_scale_color() + # 第二条折线:物种计数,对应性别颜色 geom_line(aes(y = n, color = sex)) + scale_color_manual( name = "物种数量(性别)", values = c(M = "lightblue", F = "lightpink") ) + facet_wrap(vars(species_id)) + theme_bw() + labs(y = "数值")
方案说明
- 方案1通过数据整理实现更简洁的ggplot语法,图例整合显示,适合追求数据规范的场景。
- 方案2保留原数据结构,两个图例分别对应不同指标,适合需要明确区分指标与性别对应关系的场景。
内容的提问来源于stack exchange,提问作者Justin Pretorius
相关产品推荐
相关产品推荐

