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

Shiny代码中brushedPoints引发逻辑值coercion错误的排查与修正

Shiny应用刷选回归绘图错误修复

核心问题分析

出现Error in is.null(x) || is.na(x) : 'length = 9' in coercion to 'logical(1)'错误及其他代码问题:

  • 分组逻辑矛盾:views_comments_likes_pipeline的group_by包含viewCount,导致聚合后数据失去统计意义,同时summarise中重复计算viewCount均值,逻辑混乱。
  • 刷选初始化未处理:初始状态下input$brush为NULL,直接传入brushedPoints触发类型转换错误。
  • 绘图逻辑缺陷:原代码注释了回归直线绘制,且模型不存在时直接终止绘图,导致基础散点图无法显示。
  • 颜色映射冗余:颜色生成代码过于复杂,可通过因子直接映射简化。

修正后的完整代码

library(shiny)
library(shinyWidgets)
library(shinythemes)
library(dplyr)

# 优化模拟数据生成逻辑,避免循环rbind
set.seed(123) # 设置种子保证结果可复现
df <- expand.grid(
  channel = paste0("Channel_", LETTERS[1:4]),
  Year = 2017:2024,
  month = month.name,
  day = 1:30
) %>%
  mutate(
    publishedDayName = sample(weekdays(Sys.Date() + 0:6), nrow(.), replace = TRUE),
    viewCount = round(runif(nrow(.), min = 0, max = 20*1e6)),
    commentCount = round(runif(nrow(.), min = 0, max = 16*1e3)),
    likeCount = round(runif(nrow(.), min = 0, max = .6*1e6)),
    durationMins = round(runif(nrow(.), min = 4.59, max = 30.7), 1)
  )

ui <- fluidPage(
  theme = shinytheme('journal'),
  tags$style(HTML("
    body {
      font-family: 'Pacifico', sans-serif;
    }
  ")),
  titlePanel("Youtube Data science Channels Analytics"),
  sidebarLayout(
    sidebarPanel(
      sliderTextInput(
        inputId = "year_slider",
        label = "选择年份",
        choices = as.character(2017:2024),
        selected = "2023",
        width = "300px"
      ),
      selectInput(
        inputId = "x",
        label = "X轴变量:",
        choices = c('viewCount', 'commentCount', 'likeCount'),
        selected = 'commentCount'
      ),
      selectInput(
        inputId = "y",
        label = "Y轴变量:",
        choices = c('viewCount', 'commentCount', 'likeCount'),
        selected = 'viewCount'
      ),
      h3('选中的点'),
      verbatimTextOutput('brushed_data'),
      h3('模型系数'),
      verbatimTextOutput('model'),
      actionButton("clear_pipeline", "清除刷选")
    ),
    mainPanel(
      fluidRow(
        column(12,
               plotOutput('scatter_Plot', brush = brushOpts(id = 'brush'))
        )
      )
    )
  )
)

server <- function(input, output, session) {
  df$channel <- as.factor(df$channel)
  
  # 修正数据聚合逻辑:按channel和month分组,正确计算均值
  views_comments_likes_pipeline <- reactive({
    df %>%
      filter(Year == input$year_slider) %>%
      group_by(channel, month) %>%
      summarise(
        viewCount = mean(viewCount),
        commentCount = mean(commentCount),
        likeCount = mean(likeCount),
        .groups = "drop" # 取消分组,避免后续操作异常
      )
  })
  
  # 处理刷选数据:初始状态返回空数据框
  output$brushed_data <- renderPrint({
    if (is.null(input$brush)) {
      return(data.frame())
    }
    brushedPoints(views_comments_likes_pipeline(), input$brush,
                  xvar = input$x, yvar = input$y)
  })
  
  # 生成回归模型:处理刷选为空或数据不足的情况
  model <- reactive({
    if (is.null(input$brush)) {
      return(NULL)
    }
    brushed_data <- brushedPoints(views_comments_likes_pipeline(), input$brush,
                                  xvar = input$x, yvar = input$y)
    if(nrow(brushed_data) < 2) {
      return(NULL)
    }
    lm_formula <- as.formula(paste(input$y, "~", input$x))
    lm(lm_formula, data = brushed_data)
  })
  
  # 绘制散点图并添加回归直线
  output$scatter_Plot <- renderPlot({
    plot_data <- views_comments_likes_pipeline()
    # 简化颜色映射:按channel因子分配颜色
    channel_colors <- setNames(c("#FF000060", "#FFA50060", "#FFFF0060", "#00FF0060"),
                               levels(plot_data$channel))
    
    par(bg = 'gray', family = 'sans', cex = 1.5)
    plot(x = plot_data[[input$x]], 
         y = plot_data[[input$y]], 
         col = channel_colors[plot_data$channel], 
         pch = 19, 
         main = '播放量、评论数、点赞数关系', 
         xlab = input$x,
         ylab = input$y)
    grid(col = 'white', lty = 'solid')
    
    # 当模型存在时添加回归直线
    lm_model <- model()
    if (!is.null(lm_model)) {
      abline(lm_model, color = 'blue', lwd = 1.5, lty = 'dashed')
    }
  })
  
  # 显示模型系数
  output$model <- renderPrint({
    lm_model <- model()
    if (!is.null(lm_model)) {
      summary(lm_model)$coefficients
    } else {
      cat("请刷选至少2个点生成回归模型")
    }
  })
  
  # 清除刷选按钮逻辑
  observeEvent(input$clear_pipeline, {
    session$resetBrush("brush")
  })
}

shinyApp(ui, server)

关键修正点说明

  1. 数据聚合优化:移除group_by中的viewCount,按channel和month分组,确保聚合后的均值有统计意义,同时添加.groups = "drop"避免分组残留问题。
  2. 刷选状态处理:调用brushedPoints前先判断input$brush是否为NULL,初始状态返回空数据框,避免类型转换错误。
  3. 绘图逻辑完善:先绘制基础散点图,再判断模型是否存在,存在则添加回归直线,保证初始状态下散点图正常显示。
  4. 颜色映射简化:直接用channel因子的levels映射颜色,代码更简洁。
  5. 添加清除刷选功能:绑定clear_pipeline按钮,重置刷选状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 10:32:09