Shiny应用中GoogleVis仪表盘异常:报错$ operator is invalid for atomic vectors
问题排查与修复方案
1. GoogleVis仪表盘弹出独立窗口的问题
在renderGvis函数中调用plot(Gauge)会触发googleVis在独立浏览器窗口渲染图表,这是因为plot()方法本身的行为就是弹出外部窗口。renderGvis的正确用法是直接返回gvis对象,无需调用plot(),修改后即可实现图表嵌入应用内显示。
2. "$ operator is invalid for atomic vectors"错误
这个错误来自两个核心场景:
场景一:地图点击时的浮点精度匹配问题
用df$y == click$lat & df$x == click$lng直接匹配经纬度,会因为浮点型数据的精度误差导致找不到匹配项,进而让location变成空原子向量,后续updateSelectInput中c(input$locations, location)会触发错误。
修复方法:改用dplyr的near()函数进行模糊匹配,允许微小精度误差:
location <- df %>% filter(near(x, click$lng, tol = 1e-4), near(y, click$lat, tol = 1e-4)) %>% pull(locations)
场景二:空输入或多位置选择时的处理缺失
当没有选中任何位置时,locat_data()会返回空数据,传入gvisGauge会引发错误;同时原代码未开启多选支持,地图点击累加选择时会出现逻辑冲突。
修复方法:添加req(input$locations)确保数据非空,给selectizeInput开启multiple = TRUE支持多选。
完整修复后的代码
library(shiny) library(leaflet) library(shinydashboard) library(dplyr) library(googleVis) # 构建数据框 locations <- c("A","B","C") x <- c(36.05617,36.05626,36.05634) y <- c(-2.1007,-2.05553,-2.01035) yield <- c(5.86,3.06,1.07) df <- data.frame(locations,x,y,yield) ################## UI定义 ############################ ui <- shinyUI(dashboardPage( title = "Yield Lookup", dashboardHeader(title = "Crop Yield (Tonnes per Hectare)", titleWidth = 350), dashboardSidebar( sidebarMenu( menuItem("Map Dashboard", tabName = "datavis", icon = icon("map", verify_fa = FALSE)), menuItem("Select by Location Name", icon = icon("leaf"), selectizeInput("locations", "Click on Location", choices = levels(factor(df$locations)), multiple = TRUE) ) ) ), dashboardBody( tabItems( tabItem(tabName = "datavis", h4("Map and Plot"), fluidRow( box(width= 8, leafletOutput("map", height = 800)), box("Gauge for crop yield by area", width = 4, htmlOutput("myplot")) ) ) ) ) )) ################## Server定义 ############################ server <- shinyServer(function(input,output, session){ # 筛选选中位置的数据 locat_data <- reactive({ req(input$locations) # 确保输入不为空 df %>% filter(locations %in% input$locations) }) # 渲染GoogleVis仪表盘 output[["myplot"]] <- renderGvis({ newdf <- locat_data() %>% select(locations, yield) gvisGauge(newdf, options=list(min=0, max=6, greenFrom=4, greenTo=6, yellowFrom=2, yellowTo=4, redFrom=0, redTo=2, width=400, height=300)) }) # 渲染地图 output$map <- renderLeaflet({ leaflet(df) %>% addTiles() %>% addCircleMarkers(lng = ~x, lat = ~y, layerId = ~locations, color = "blue", radius = 3) %>% addCircles(lng = ~x, lat = ~y, weight = 1, radius = 1, label = ~locations) }) # 更新选择框(手动选择时) observeEvent(input$locations,{ updateSelectInput(session, "locations", "Click on Locations", choices = levels(factor(df$locations)), selected = input$locations) }) # 地图点击事件处理 observeEvent(input$map_marker_click, { click <- input$map_marker_click # 处理浮点精度问题的坐标匹配 location <- df %>% filter(near(x, click$lng, tol = 1e-4), near(y, click$lat, tol = 1e-4)) %>% pull(locations) if(length(location) > 0){ # 确保找到有效位置 current_selected <- input$locations %||% c() new_selected <- unique(c(current_selected, location)) updateSelectInput(session, "locations", "Click on Location", choices = levels(factor(df$locations)), selected = new_selected) } }) }) shinyApp(ui=ui, server = server)
额外优化点
- 开启
selectizeInput的多选支持,匹配地图点击累加选择的逻辑 - 用
unique()避免选择框出现重复选项 - 删除无用的空响应式对象
lo - 添加空输入判断,避免无数据时的渲染错误
内容的提问来源于stack exchange,提问作者Julie Ishimwe
相关产品推荐
相关产品推荐

