You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shiny交互式choropleth地图报错:metaData方法不适用于sfc_GEOMETRY类对象

问题

开发Shiny交互式 choropleth 地图应用时,用户可依次选择国家、州和感兴趣的变量,地图响应式展示所选州内各郡县的变量值,但运行时出现错误:
Error: no applicable method for 'metaData' applied to an object of class "c('sfc_GEOMETRY', 'sfc')"
错误疑似源于addPolygons(data = filteredData()$geometry),最初未加data =时出现另一错误,参考资料添加该参数后出现此新错误,附示例数据及报错代码。

解决思路
  • 错误核心:addPolygons的data参数要求传入完整的sf对象,而非单独的sfc几何列。直接传入filteredData()$geometry会让leaflet无法关联属性数据(如Value),触发元数据处理失败。
  • 具体修复步骤:
    1. 调整响应式数据的作用域:将filteredData从renderLeaflet内部移到服务器顶层,确保它能被正确调用。
    2. 修正addPolygons的数据传入:要么移除data参数(直接使用leaflet()初始化时的sf数据),要么传入完整的filteredData()对象,而非单独的几何列。
    3. 修复fitBounds的坐标获取:用st_bbox()从sf对象中提取边界,替代错误的$x/$y访问方式。
    4. 删除不必要的group_by(state):我们需要展示每个郡县的独立多边形,无需聚合州数据。
修正后的完整代码

数据准备部分

library(shiny)
library(leaflet)
library(sf)
library(dplyr)
library(geodata)

# 示例数据
dat <- data.frame(
  country = rep("United States", 26),
  state = c(rep("Connecticut", 16), rep("Rhode Island", 10)),
  county = c("Fairfield", "Fairfield", "Hartford", "Hartford",
             "Litchfield", "Litchfield", "Middlesex", "Middlesex",
             "New Haven", "New Haven", "New London", "New London",
             "Tolland", "Tolland", "Windham", "Windham",
             "Bristol", "Bristol", "Kent", "Kent",
             "Newport", "Newport", "Providence", "Providence",
             "Washington", "Washington"),
  Variable = rep(c("Tmean", "Pmean_cm"), 13),
  Value = c(10.5, 143, 10.6, 127, 8.3, 148, 10.5, 138, 10.4, 141, 10.6, 128, 9.2, 137, 9.7, 133, 10.8, 127, 10.3, 139, 10.6, 127, 10, 137, 10.5, 135)
)

# 获取郡县几何数据并合并
usa <- gadm(country = 'USA', level = 2, path = tempdir()) %>%
  st_as_sf() %>%
  filter(ENGTYPE_2 != 'Water body') %>%
  select(COUNTRY, NAME_1, NAME_2, geometry) %>%
  rename(country = COUNTRY, state = NAME_1, county = NAME_2)

dat <- left_join(dat, usa, by = c('country', 'state', 'county'))
rm(usa)

Shiny应用部分

ui <- fluidPage(
  titlePanel("Choropleth Map"),
  sidebarLayout(
    sidebarPanel(
      selectInput("countryInput", "选择国家:", choices = unique(dat$country)),
      uiOutput("stateDropdown"),
      selectInput("variableInput", "选择变量:", choices = unique(dat$Variable))
    ),
    mainPanel(
      leafletOutput("map")
    )
  )
)

server <- function(input, output, session) {
  # 动态生成州选择列表
  stateChoices <- reactive({
    req(input$countryInput)
    unique(dat$state[dat$country == input$countryInput])
  })
  
  output$stateDropdown <- renderUI({
    selectInput("stateInput", "选择州:", choices = stateChoices())
  })
  
  # 过滤数据的响应式对象(移到顶层)
  filteredData <- reactive({
    req(input$stateInput, input$variableInput)
    dat %>%
      filter(country == input$countryInput,
             state == input$stateInput,
             Variable == input$variableInput) %>%
      st_as_sf() # 确保是sf对象
  })
  
  # 渲染地图
  output$map <- renderLeaflet({
    req(filteredData())
    
    pal <- colorNumeric(
      palette = "Blues",
      domain = filteredData()$Value
    )
    
    # 获取边界坐标
    bbox <- st_bbox(filteredData())
    
    leaflet(data = filteredData()) %>%
      addProviderTiles("CartoDB.Positron") %>%
      addPolygons(
        fillColor = ~pal(Value),
        color = "white",
        fillOpacity = 0.7,
        stroke = TRUE,
        weight = 1,
        layerId = ~county # 用郡县ID更合理
      ) %>%
      fitBounds(
        lng1 = bbox[["xmin"]],
        lat1 = bbox[["ymin"]],
        lng2 = bbox[["xmax"]],
        lat2 = bbox[["ymax"]]
      )
  })
}

shinyApp(ui = ui, server = server)
补充说明
  • 使用req()函数确保输入参数存在后再执行操作,避免空值错误。
  • 过滤后的数据显式转为sf对象,确保leaflet能正确识别。
  • layerId改为~county,方便后续如果需要交互时定位到具体郡县。

内容的提问来源于stack exchange,提问作者tassones

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 15:14:52