R Shiny多输入场景下空输入处理问题求助
R Shiny 应用筛选逻辑问题
我正在开发首个R Shiny应用,使用包含Code、Drug、DIN、Description、Price、Plan列的处方数据集。核心需求是让用户通过PlanType选择药品保障计划筛选数据,同时支持两种可选输入:
- 选择药品类别ProductID
- 输入药品名称Name(基于Description列用
str_detect匹配,因Drug列数据不全)
当前问题:必须同时输入ProductID和Name才不会报错,但用户可能仅需按类别或仅按药品名称查询。我尝试多种解决方案均未成功,请求技术帮助。
核心代码
# Dependencies library(tidyverse) library(readxl) library(shiny) # Import Dataset dat <- read_excel("Excel-Format-Formulary-for-Vendors.xlsx", sheet = 1) dat <- dat[,c(1,2,3,4,6,8)] names(dat) <- c("Code","Drug","DIN", "Description", "Price", "Plan") # Code列清洗代码(省略重复替换部分) dat$Code <- dat$Code %>% replace(str_detect(dat$Code,"^A"),"Alimentary tract and metabolism") # UI ui <- fluidPage( titlePanel("Project Titlee"), fluidRow( column(6,selectInput("ProductID", "Class", choices = dat$Code)), column(3,textInput("Name", "Drug Name")), column(3,selectInput("PlanType", "Drug Plan:", c("Seniors' Pharmacare"="S", "Community Services Pharmacare" = "F", "Drug Assistance for Cancer Patients" = "C", "Diabetes Assistance Program" = "D", "Exception status applies" = "E" ), selected=NULL)) ), fluidRow(column(9, tableOutput("Drug")),column(3, "some text")) ) server <- function(input, output, session) { selected <- reactive( dat %>% filter(Code == input$ProductID) %>% filter(str_detect(Plan, input$PlanType)) %>% if (exists("Name") && Name != ""){ filter(str_detect(Description, input$Name)) }) output$Drug <- renderTable(selected())} shinyApp(ui = ui, server = server)
尝试过的解决方案
- 参考方案仅ProductID正常工作,Name输入返回Null
selected <- reactive({ y <- dat %>% select(if(input$Name == "") NULL else filter(str_detect(Description,{input$Name}))) if (ncol(y) == 0){dat %>% filter(Code == input$ProductID) %>% filter(str_detect(Plan, input$PlanType)) } else { dat %>% filter(Code == input$ProductID) %>% filter(str_detect(Plan, input$PlanType)) %>%filter(str_detect(Description, y))} })
- 筛选逻辑与if/else结合,报错
Can't subset columns with if (...) NULL
server <- function(input, output, session) { selected <- reactive( { x <- dat %>% filter(str_detect(Plan, input$PlanType)) y <- dat %>% select(if(input$ProductID == "") NULL else {x %>% filter(Code == input$ProductID) }) z <- dat %>% select(if(input$Name == "") NULL else {x %>% filter(str_detect(Description, input$Name))}) if (ncol(y & z) == 0){x} else { if (ncol(z) == 0){y} if (ncol(y) == 0){z} else {dat %>% filter(Code == input$ProductID) %>% filter(str_detect(Plan, input$PlanType)) %>%filter(str_detect(Description, input$Name))} } })
解决方案
问题出在筛选逻辑未正确处理可选输入的空值情况,同时selectInput默认会强制选中第一个选项,导致用户无法跳过类别筛选。以下是修正后的完整代码:
# Dependencies library(tidyverse) library(readxl) library(shiny) # Import Dataset dat <- read_excel("Excel-Format-Formulary-for-Vendors.xlsx", sheet = 1) dat <- dat[,c(1,2,3,4,6,8)] names(dat) <- c("Code","Drug","DIN", "Description", "Price", "Plan") # Code列清洗代码(省略重复替换部分) dat$Code <- dat$Code %>% replace(str_detect(dat$Code,"^A"),"Alimentary tract and metabolism") # UI 修改:给ProductID添加空选项,允许用户不选择类别 ui <- fluidPage( titlePanel("Project Titlee"), fluidRow( column(6,selectInput("ProductID", "Class", choices = c("请选择类别" = "", unique(dat$Code)))), column(3,textInput("Name", "Drug Name")), column(3,selectInput("PlanType", "Drug Plan:", c("Seniors' Pharmacare"="S", "Community Services Pharmacare" = "F", "Drug Assistance for Cancer Patients" = "C", "Diabetes Assistance Program" = "D", "Exception status applies" = "E" ), selected=NULL)) ), fluidRow(column(9, tableOutput("Drug")),column(3, "some text")) ) server <- function(input, output, session) { selected <- reactive({ # 初始必选筛选:按PlanType过滤 result <- dat %>% filter(str_detect(Plan, input$PlanType)) # 可选筛选:仅当ProductID不为空时,添加类别过滤 if (input$ProductID != "") { result <- result %>% filter(Code == input$ProductID) } # 可选筛选:仅当Name输入不为空时,添加名称匹配(不区分大小写) if (input$Name != "") { result <- result %>% filter(str_to_lower(Description) %>% str_detect(str_to_lower(input$Name))) } result }) output$Drug <- renderTable(selected()) } shinyApp(ui = ui, server = server)
关键修改说明
- UI部分:给
ProductID的选择框添加了空默认选项,让用户可以主动选择不筛选类别。 - Server部分:
- 先执行必选的PlanType筛选,得到基础结果集。
- 分别判断两个可选输入是否有效,仅当输入不为空时才追加对应的筛选条件,避免空输入导致的逻辑错误。
- 名称匹配时加入
str_to_lower,实现不区分大小写的模糊匹配,提升用户体验。
内容的提问来源于stack exchange,提问作者Kmor
相关产品推荐
相关产品推荐

