ggplot2中geom_circle动画出现非预期插值圆问题求助
问题描述
我使用R语言的gifski包制作GIF动画:以底部固定红点为圆心绘制圆,圆的半径随移动蓝点的距离变化。其中circle_df.rds仅包含13个时间点的圆数据,gps.rds包含约700个时间点的蓝点数据。我需要仅在动画帧时间与circle_df中的时间点完全匹配时才显示对应圆,但当前动画全程显示插值后的圆,比如11:30:41和11:31:14之间本不该显示圆,却出现了插值生成的圆。
解决方案
问题根源是transition_time()会对所有图层的数据自动进行时间插值,包括圆的图层。要实现仅指定时间点显示圆,需通过以下步骤修正:
- 提取gps中的所有时间帧,与circle_df做全连接,为非目标时间点的圆半径设为0
- 在
geom_circle的映射中添加条件判断,仅当当前时间属于circle_df的时间集合时,使用真实半径绘制圆,否则半径设为0(等同于不显示)
修改后的可复现代码
## Google maps API register_google(key="YOURKEY", write=TRUE) ## 读取数据 gps <- readRDS("gps.rds") sensor <- readRDS("sensor.rds") circle_df <- readRDS("circle_df.rds") ## 补全所有时间帧的圆数据:非目标时间点半径设为0 full_time_df <- data.frame(time = unique(gps$time)) circle_full <- merge(full_time_df, circle_df, by = "time", all.x = TRUE) # 填充缺失值:非匹配时间点半径为0,信号强度设为最小值 circle_full$distance_deg <- ifelse(is.na(circle_full$distance_deg), 0, circle_full$distance_deg) circle_full$signal <- ifelse(is.na(circle_full$signal), -100, circle_full$signal) # 补全传感器经纬度(确保每个时间点都有圆心坐标) circle_full <- merge(circle_full, sensor[, c("lon", "lat")], by = c("lon", "lat"), all.x = TRUE) ## 获取卫星底图 cor <- c(mean(gps$lon), mean(gps$lat)) map <- ggmap(get_googlemap(center=cor, zoom=18, maptype="satellite")) ## 构建绘图对象 p <- map + geom_point(data=gps, aes(x=lon, y=lat), color="blue", size=2, shape=10) + geom_point(data=sensor, aes(x=lon, y=lat), color="red", fill="white", size=3.4, shape=21) + geom_text(data=sensor, aes(x=lon, y=lat, label=ID), color="red", fontface="bold", size=2.4, vjust=0.24) + ## 仅匹配时间点显示圆 geom_circle(data=circle_full, aes(x0=lon, y0=lat, color=signal, r=ifelse(time %in% circle_df$time, as.numeric(distance_deg), 0)), fill=NA, alpha=0.6, linewidth=0.8) + scale_color_gradient(low="dodgerblue", high="red", name=expression("Signal Intensity\n(-100 to 0)"), limits=c(-100,0), guide = guide_colorbar(title.theme=element_text(color="white", size=10), label.theme = element_text(color = "white", size=10), barwidth=1, barheight = 5, nbin = 10)) + theme(axis.title.x=element_blank(), axis.text.x = element_blank(), axis.title.y=element_blank(), axis.text.y = element_blank(), axis.ticks = element_blank(), rect = element_blank(), legend.position=c(0.9,0.14), plot.margin = unit(c(0, 0, 0, 0), "cm")) + transition_time(time) + ggtitle('Time:, {frame_time}', subtitle = 'Frame {frame} of {nframes}') ## 生成动画 frame <- as.integer((max(gps$time) - min(gps$time)) * 60) anime <- animate(p, nframes=frame, fps=round(frame/20)) ## 保存并预览 anim_save("test.gif", anime) ; anime
内容的提问来源于stack exchange,提问作者HSJ
相关产品推荐
相关产品推荐

