geom_point与geom_boxplot用不同颜色变量时公司代码配色序列异常
问题解决:添加箱线图后数据点配色序列失效
问题场景
我需要生成这样的图表:每个财年下的各公司数据点按特定序列渐变配色,背景叠加对应财年的箱线图。原本通过arrange+mutate(fct_inorder())把company_code转为有序因子,以此控制配色序列,但添加geom_boxplot(aes(colour=financial_year))后,数据点的配色变得随机,移除箱线图层则配色序列恢复正常。
示例代码:
library(dplyr); library(forcats) df1 %>% arrange(financial_year != "2018-19", -production) %>% mutate(company_code = fct_inorder(as.factor(company_code))) %>% arrange(company_code, financial_year) %>% ggplot(., mapping = aes(x=financial_year, y = production))+ geom_point(aes(colour=company_code),position = position_jitter(height=0, width=0.2), size = 1.1, alpha = 0.6) + geom_boxplot(aes(colour=financial_year))
示例数据:
company_code <- c(1,1,1,1,2,2,2,2,3,3,3,3) financial_year <- c("2018-19","2019-20","2020-21","2018-21","2018-19","2019-20","2020-21","2018-21","2018-19","2019-20","2020-21","2018-21") production <- c(2000,2500,3000,7500,1000,1500,1000,3500,5000,5500,4000,14500) df <- data.frame(company_code,financial_year,production) df$company_code <- as.factor(df$company_code) df$financial_year <- as.factor(df$financial_year)
原因分析
ggplot中同一个绘图上下文不能同时绑定两个独立的colour美学映射。当给geom_boxplot添加aes(colour=financial_year)后,ggplot会重置全局颜色标尺,覆盖掉之前通过有序因子company_code设定的配色序列规则,导致数据点颜色随机分配。
解决方案
方案1:手动固定公司配色序列
直接用scale_colour_manual指定company_code的颜色,同时给箱线图单独设置固定颜色,避免映射冲突:
library(dplyr); library(forcats); library(ggplot2) # 按需求定义公司配色序列 company_colors <- c("1" = "#1f77b4", "2" = "#ff7f0e", "3" = "#2ca02c") df %>% arrange(financial_year != "2018-19", -production) %>% mutate(company_code = fct_inorder(as.factor(company_code))) %>% ggplot(aes(x=financial_year, y = production))+ # 箱线图用固定灰色边框,不绑定colour映射 geom_boxplot(colour = "gray50", alpha = 0.2) + # 数据点使用手动定义的配色序列 geom_point(aes(colour=company_code), position = position_jitter(height=0, width=0.2), size = 1.1, alpha = 0.6) + scale_colour_manual(values = company_colors)
方案2:用fill替代箱线图的colour映射
如果不需要箱线图边框颜色对应财年,改用填充色区分财年,这样就不会和数据点的colour映射冲突:
library(dplyr); library(forcats); library(ggplot2) df %>% arrange(financial_year != "2018-19", -production) %>% mutate(company_code = fct_inorder(as.factor(company_code))) %>% ggplot(aes(x=financial_year, y = production))+ # 箱线图用fill映射财年,边框统一为黑色 geom_boxplot(aes(fill=financial_year), colour = "black", alpha = 0.2) + # 数据点的colour映射不受影响 geom_point(aes(colour=company_code), position = position_jitter(height=0, width=0.2), size = 1.1, alpha = 0.6) + # 可选:给fill设置渐变配色 scale_fill_viridis_d(alpha = 0.3)
方案3:用ggnewscale创建多组独立颜色标尺
如果必须让箱线图边框颜色对应财年,同时保留数据点的配色序列,可以用ggnewscale包创建独立的颜色标尺:
library(dplyr); library(forcats); library(ggplot2); library(ggnewscale) df %>% arrange(financial_year != "2018-19", -production) %>% mutate(company_code = fct_inorder(as.factor(company_code))) %>% ggplot(aes(x=financial_year, y = production))+ # 先绘制数据点,绑定company_code的colour映射 geom_point(aes(colour=company_code), position = position_jitter(height=0, width=0.2), size = 1.1, alpha = 0.6) + scale_colour_viridis_d() + # 新建独立的颜色标尺用于箱线图 new_scale_colour() + geom_boxplot(aes(colour=financial_year))
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

