首页 > 解决方案 > R Shiny:使用逻辑条件从 checkboxGroupInput() 反应性地子集数据帧

问题描述

我在 UI 中有一个带有 checkboxGroupInput() 的 Shiny 应用程序,用户可以在其中选择他们以前患有的任何癌症。我的数据框有一个名为“cancer”的列,其中包含九种不同的癌症类型。当用户选择他们之前的癌症时,我想从数据框中删除这些行。相反,如果他们取消选择癌症,则该行应自动添加回数据框中。数据框也需要稍后由服务器中的其他函数调用以进行绘图。

我能够使用逻辑参数相当容易地通过性别和年龄等变量对数据框进行反应性子集化:

tmp.df <- reactive({
          lynch.data[which(lynch.data$gender == input$gender & lynch.data$age == input$age),]
})

癌症的问题在于,这个人可能患有 0 到 9 种独特的癌症类型。根据选择,我需要可变数量的 OR 语句。为了做到这一点,我一直在使用此代码片段的不同变体作为逻辑参数,但没有成功:

str2lang(paste0("lynch.data$cancer != ",input$cancer, collapse = " | "))

以下是相关部分的代码摘录。我尝试让我的数据框既是反应函数又是反应值,但没有成功。下面的这段摘录显示了 reactiveValue 版本。

用户界面:

library(shiny)
load("Cancer_Data.RData") # lynch.data is the object name that is loaded

ui <- fluidPage(
  
  # App title 
  titlePanel("Risk Calculator"),
  
  # Sidebar layout with input and output definitions
  sidebarLayout(
    
    # Sidebar panel for inputs
    sidebarPanel(

      radioButtons(inputId = "gender", label = "Sex:",
                   choices = c("Female","Male")),
      
      sliderInput(inputId = "age", label = "Current Age:",
                  min = 1, max = 110, value = 25),
            
      checkboxGroupInput(inputId = "cancer", label = "Prior Cancers (check all that apply):",
                         choices = c("Colorectal","Brain","Endometrial","Gastric","Ovarian","Pancreatic",
"Small Intestine","Upper Urinary Tract","Urinary Bladder")),

      actionButton("calc","Calculate")
      
    ),
    
    # Main panel for displaying outputs
    mainPanel(
      
      #Output: Output table
      tableOutput(outputId = "table")
      
)))

服务器:

server <- function(input, output) {

  rv <- reactiveValues(tmp.df = lynch.data[which(lynch.data$gender == input$gender &
                             lynch.data$age == input$age),])

  observeEvent(input$calc,{

  rv$tmp.df <- if(length(input$cancer) != 0){
                tmp.df <- lynch.data[which(lynch.data$gender == input$gender &
                             lynch.data$age == input$age & 
                             str2lang(paste0("lynch.data$cancer != ",input$cancer, collapse = " | "))),] 
               } else {
                   tmp.df <- lynch.data[which(lynch.data$gender == input$gender &
                                              lynch.data$age == input$age),]
               }
  })

  output$table <- renderTable({head(rv$tmp.df,20)})

}

提前致谢!

标签: rshiny

解决方案


我找到了一个相当简单的解决方案:我没有将数据框包装在 reactiveValues() 中,而是使用了一个反应函数。我首先根据具有单个条件的变量对数据框进行子集化。在同一个函数中,然后我使用 for 循环进行迭代以删除 input$cancer 中的每个癌症。在其他任何地方我需要参考我刚刚调用的数据框 tmp.df()

tmp.df <- reactive({

all.cancers <- lynch.data[which(lynch.data$gender == input$gender &
                                  lynch.data$age == input$age),]

for (cancer in input$cancer) {
  
  all.cancers <- all.cancers[-which(all.cancers$cancer == cancer),]
  
}

all.cancers

})

推荐阅读