在ggplot geom_sf地图中为geom_tile添加水平渐变填充
解决地图中添加水平渐变填充矩形的问题
问题描述
制作地图时,希望添加左侧颜色最深、向右渐变为白色的水平渐变填充矩形。最初用geom_rect绘制矩形,参考示例尝试带fill变量的geom_tile,生成存储xmax与xmin差值的虚拟列newcol,但矩形仍无渐变效果。
原代码如下:
library(ggplot2) library(sf) library(rnaturalearth) library(tidyverse) states <- ne_states(country = c("United States of America","Canada"), returnclass = "sf") rectangles <- data_frame( y = (35:44)+0.5, xmin = c(-75.5, -75.770333, -75.683333, -75.916667, -74.613, -74.0315, -71.916667, -70.666667, -70.466667, -68.4), xmax = c(-74.8, -74.616667, -73.983333, -72.8, -69.216667, -66.416667, -65.65, -65.675833, -66.516667, -66.721667) )%>% pivot_longer(cols = c(xmax, xmin), names_to="identity", values_to="x") %>% group_by(y) %>% mutate(meanx = mean(x), newcol = x - min(x)) ggplot(data = states) + geom_sf() + geom_tile(data = rectangles, aes(x=meanx, y=y, width=2, height=1, fill=newcol), color="black") + scale_fill_gradient(low="darkblue", high="white") + coord_sf(xlim = c(-80, -65), ylim = c(34, 45.5), expand = FALSE) + NULL
原效果:
解决方案
原方法失效的原因是:每个geom_tile对应一个完整的矩形区域,即使设置了fill变量,每个tile也只会显示单一颜色,无法实现区域内的渐变。
正确思路是将每个大矩形拆分为大量细小的垂直条带,每个条带对应x轴上的一个小区间,通过给每个条带分配对应位置的颜色值,模拟出从左到右的渐变效果。
修改后的代码
library(ggplot2) library(sf) library(rnaturalearth) library(tidyverse) # 获取地图数据 states <- ne_states(country = c("United States of America","Canada"), returnclass = "sf") # 定义矩形参数,保留每个矩形的y、xmin、xmax原始信息 rect_params <- tibble( y = (35:44)+0.5, xmin = c(-75.5, -75.770333, -75.683333, -75.916667, -74.613, -74.0315, -71.916667, -70.666667, -70.466667, -68.4), xmax = c(-74.8, -74.616667, -73.983333, -72.8, -69.216667, -66.416667, -65.65, -65.675833, -66.516667, -66.721667) ) # 为每个矩形生成密集x点,拆分出细小垂直条带 rectangles <- rect_params %>% group_by(y, xmin, xmax) %>% summarize(x = seq(xmin, xmax, length.out = 100), # 生成100个点,数量越多渐变越平滑 .groups = "drop") %>% mutate( fill_val = (x - xmin)/(xmax - xmin) # 计算相对位置,0对应左端点(最深色),1对应右端点(白色) ) # 绘图 ggplot(data = states) + geom_sf() + # 用细小tile模拟渐变,width设为条带宽度,隐藏条带边框避免缝隙 geom_tile(data = rectangles, aes(x = x, y = y, width = (xmax - xmin)/99, height = 1, fill = fill_val), color = NA) + # 添加大矩形的黑色边框,保证外观完整 geom_rect(data = rect_params, aes(xmin = xmin, xmax = xmax, ymin = y - 0.5, ymax = y + 0.5), fill = NA, color = "black") + scale_fill_gradient(low = "darkblue", high = "white") + coord_sf(xlim = c(-80, -65), ylim = c(34, 45.5), expand = FALSE) + theme_minimal()
代码解释
- 保留矩形原始范围:不再对
xmin和xmax做pivot_longer,直接保留每个矩形的完整边界参数。 - 生成密集x采样点:对每个矩形用
seq生成100个均匀分布的x点,点的数量越多,渐变过渡越自然平滑。 - 计算相对填充比例:
fill_val是当前x点距离左端点的相对比例,取值范围0到1,完美匹配渐变的深浅变化。 - 分层绘制元素:先用无框小tile绘制渐变填充,再用
geom_rect叠加黑色边框,既实现渐变效果,又保证矩形的完整轮廓。
内容的提问来源于stack exchange,提问作者Alexa Fredston
相关产品推荐
相关产品推荐

