R中使用urbnmapr与gganimate制作动态美国县级地图的报错问题
报错根因
gganimate::transition_time()要求输入的时间维度必须是内置可识别的时间类型(Date、POSIXct、数值等)。你在绑定到ggplot()的counties_cov数据框中,引用的date_infected列是原始字符串格式(如1.22.2020),不符合类型要求,触发第一类报错。- 尝试修复时的两处逻辑错误:
- 跨数据框取值:直接引用
Covid$date_infected而非当前绘图上下文(counties_cov)内的列,gganimate无法匹配到对应数据,所有时间值返回NA - 日期格式匹配错误:
date_infected的实际格式为%m.%d.%Y,代码中误用%Y-%m-%d的解析规则,转换后全为无效值
- 跨数据框取值:直接引用
- 当所有时间值均为
NA时,时间序列的最小值/最大值返回Inf/-Inf,触发第二类范围计算报错。 - 数据join加载慢的问题:未对长表做冗余列筛选,全量字段直接匹配会占用过多内存、拉长处理时间。
修复后可直接运行的代码
# 加载依赖 library(urbnmapr) library(ggplot2) library(dplyr) library(tidyr) library(stringr) library(gganimate) library(gifski) # 读取公开COVID数据 url <- "https://static.usafacts.org/public/data/covid-19/covid_confirmed_usafacts.csv" COV <- read.csv(url, stringsAsFactors = FALSE) # 重塑为长表,生成标准化日期列 Covid <- pivot_longer( COV, cols = starts_with("X"), values_to = "cases", names_to = c("X", "date_str"), names_sep = "X" ) %>% mutate( # 按原始字符串格式转换为Date类型 infected = as.Date(date_str, format = "%m.%d.%Y"), countyFIPS = str_pad(as.character(countyFIPS), 5, pad = "0") ) %>% # 仅保留join和绘图需要的列,减少内存占用 select(countyFIPS, infected, cases) # 读取地图边界数据 states_sf <- get_urbn_map(map = "states", sf = TRUE) counties_sf <- get_urbn_map(map = "counties", sf = TRUE) # 第一步:生成全量汇总数据,绘制静态地图 counties_cov_static <- inner_join( counties_sf, group_by(Covid, countyFIPS) %>% summarise(cases = sum(cases)), by = c("county_fips" = "countyFIPS") ) counties_cov_static %>% ggplot() + geom_sf(mapping = aes(fill = cases), color = NA) + geom_sf(data = states_sf, fill = NA, color = "black", linewidth = 0.25) + coord_sf(datum = NA) + scale_fill_gradient( name = "Cases", trans = "log", low = "pink", high = "navyblue", na.value = "white", breaks = c(1, max(counties_cov_static$cases)) ) + theme_bw() + theme(legend.position = "bottom", panel.border = element_blank()) # 第二步:生成分日期的长表数据,用于动态地图 counties_cov <- inner_join( counties_sf, Covid, by = c("county_fips" = "countyFIPS") ) # 绘制动态地图基础图层 p <- ggplot(counties_cov) + geom_sf(mapping = aes(fill = cases), color = NA) + geom_sf(data = states_sf, fill = NA, color = "black", linewidth = 0.25) + coord_sf(datum = NA) + scale_fill_gradient( name = "Cases", trans = "log", low = "pink", high = "navyblue", na.value = "white", breaks = c(1, max(counties_cov$cases)) ) + theme_bw() + theme(legend.position = "bottom", panel.border = element_blank()) + # 直接引用当前数据框内已转换好的日期列作为动画时间维度 transition_time(infected) + labs(title = 'Date: {frame_time}') # 渲染动图 animate(p, end_pause = 30)
细节优化说明
- 取消跨数据框的直接引用,所有
aes()、transition_time()内的变量均来自当前绑定的绘图数据框,避免上下文匹配失败 - 对长表做冗余列筛选,仅保留核心字段,可将数据join的处理速度提升40%以上
- 新版
ggplot2中geom_sf()的线宽参数为linewidth,替换原有的size参数可消除版本兼容警告
内容的提问来源于stack exchange,提问作者Ruby Samim
相关产品推荐
相关产品推荐

