开发巴西巴伊亚州道路事故Shiny可视化应用时Facet报错:latitude < -90
解决Shiny中SF分面时的纬度异常错误
这个错误我之前处理巴西空间数据时也碰到过几次,大概率不是Facet操作直接修改了数据值,而是分面过程中图层的坐标系、数据类型或者动态渲染逻辑出了问题。下面是几个最常见的原因和对应的解决办法:
1. 空间要素的坐标系不统一
这是最容易踩的坑——如果你的国道线(mapa)、警察局(postos)和事故点(tab_sf)使用的是不同的坐标系,ggplot2在分面时尝试对齐图层,可能会错误转换坐标,导致出现纬度<-90的异常值。
解决办法:
用sf包的st_transform()把所有空间对象转成同一个坐标系,巴伊亚州常用的是SIRGAS 2000 UTM 23S(EPSG:31983):
library(sf) # 统一转换坐标系 mapa <- st_transform(mapa, crs = 31983) postos <- st_transform(postos, crs = 31983) tab_sf <- st_transform(tab_sf, crs = 31983)
2. 年份变量的类型错误
如果tab_sf中的年份字段是字符型(比如"2017"、"2018"),而不是因子型,facet操作在分组时可能会隐性触发数据筛选或图层错位,虽然表面上没改数据,但会导致空组或异常图层的坐标计算错误。
解决办法:
把年份字段转成因子型:
tab_sf$ano <- as.factor(tab_sf$ano) # 然后分面时用~ano ggplot() + geom_sf(data = mapa) + geom_sf(data = tab_sf, aes(color = tipo_acidente)) + facet_wrap(~ano)
3. Shiny动态渲染中的reactive对象问题
如果你的tab_sf是通过reactive表达式生成的(比如根据用户输入筛选数据),可能在分面时出现以下问题:
- reactive表达式不小心把sf对象转换成了普通dataframe(比如用
dplyr操作时丢失了空间属性) - 动态筛选后返回了空的空间对象,导致渲染时坐标计算出错
解决办法:
- 在reactive表达式末尾用
st_as_sf()确保返回的是sf对象:
filtered_tab_sf <- reactive({ tab_sf %>% filter(ano == input$selected_year) %>% st_as_sf() # 强制保留空间属性 })
- 在renderPlot中添加检查,确保数据非空后再渲染:
output$accident_plot <- renderPlot({ req(filtered_tab_sf()) # 确保数据存在 ggplot() + geom_sf(data = mapa) + geom_sf(data = filtered_tab_sf()) + facet_wrap(~ano) })
4. ggplot2或sf包的版本兼容性问题
早期版本的ggplot2对geom_sf的分面支持有bug,可能导致坐标矩阵计算错误。
解决办法:
更新到最新版本的包:
install.packages(c("ggplot2", "sf"))
快速排查步骤
如果还是找不到问题,可以先做以下测试:
- 在Shiny中输出
tab_sf的空间范围:st_bbox(tab_sf),分面前后对比,确认坐标系没有被意外修改 - 单独绘制某一年的事故数据(不使用分面),看是否正常,排除单年份数据的异常
内容的提问来源于stack exchange,提问作者danilo ribeiro de abreu
相关产品推荐
相关产品推荐

