如何在ggplot2中基于阈值实现不同填充渐变效果?
瓷砖图(Tile Plot)分组渐变填充问题
数据
dat <- structure(list(Date = structure(c(19913, 19913, 19913, 19913, 19914, 19914, 19914, 19914, 19915, 19915, 19915, 19915, 19916, 19916, 19916, 19916), class = "Date"), meal = structure(c(1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L), levels = c("Fasting", "Breakfast", "Lunch", "Dinner"), class = "factor"), value = c(NA, NA, 121, 136, 75, 82, 86, 114, 80, 81, 78, 90, 75, 91, NA, NA ), threshold = c(NA, NA, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, NA, NA)), row.names = c(NA, -16L), class = "data.frame")
数据预览:
Date meal value threshold <date> <fct> <dbl> <lgl> 1 2024-07-09 Fasting NA NA 2 2024-07-09 Breakfast NA NA 3 2024-07-09 Lunch 121 FALSE 4 2024-07-09 Dinner 136 FALSE 5 2024-07-10 Fasting 75 TRUE 6 2024-07-10 Breakfast 82 TRUE 7 2024-07-10 Lunch 86 TRUE 8 2024-07-10 Dinner 114 TRUE 9 2024-07-11 Fasting 80 TRUE 10 2024-07-11 Breakfast 81 TRUE 11 2024-07-11 Lunch 78 TRUE 12 2024-07-11 Dinner 90 TRUE 13 2024-07-12 Fasting 75 TRUE 14 2024-07-12 Breakfast 91 TRUE 15 2024-07-12 Lunch NA NA 16 2024-07-12 Dinner NA NA
需求
需创建瓷砖图(tile plot),基于threshold实现两种填充渐变:
threshold为FALSE时,value越高填充越红;threshold为TRUE时,value越低填充越绿;threshold为NA时用灰色(默认颜色)。
尝试代码
library(ggplot2) ggplot(dat, aes(x = meal, y = Date, fill = threshold)) + geom_tile() + geom_text(aes(label = value), color = "white", fontface = "bold") + scale_fill_manual(values = c("#ef5350", "#48bf53")) + scale_x_discrete(expand = c(0, 0)) + scale_y_date(expand = c(0, 0), date_breaks = "1 day", date_labels = "%B %d") + theme(legend.position = "none") + labs(x = element_blank(), y = element_blank())
当前输出仅为纯色块,无法在threshold分组内实现基于value的渐变效果,需解决该问题。
解决方案
要实现分组渐变,需将value按threshold分组归一化,再映射到对应颜色区间,具体代码如下:
library(ggplot2) library(dplyr) library(scales) # 预处理数据:按threshold分组标准化value到0-1区间 dat_processed <- dat %>% group_by(threshold) %>% mutate(norm_value = ifelse(is.na(threshold), NA, rescale(value))) %>% ungroup() # 绘制渐变瓷砖图 ggplot(dat_processed, aes(x = meal, y = Date)) + geom_tile(aes(fill = interaction(threshold, norm_value)), color = "white") + geom_text(aes(label = value), color = "white", fontface = "bold") + # 自定义颜色映射 scale_fill_manual( values = c( # TRUE组:value越低(norm_value越接近0)颜色越深绿 gradient_n_pal(c("#2e7d32", "#c8e6c9"))(seq(0, 1, length.out = 10)), # FALSE组:value越高(norm_value越接近1)颜色越深红 gradient_n_pal(c("#ffccbc", "#c62828"))(seq(0, 1, length.out = 10)), # NA值填充灰色 "grey80" ), guide = "none" ) + scale_x_discrete(expand = c(0, 0)) + scale_y_date(expand = c(0, 0), date_breaks = "1 day", date_labels = "%B %d") + theme_minimal() + labs(x = NULL, y = NULL)
代码说明
- 数据归一化:用
rescale()将每个threshold分组内的value缩放到0-1范围,确保每组数值都能覆盖完整渐变区间。 - 颜色逻辑:
threshold=TRUE组:从深绿到浅绿渐变,对应value从低到高;threshold=FALSE组:从浅红到深红渐变,对应value从低到高,满足"值越高越红"的需求;- NA值直接指定灰色填充。
- 交互变量:用
interaction(threshold, norm_value)作为填充变量,让ggplot区分不同分组的归一化数值,从而应用对应渐变。
内容的提问来源于stack exchange,提问作者LMc
相关产品推荐
相关产品推荐

