R语言ggplot2:如何通过循环优化散点图着色代码?
问题描述
我有一段可正常运行的代码如下:
library(ggplot2) ggplot(data = iris, aes(x = Sepal.Length, y = Petal.Length)) + geom_point(color = case_when( iris[["Sepal.Length"]] > 7 ~ rgb(133, 188, 121, maxColorValue = 255), iris[["Sepal.Length"]] > 6 ~ rgb(83, 110, 155, maxColorValue = 255), iris[["Sepal.Length"]] > 5 ~ rgb(111, 112, 107, maxColorValue = 255), iris[["Sepal.Length"]] > 4 ~ rgb(249, 222, 91, maxColorValue = 255), TRUE ~ NA ) )
这段代码通过case_when函数根据Sepal.Length的区间为散点图着色,但存在大量重复代码。想通过循环结构生成着色规则实现散点图着色,已知可以用eval(parse(text="...string from a loop comes in here...")),但有没有更优雅的实现方式?
优雅实现方式
方法1:用cut()分箱映射颜色(最贴合ggplot范式)
先将Sepal.Length按指定阈值分箱,再把分箱结果和颜色做映射,完全避免重复写条件:
library(ggplot2) # 定义区间阈值和对应颜色(注意顺序和区间匹配) thresholds <- c(4, 5, 6, 7) color_palette <- c( rgb(249, 222, 91, maxColorValue = 255), rgb(111, 112, 107, maxColorValue = 255), rgb(83, 110, 155, maxColorValue = 255), rgb(133, 188, 121, maxColorValue = 255) ) # 对Sepal.Length分箱:区间为(4,5], (5,6], (6,7], (7,Inf),right=FALSE表示左开右闭 iris$length_bin <- cut(iris$Sepal.Length, breaks = c(-Inf, thresholds, Inf), right = FALSE) ggplot(data = iris, aes(x = Sepal.Length, y = Petal.Length)) + geom_point(aes(color = length_bin)) + scale_color_manual(values = color_palette, na.value = NA) + theme(legend.position = "none") # 不需要图例可删除此行
方法2:动态构建case_when条件对(保留case_when逻辑)
如果想继续用case_when,可以通过列表生成条件-颜色表达式,再用!!!(大爆炸运算符)展开,无需eval(parse):
library(ggplot2) library(dplyr) library(purrr) # 按阈值从高到低定义规则(case_when按顺序匹配,高阈值优先) rule_set <- list( list(threshold = 7, color = rgb(133, 188, 121, maxColorValue = 255)), list(threshold = 6, color = rgb(83, 110, 155, maxColorValue = 255)), list(threshold = 5, color = rgb(111, 112, 107, maxColorValue = 255)), list(threshold = 4, color = rgb(249, 222, 91, maxColorValue = 255)) ) # 生成case_when的条件表达式 case_exprs <- map(rule_set, function(rule) { expr(Sepal.Length > !!rule$threshold ~ !!rule$color) }) # 添加默认匹配规则 case_exprs <- c(case_exprs, expr(TRUE ~ NA)) ggplot(data = iris, aes(x = Sepal.Length, y = Petal.Length)) + geom_point(color = case_when(!!!case_exprs))
方法3:用findInterval()快速匹配颜色(高效简洁)
findInterval能快速定位每个数值所属的区间,再通过索引取对应颜色,代码更精简:
library(ggplot2) thresholds <- c(4, 5, 6, 7) color_palette <- c( rgb(249, 222, 91, maxColorValue = 255), rgb(111, 112, 107, maxColorValue = 255), rgb(83, 110, 155, maxColorValue = 255), rgb(133, 188, 121, maxColorValue = 255) ) # 找到每个Sepal.Length对应的区间索引,调整索引匹配颜色顺序 color_idx <- findInterval(iris$Sepal.Length, thresholds) + 1 # 将<=4的数值设为NA(对应无颜色) color_idx[iris$Sepal.Length <= 4] <- NA ggplot(data = iris, aes(x = Sepal.Length, y = Petal.Length)) + geom_point(color = color_palette[color_idx])
内容的提问来源于stack exchange,提问作者Aku-Ville Lehtimäki
相关产品推荐
相关产品推荐

