如何基于太阳高度在ggplot2中动态调整绘图背景颜色?
实现动态昼夜遮罩图层的方案
核心思路
利用已计算的太阳高度值,创建覆盖整个绘图范围的动态遮罩图层:
- 太阳高度>0时(白天):遮罩透明度极低,几乎不影响地图显示
- 太阳高度<0时(夜晚):遮罩透明度随太阳高度降低而升高(太阳高度越低,夜晚越暗),用深色填充模拟夜间效果
修改后的完整代码
library(ggplot2) library(gganimate) library(sf) library(suncalc) library(ggspatial) library(gifski) library(prettymapr) # 模拟数据 set.seed(123) gps_data_sf <- data.frame( IMEI = rep(35664665, 300), Pick.Time = seq.POSIXt(as.POSIXct("2024-08-13 00:00:00"), by = "15 mins", length.out = 300), Longitude = runif(300, 2.7, 2.8), Latitude = runif(300, 51.1, 51.2), Bird = rep("Bird A", 300) ) # 添加太阳高度数据 gps_data_sf$sunheight <- mapply(function(lat, lon, time) { sun_position <- getSunlightPosition(date = time, lat = lat, lon = lon) return(sun_position$altitude) }, gps_data_sf$Latitude, gps_data_sf$Longitude, gps_data_sf$Pick.Time) # 转换为sf格式 gps_data_sf <- st_as_sf(gps_data_sf, coords = c("Longitude", "Latitude"), crs = 4326) # 创建昼夜遮罩图层数据:覆盖整个数据范围的多边形,绑定每个时间点的太阳高度 bbox <- st_bbox(gps_data_sf) mask_poly <- st_as_sfc(bbox) mask_data <- data.frame( Pick.Time = gps_data_sf$Pick.Time, sunheight = gps_data_sf$sunheight ) %>% st_sf(geometry = mask_poly, crs = 4326) # 创建动画绘图 animated_plot <- ggplot() + annotation_map_tile(type = "osm", zoom = 12) + # 添加动态昼夜遮罩:根据太阳高度调整透明度和填充色 geom_sf(data = mask_data, aes(alpha = ifelse(sunheight >= 0, 0.05, abs(sunheight)/10)), fill = "darkslategray", color = NA) + # 固定透明度范围,避免动态变化出现异常 scale_alpha_continuous(range = c(0.05, 0.8), limits = c(0, 0.8)) + # 绘制GPS轨迹点 geom_sf(data = gps_data_sf, aes(geometry = geometry, color = Bird, group = Bird), size = 5, alpha = 0.8) + labs( title = "物种移动轨迹(动态昼夜)", subtitle = "时间: {frame_time}", x = "经度", y = "纬度" ) + transition_time(Pick.Time) + ease_aes('linear') + # 隐藏透明度图例(可选) guides(alpha = "none") # 渲染动画 animate(animated_plot, nframes = 100, fps = 10, width = 800, height = 600, renderer = gifski_renderer())
关键细节说明
- 遮罩图层创建:通过数据的边界框生成覆盖整个绘图区域的多边形,确保每个时间点的遮罩都能完全覆盖地图
- 透明度逻辑:
- 白天(太阳高度≥0):透明度设为0.05,几乎不遮挡地图
- 夜晚(太阳高度<0):用
abs(sunheight)/10计算透明度,太阳高度越低(绝对值越大),遮罩越暗
- 图层顺序:遮罩层放在地图和轨迹点之间,既实现昼夜效果,又保证轨迹点清晰可见
- 固定透明度范围:用
scale_alpha_continuous锁定透明度区间,避免动画中出现过度透明或完全不透明的异常情况
内容的提问来源于stack exchange,提问作者reinoud
相关产品推荐
相关产品推荐

