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

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)

尝试过的解决方案

  1. 参考方案仅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))} })
  1. 筛选逻辑与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部分:
    1. 先执行必选的PlanType筛选,得到基础结果集。
    2. 分别判断两个可选输入是否有效,仅当输入不为空时才追加对应的筛选条件,避免空输入导致的逻辑错误。
    3. 名称匹配时加入str_to_lower,实现不区分大小写的模糊匹配,提升用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 04:37:10