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

Shiny中Leaflet绘制分级统计图报closure转character错误

问题根因

你碰到的Error in as.vector: cannot coerce type 'closure' to vector of type 'character'是Shiny开发中非常典型的错误:代码里引用了根本不存在的数据框对象df。R在全局环境找不到名为df的变量时,会默认匹配到base包内置的df()函数(F分布密度函数,类型为closure即闭包/函数),你尝试从函数对象里提取$Rate/$Year列、做切片操作时,就会触发“无法把函数转成字符向量”的报错。

代码存在的所有问题清单
  • 预处理完成的最终数据集是optdata_ratio,但UI和Server端全程在调用不存在的df,且列名完全不匹配:实际列名是indicator(指标)、year(年份)、ratio(男女比值),你代码里写的是Rate/Year/Total_ratio
  • UI中调用了useShinyjs()但没有加载shinyjs包,应用启动就会报错
  • 色板用到的bins分组断点、多边形标签用到的labels对象均未定义
  • 弹窗内容直接引用全局的spain空间对象字段,切换指标/年份时弹窗不会同步更新
  • Leaflet初始化错误写为leaflet('map'),正确写法是直接调用leaflet()不需要传字符串参数
  • 提前整理好的社会经济/健康指标列表完全没有用到下拉选择控件里
修正后的可运行代码
## app.R ##
library(shiny)    
library(leaflet)  
library(shinyjs)
library(RSocrata)
library(dplyr)
library(raster)
library(read_excel)
library(tidyverse)
library(tidyr)
library(RColorBrewer)

spain <-  getData("GADM", country="ESP", level=1)
optdata <- read_excel("D:\\Documents and Settings\\05635062Q\\Mis documentos\\GHEALTH\\optdata.xlsx")

# 计算男女比值
optdata_mean <- optdata%>%
  select('indicator_id', 'year', 'sex', 'measure',  'trend_axis',   'indicator',    'interpret', 
         'type_definition', 'profile',  'areaname', 'areatype', 'code')%>%
  group_by(year,indicator, areaname, sex, code, profile)%>%
  summarise(Total_mean=mean(measure), .groups = "drop") 


optdata_ratio <-spread(optdata_mean, sex, Total_mean)%>%mutate(ratio=round(Mujeres/Hombres,2))
optdata_ratio <- optdata_ratio%>%rename("women" = "Mujeres",  "men" = "Hombres")

###############################################.
## 匹配空间数据需要的HASC编码
###############################################.
optdata_ratio <- optdata_ratio%>%
  mutate(
    HASC_1 = case_when(
      code == "01"  ~ 'ES.AN',
      code == "02"  ~ 'ES.AR', 
      code == "03"  ~ 'ES.AS',
      code == "04"  ~ 'ES.PM',
      code == "05"  ~ 'ES.CN',
      code == "06"  ~ 'ES.CB',
      code == "07"  ~ 'ES.CL',
      code == "08"  ~ 'ES.CM',
      code == "09"  ~ 'ES.CT',
      code == "10"  ~ 'ES.VC',
      code == "11"  ~ 'ES.EX',
      code == "12"  ~ 'ES.GA',
      code == "13"  ~ 'ES.MD',
      code == "14"  ~ 'ES.MU',
      code == "15"  ~ 'ES.NA',
      code == "16"  ~ 'ES.PV',
      code == "17"  ~ 'ES.LO',
      code == "20"  ~ 'ES.ML',
      TRUE ~  "OTHER"
    )
  )
# 过滤掉不匹配的无效区域
optdata_ratio <- optdata_ratio %>% filter(HASC_1 != "OTHER")

# 提取社会经济类指标作为下拉选项
indicator_se_list <-sort(unique(optdata_ratio$indicator[optdata_ratio$profile %in% c("socieconomic")]))


########### SHINY APP ###########

ui <- fluidPage(
  useShinyjs(),
  sidebarLayout(
    sidebarPanel(
      selectInput("rate", label = "选择社会经济指标:",
                  choices=indicator_se_list, selected = indicator_se_list[1]),
      shiny::hr(),
      uiOutput("year_ui_rank"),
    ),
    mainPanel(
      leafletOutput("map", height = "600")
    )
  )
)

server = function(input, output) {

  # 动态生成年份选择器
  output$year_ui_rank <- renderUI({
    time<- sort(unique(optdata_ratio$year[optdata_ratio$indicator == input$rate]))
    selectInput("year",label= shiny::HTML("<p>选择年份 <br/> <span style='font-weight: 400'></span></p>"),
                choices = time, selected = last(time))
  })

  
  # 按用户选择筛选数据
  data_filtered <-reactive({
    req(input$year, input$rate)
    d<-optdata_ratio%>%subset(year==input$year  & indicator==input$rate)
    return(d)
  })

  # 合并空间数据和指标数据
  poly_map <- reactive({
    req(data_filtered())
    MergedData <- sp::merge(spain, data_filtered(), duplicateGeoms = TRUE, by.x = "HASC_1", by.y ="HASC_1") 
    return(MergedData)
  })

  
  output$map <- renderLeaflet({
    req(poly_map())
    # 定义色板分组断点
    bins <- quantile(poly_map()$ratio, probs = seq(0,1,0.2), na.rm = T)
    pal <- colorBin("YlOrRd", domain = poly_map()$ratio, bins = bins)
    
    # 定义弹窗和悬浮标签
    polygon_popup <- paste0("<strong>区域名称: </strong>", poly_map()$NAME_1, "<br>",
                            "<strong>指标值: </strong>", poly_map()$ratio)
    labels <- paste0(poly_map()$NAME_1, ": ", poly_map()$ratio)
    
    leaflet() %>% 
      addProviderTiles("CartoDB.Positron") %>% 
      setView(lng = -3.7, lat = 40.4, zoom = 6) %>% 
      addPolygons(data =  poly_map(), 
                  fillColor= ~pal(ratio),
                  weight = 2,
                  opacity = 1,
                  color = "white",
                  dashArray = "3",
                  fillOpacity = 0.7,
                  highlightOptions = highlightOptions(
                    weight = 5,
                    color = "#666",
                    dashArray = "",
                    fillOpacity = 0.8,
                    bringToFront = TRUE),
                  label = labels,
                  popup = polygon_popup,
                  labelOptions = labelOptions(
                    style = list("font-weight" = "normal", padding = "3px 8px"),
                    textsize = "15px",
                    direction = "auto"))%>%addLegend('bottomright',
                                                     opacity = 0.7,
                                                     pal = pal,
                                                     values =  poly_map()$ratio,
                                                     title = "男女比值")  
  })
}

shinyApp(ui, server)
修正说明
  • 所有不存在的df对象替换为实际预处理好的optdata_ratio,列名全部和预处理结果对齐
  • 补全了缺失的shinyjs包加载、bins断点定义、labels标签定义
  • 所有reactive节点加了req()做校验,避免初始化时输入值为空触发报错
  • 下拉选项直接用提前整理好的社会经济指标列表,去掉了不存在的levels(df$Rate)调用
  • 弹窗、标签全部引用合并后的空间数据集字段,切换选项时会同步更新
  • 过滤掉了HASC_1为OTHER的无效数据,避免地图上出现多余区域

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 11:03:24