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

Posted

技术标签:

【中文标题】如何在 R Shiny App 中保留复选框中的值?【英文标题】:How to Retain the values in the Check Box in R Shiny App? 【发布时间】:2020-08-06 12:40:11 【问题描述】:

我正在尝试创建一个闪亮的应用程序。在这个特定的应用程序中,我有一组单选按钮,其中选择一个将在下面显示一组选项作为复选框,选择另一个单选按钮将选择其他选项集。请在下面找到 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)

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

在我的例子中,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"))
    

  )

即使选择了另一个单选按钮,请建议我如何保留复选框中的值。另请注意,每个单选按钮下的复选框选项将根据用户在上一个选项卡中选择的选项而改变。所以我使用观察函数来获取对应的复选框。

【问题讨论】:

【参考方案1】:

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

  global <- reactiveValues(years = NULL)

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

然后你让你的动态用户界面依赖于反应值:

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 隐藏/显示变体也很有趣。我还没有测试过,但我认为你可以用动态替换静态 ui (?)。

【讨论】:

非常感谢 :) 这确实有效。现在我可以保留复选框中的值。实际上我想要做的是当用户选择一个复选框时,将在主面板中相应地绘制一个绘图。现在,当用户单击年份单选按钮中的复选框时,将绘制图表。但是当用户点击数字单选按钮中的复选框时。图表正在绘制。但是它们被绘制在屏幕下方。在主面板中我应该使用两个 UIOutput 值吗?用于在同一级别绘制这些图表? 呸,不看实际代码就不是那么容易理解了。也许您可以在一个新问题中分享这一点,我很高兴在那里看看! 感谢您对这个 Tonio 的帮助,我已经在这里发布了问题 (***.com/q/62441281/11104327)【参考方案2】:

我建议显示/隐藏复选框,而不是使用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)

【讨论】:

感谢您的回答。您的答案添加了一个新的视角。我有个疑问。 CheckboxGroupInput() 中的选择在我的情况下是动态的。所以我将无法在 UI() 中给出这个选择。有没有办法解决这个问题? 当然,updateCheckboxGroupInput 会让您动态更改选择。使用我上面提供的代码并添加 updateCheckboxGroupInput。 您好,感谢灰的建议。我使用了 updateCheckboxGroupInput,我收到错误“as.vector 中的错误:无法将类型‘环境’强制转换为‘字符’类型的向量”。我不确定为什么会发生这个特定问题。我对此感到困惑。【参考方案3】:

这是我的方法,使用来自shinyjshidden。我还添加了默认选择为空,因此反应性没有歧义。请尽量避免在名称中单独使用数值变量,例如"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 默认选择第一个值,您可以隐藏第二个元素:

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)

【讨论】:

非常感谢 :) 您的回答让我对如何处理这个问题有了新的认识。现在我能够保留这些值。但我无法将主面板中的图表作为两个单选按钮下的复选框选择。你能帮我解决这个问题吗?我发布了一个单独的问题,解释了我面临的问题。 ***.com/q/62441281/11104327你的建议对我有很大帮助。

以上是关于如何在 R Shiny App 中保留复选框中的值?的主要内容,如果未能解决你的问题,请参考以下文章

Shiny r-单击后如何禁用复选框组输入?

在 R Shiny 中创建第二个 UI 元素

在 R Shiny App 中,如何在首次调用 App 时呈现默认表格?

r 将模块中返回的值存储在Shiny中的reactiveValues中

根据 r shiny 中的选定类别创建图表饼图

在 R Shiny 中使用 renderTable 时如何格式化数字行输出?