如何在 R Shiny App 中保留复选框中的值?

How to Retain the values in the Check Box in R Shiny App?

我正在尝试创建一个闪亮的应用程序。在这个特定的应用程序中,我有一组单选按钮,选择一个按钮将在下面显示一组选项作为复选框,选择另一个单选按钮将选择其他选项集。请在下面找到 UI 和服务器代码。

library(shiny)
library(shinydashboard)
library(shinyWidgets)

d <-
  data.frame(
    year = c(1995, 1995, 1995, 1996, 1996, 1996, 1997, 1997, 1997),
    Product_Name = c(
      "Table",
      "Chair",
      "Bed",
      "Table",
      "Chair",
      "Bed",
      "Table",
      "Chair",
      "Bed"
    ),
    Product_desc = c("X", "X", "X", "Y", "Y", "Y", "Z", "Z", "Z"),
    Cost = c(1, 2, 3, 4, 2, 3, 4, 5, 6)
  )

ui <- shinyUI(fluidPage(
  useShinydashboard(),
  tabPanel(
    "Plot",
    sidebarLayout(
      sidebarPanel(
        radioButtons(
          "Choose",
          "Choose One",
          c("Year" = "p", "Numbers" = "l")
        ),
        uiOutput('checkbox'),
        #width = 2,
        position = "bottom"),
      mainPanel(uiOutput("graph"))

    )
  )
))

server <- function(input, output, session) {

  output$graph <- renderUI({
    # create tabPanel with datatable in it
    req(input$year)
    tabPanel("Plots",
             fluidRow(lapply(as.list(paste0("plot", seq_along(input$year))), plotOutput)))

  })

  output$checkbox <- renderUI({
    if (input$Choose == "p") {
      checkboxGroupInput("Cross",
                         "Year",
                         choices = (unique(d$year)))

    } else{
      checkboxGroupInput("Cross_1",
                         "Numbers",
                         choices = c("1","2","3"))
    }

  })

}

shinyApp(ui, server)

现在我面临的挑战是当我选择 "Year" 单选按钮时,年份值显示为复选框,当我 select 复选框时,相应的图表显示在主面板(我没有在这里给出代码)。现在,当我选择 "Number" 单选按钮时,会显示正确的复选框选项。但是当我回到 "Year" 单选按钮时。已经 selected 的复选框值不会保留,因此用户需要再次选中复选框以获取相应的图表。

在我的例子中,CheckboxGroupInput() 中的选择是动态的。所以我将无法在 UI() 中给出这个选择。我也尝试使用失败的 updateCheckboxGroupInput() 。通过再次对代码进行一些调查,我了解到问题发生的地方是这部分代码。

  output$checkbox <- renderUI({
    if (input$Choose == "p") {
      checkboxGroupInput("Cross",
                         "Year",
                         choices = (unique(d$year)))

    } else{
      checkboxGroupInput("Cross_1",
                         "Numbers",
                         choices = c("1","2","3"))
    }

  })

请建议我如何在选中另一个单选按钮时保留复选框中的值。另请注意,每个单选按钮下的复选框选项将根据用户在上一个选项卡中 select 编辑的选项而变化。所以我用observe函数来获取对应的复选框。

我建议 showing/hiding 复选框而不是使用 renderUI。这样,即使它们未显示,它们也会保留其设置。

shinyjs 是一个流行的包,可以为我们做到这一点。我根据上面的代码创建了一个最小的例子来展示它的实际效果:

library(shiny)
library(shinyjs)

ui <- shinyUI(fluidPage(

    useShinyjs(),

    radioButtons("radio_choose", "Choose One", choices = c("Year", "Numbers")),

    checkboxGroupInput("checkbox_years", "Year", choices = c(1995, 1996, 1997, 1997)),

    checkboxGroupInput("checkbox_numbers", "Numbers", choices = c(1, 2, 3))

))

server <- function(input, output, session) {

    #Observe the radio buttons (runs when the radio button changes)
    observeEvent(input$radio_choose, {

        if(input$radio_choose == "Year") {

            shinyjs::show("checkbox_years")
            shinyjs::hide("checkbox_numbers")

        }

        if(input$radio_choose == "Numbers") {

            shinyjs::hide("checkbox_years")
            shinyjs::show("checkbox_numbers")

        }

    })

}

shinyApp(ui, server)

您可以将您尝试保留的年份值存储在反应值中。

  global <- reactiveValues(years = NULL)

  observeEvent(input$Cross, {
    global$years <- input$Cross
  })

然后你使你的动态 ui 依赖于反应值:

checkboxGroupInput(
  "Cross",
  "Year",
  choices = (unique(d$year)),
  selected = global$years
)

可重现的例子:

library(shiny)
library(shinydashboard)
library(shinyWidgets)

d <-
  data.frame(
    year = c(1995, 1995, 1995, 1996, 1996, 1996, 1997, 1997, 1997),
    Product_Name = c(
      "Table",
      "Chair",
      "Bed",
      "Table",
      "Chair",
      "Bed",
      "Table",
      "Chair",
      "Bed"
    ),
    Product_desc = c("X", "X", "X", "Y", "Y", "Y", "Z", "Z", "Z"),
    Cost = c(1, 2, 3, 4, 2, 3, 4, 5, 6)
  )

ui <- shinyUI(fluidPage(
  useShinydashboard(),
  tabPanel(
    "Plot",
    sidebarLayout(
      sidebarPanel(
        radioButtons(
          "Choose",
          "Choose One",
          c("Year" = "p", "Numbers" = "l")
        ),
        uiOutput('checkbox'),
        #width = 2,
        position = "bottom"),
      mainPanel(uiOutput("graph"))

    )
  )
))

server <- function(input, output, session) {

  global <- reactiveValues(years = NULL)

  observeEvent(input$Cross, {
    global$years <- input$Cross
  })

  output$graph <- renderUI({
    # create tabPanel with datatable in it
    req(input$year)
    tabPanel("Plots",
             fluidRow(lapply(as.list(paste0("plot", seq_along(input$year))), plotOutput)))

  })

  output$checkbox <- renderUI({
    if (input$Choose == "p") {
      checkboxGroupInput("Cross",
                         "Year",
                         choices = (unique(d$year)),selected = global$years)

    } else{
      checkboxGroupInput("Cross_1",
                         "Numbers",
                         choices = c("1","2","3"))
    }

  })

}

shinyApp(ui, server)

我认为 Ash 的 shinyjs hide/show 变体也很有趣。我还没有测试过它,但我假设你可以用动态替换静态 ui (?).

这是我的方法,使用 shinyjs 中的 hidden。我还添加了默认 selection 为空,因此反应性没有歧义。尽量避免在名称中单独使用数值变量,例如 "1""2"

library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(shinyjs)

d <- data.frame(
    year = c(1995, 1995, 1995, 1996, 1996, 1996, 1997, 1997, 1997),
    Product_Name = c("Table","Chair","Bed","Table","Chair","Bed","Table","Chair","Bed"),
    Product_desc = c("X", "X", "X", "Y", "Y", "Y", "Z", "Z", "Z"),
    Cost = c(1, 2, 3, 4, 2, 3, 4, 5, 6)
)

ui <- shinyUI(fluidPage(
    useShinyjs(),
    useShinydashboard(),
    tabPanel("Plot",
             sidebarLayout(
                 sidebarPanel(
                     radioButtons("Choose","Choose One", c("Year" = "p", "Numbers" = "b"),selected = character(0)),
                     uiOutput('checkbox'),
                     position = "bottom"),
                 mainPanel(
                     uiOutput("graph")
                 )

             )
    )
))

server <- function(input, output, session) {

    output$checkbox <- renderUI({
        hidden(
            tagList(
                checkboxGroupInput("Cross","Year",choices = (unique(d$year))),
                checkboxGroupInput("Cross_1","Numbers",choices = c("1","2","3"))
            )
        )
    })

    observeEvent(input$Choose,{
        toggleElement(id = "Cross", condition = input$Choose == "p")
        toggleElement(id = "Cross_1", condition = input$Choose == "b")
    })

}

shinyApp(ui, server)

或者,由于 radioButtons 默认为 select 第一个值,您可以隐藏第二个元素:

ui <- shinyUI(fluidPage(
    useShinyjs(),
    useShinydashboard(),
    tabPanel("Plot",
             sidebarLayout(
                 sidebarPanel(
                     radioButtons("Choose","Choose One", c("Year" = "p", "Numbers" = "b")),
                     uiOutput('checkbox'),
                     position = "bottom"),
                 mainPanel(
                     uiOutput("graph")
                 )

             )
    )
))

server <- function(input, output, session) {

    output$checkbox <- renderUI({
        tagList(
            checkboxGroupInput("Cross","Year",choices = (unique(d$year))),
            hidden(checkboxGroupInput("Cross_1","Numbers",choices = c("1","2","3")))
        )
    })

    observeEvent(input$Choose,{
        toggleElement(id = "Cross", condition = input$Choose == "p")
        toggleElement(id = "Cross_1", condition = input$Choose == "b")
    })

}

shinyApp(ui, server)