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
相关产品推荐
相关产品推荐

