Shiny应用中如何将selectInput选择值传入服务端group_by函数
问题原因
selectInput返回的input$breakdown是字符型值(例如选月度分组时返回字符串"month"),而dplyr的group_by()默认使用非标准求值逻辑,会直接把传入的参数识别为数据框内的列名,不会自动解析字符串形式的列名,因此无法正确识别分组字段,导致代码运行失败。
另外原复现代码还存在一个小问题:renderDataTable内仅对处理后的数据框df做了赋值,没有将其作为表达式返回值,就算分组逻辑修复后也无法正常渲染表格。
修复方案
推荐使用dplyr官方支持的动态列名传入写法,任选以下一种即可:
方案1:使用all_of()搭配across()(dplyr 1.0.0+版本首选)
这是当前dplyr版本官方推荐的标准写法,适合传入一个或多个字符型列名的场景,修改后的服务端代码如下:
server <- function(input, output) { output$datTB <- DT::renderDataTable({ df <- dat %>% # 用all_of解析字符型列名 group_by(across(all_of(input$breakdown))) %>% mutate(LongTermWI = mean(value, na.rm = T)) # 返回处理后的数据框用于渲染 df }) }
方案2:使用.data代词索引动态列
如果只需要传入单个动态分组列,用.data代词的写法更简洁,代码可读性更高:
server <- function(input, output) { output$datTB <- DT::renderDataTable({ df <- dat %>% # 用.data[[字符串]]直接索引对应列 group_by(.data[[input$breakdown]]) %>% mutate(LongTermWI = mean(value, na.rm = T)) df }) }
注意:不推荐使用dplyr已废弃的
group_by_()标准求值接口,该接口在新版本dplyr中已经被移除,会导致兼容性问题。
完整可运行修复代码
dat = structure(list(year = c(2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001), month = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8), Quarter = c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 4L, 4L, 4L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L), project = c("DKF", "DKF", "DKF", "DKF", "DKF", "DKF", "DKF", "DKF", "DKF", "DKF", "DKF", "DKF", "DKF", "DKF", "DKF", "DKF", "DKF", "DKF", "DKF", "DKF"), value = c(135.172264747094, 128.304968251943, 124.552331218312, 72.9910740042406, 78.3565950925784, 93.7813954394283, 65.906459417623, 67.4455518391957, 100.287050913478, 96.6700531783534, 106.789122585464, 91.1228414774245, 88.8192557763821, 100.949844928465, 92.3481876481075, 82.5695257044659, 78.2314855696782, 58.656187528325, 59.863983014387, 91.5297764110538)), row.names = c(NA, 20L), class = "data.frame") library(shiny) library(dplyr) ui <- fluidPage( sidebarLayout( sidebarPanel( selectInput(inputId = 'breakdown', label = 'Breakdown', choices = c("Yearly"="year","Quarterly"="Quarter","Monthly"="month"),selected="Monthly") ), mainPanel( DT::dataTableOutput("datTB") ) ) ) server <- function(input, output) { output$datTB <- DT::renderDataTable({ dat %>% group_by(across(all_of(input$breakdown))) %>% mutate(LongTermWI = mean(value,na.rm = T)) }) } shinyApp(ui = ui, server = server)
内容的提问来源于stack exchange,提问作者Haribo
相关产品推荐
相关产品推荐

