【问题标题】:Shiny: How to prevent selectInput from being reset by selecting a second selectInputShiny:如何通过选择第二个 selectInput 来防止 selectInput 被重置
【发布时间】:2021-06-13 08:30:53
【问题描述】:

这是建立在我提出的问题 here 的基础上,但我正在简化示例,以便更易于阅读(因此对未来的搜索者来说更容易)。

可重现的示例

这是数据:

library(tidyverse)
library(shiny)

food_table <- structure(list(Food_category = c("Fruit", "Fruit", "Fruit", "Fruit", 
                                               "Vegetable", "Vegetable", "Fruit", "Fruit", "Fruit", "Vegetable"
), Food = c("Granny Smith apple", "McIntosh apple", "Avocado", 
            "Blueberries", "Broccoli, steamed", "Cucumber", "Banana", "Cherries", 
            "Nectarine", "Red onion"), Serving_Size = c(1, 1, 0.333333333333333, 
                                                        1, 1, 1, 1, 1, 1, 1), Serving_Unit = c("apple", "apple", "avocado", 
                                                                                               "cup", "cup", "cup", "banana", "cup", "nectarine", "cup"), Carbs_per_Serving = c(25, 
                                                                                                                                                                                25, 4, 21, 3.5, 4, 27, 25, 15, 11)), row.names = c(NA, -10L), class = c("tbl_df", 
                                                                                                                                                                                                                                                        "tbl", "data.frame"))


(food_table)

   Food_category Food               Serving_Size Serving_Unit Carbs_per_Serving
   <chr>         <chr>                     <dbl> <chr>                    <dbl>
 1 Fruit         Granny Smith apple        1     apple                     25  
 2 Fruit         McIntosh apple            1     apple                     25  
 3 Fruit         Avocado                   0.333 avocado                    4  
 4 Fruit         Blueberries               1     cup                       21  
 5 Vegetable     Broccoli, steamed         1     cup                        3.5
 6 Vegetable     Cucumber                  1     cup                        4  
 7 Fruit         Banana                    1     banana                    27  
 8 Fruit         Cherries                  1     cup                       25  
 9 Fruit         Nectarine                 1     nectarine                 15  
10 Vegetable     Red onion                 1     cup                       11  

我有一个闪亮的应用程序,它有多个输入。这有效,除了在第二个食品类别框中进行新选择时,第一行中的食品选择变回第一个元素。换句话说,如果我在第一行选择“水果”,然后选择“鳄梨”和“1”,那么当我转到第二行并选择“蔬菜”时,选择的食物项目从“鳄梨”变为“奶奶”史密斯苹果”。我试图弄清楚一旦做出选择,我如何防止行重置。

这是精简的闪亮代码:

# Table filters
categories <- sort(unique(food_table$Food_category))
foods      <- sort(unique(food_table$Food))
unit       <- sort(unique(food_table$Serving_Unit))

# Create Shiny app 

   # Define UI
    ui <- fluidPage(headerPanel(strong("Carbohydrate Calculator")),
                    
                    fluidRow(
                      column(
                        width = 3,
                        selectInput(
                          inputId = 'cat_1',
                          label   = 'Food Category',
                          choices = c("None", categories)
                        )),
                      column(
                        width = 3,
                        selectInput(
                          inputId = 'food_1',
                          label   = 'Food Item',
                          choices = foods
                        )),
                      column(
                        width = 3,
                        numericInput(
                          inputId = "actual_serving_1",
                          label = "How much?",
                          value = "",
                          min = 0,
                          max = 100
                        ))
                    ),
                    fluidRow(
                      column(
                        width = 3,
                        selectInput(
                          inputId = 'cat_2',
                          label   = 'Food Category',
                          choices = c("None", categories)
                        )),
                      column(
                        width = 3,
                        selectInput(
                          inputId = 'food_2',
                          label   = 'Food Item',
                          choices = foods
                        )),
                      column(
                        width = 3,
                        numericInput(
                          inputId = "actual_serving_2",
                          label = "How much?",
                          value = "",
                          min = 0,
                          max = 100
                        ))
                    ),
                    
                    column(8,
                           tableOutput("my_table"),
                           span(textOutput("my_message"), style="color:red")
                    ) # Column close
                    
    )                 # fluidPage close
    
    
    
    # Define server logic required to draw a histogram
    server <- function(input, output, session) {
      
      
      food_table_1 <- reactive({
        food_table %>%
          filter(Food_category == input$cat_1) %>% 
          filter(Food == input$food_1) %>% 
          mutate(Actual_amount = input$actual_serving_1) 
      })
      
      food_table_2 <- reactive({
        food_table %>%
          filter(Food_category == input$cat_2) %>% 
          filter(Food == input$food_2) %>% 
          mutate(Actual_amount = input$actual_serving_2) 
      })
      
    
      
      # Combine selections into a single table
      combined_tables <- reactive({
        do.call("rbind", list(food_table_1(),
                              food_table_2()
        )
        ) %>% 
          mutate(Total_Carbs_grams = Carbs_per_Serving * Actual_amount / Serving_Size) %>% 
          select(Food_category, Food, Serving_Size, Serving_Unit, Actual_amount, Carbs_per_Serving, Total_Carbs_grams, everything())
      })
      
      
      # Render Output table
      output$my_table <- renderTable({
        
        combined_tables()
        
      })
      
      
      
      # Create observe function which updates the second selectInput when the first selectInput is changed
      observe({
        
        updateSelectInput(
          session,
          inputId = "food_1",
          choices = food_table %>% filter(Food_category == input$cat_1) %>% pull(Food)
        )
        
        updateSelectInput(
          session,
          inputId = "food_2",
          choices = food_table %>% filter(Food_category == input$cat_2) %>% pull(Food)
        )
        
        
      }) # Observe close
    }    # Server close
    
    
    
    # Run the application 
    shinyApp(ui = ui, server = server)

【问题讨论】:

    标签: r shiny


    【解决方案1】:

    您可以将updateSelectInput中的selected分别设置为input$food_1和input$food_2。

    updateSelectInput(
          session,
          inputId = "food_1",
          choices = food_table %>% filter(Food_category == input$cat_1) %>% pull(Food), 
          selected = input$food_1
        )
    

    完整的应用代码 -

    library(shiny)
    library(dplyr)
    
    categories <- sort(unique(food_table$Food_category))
    foods      <- sort(unique(food_table$Food))
    unit       <- sort(unique(food_table$Serving_Unit))
    
    # Create Shiny app 
    
    # Define UI
    ui <- fluidPage(headerPanel(strong("Carbohydrate Calculator")),
                    
                    fluidRow(
                      column(
                        width = 3,
                        selectInput(
                          inputId = 'cat_1',
                          label   = 'Food Category',
                          choices = c("None", categories)
                        )),
                      column(
                        width = 3,
                        selectInput(
                          inputId = 'food_1',
                          label   = 'Food Item',
                          choices = foods
                        )),
                      column(
                        width = 3,
                        numericInput(
                          inputId = "actual_serving_1",
                          label = "How much?",
                          value = "",
                          min = 0,
                          max = 100
                        ))
                    ),
                    fluidRow(
                      column(
                        width = 3,
                        selectInput(
                          inputId = 'cat_2',
                          label   = 'Food Category',
                          choices = c("None", categories)
                        )),
                      column(
                        width = 3,
                        selectInput(
                          inputId = 'food_2',
                          label   = 'Food Item',
                          choices = foods
                        )),
                      column(
                        width = 3,
                        numericInput(
                          inputId = "actual_serving_2",
                          label = "How much?",
                          value = "",
                          min = 0,
                          max = 100
                        ))
                    ),
                    
                    column(8,
                           tableOutput("my_table"),
                           span(textOutput("my_message"), style="color:red")
                    ) # Column close
                    
    )                 # fluidPage close
    
    
    
    # Define server logic required to draw a histogram
    server <- function(input, output, session) {
      
      
      food_table_1 <- reactive({
        food_table %>%
          filter(Food_category == input$cat_1) %>% 
          filter(Food == input$food_1) %>% 
          mutate(Actual_amount = input$actual_serving_1) 
      })
      
      food_table_2 <- reactive({
        food_table %>%
          filter(Food_category == input$cat_2) %>% 
          filter(Food == input$food_2) %>% 
          mutate(Actual_amount = input$actual_serving_2) 
      })
      
      
      
      # Combine selections into a single table
      combined_tables <- reactive({
        do.call("rbind", list(food_table_1(),
                              food_table_2()
        )
        ) %>% 
          mutate(Total_Carbs_grams = Carbs_per_Serving * Actual_amount / Serving_Size) %>% 
          select(Food_category, Food, Serving_Size, Serving_Unit, Actual_amount, Carbs_per_Serving, Total_Carbs_grams, everything())
      })
      
      
      # Render Output table
      output$my_table <- renderTable({
        
        combined_tables()
        
      })
      
      
      
      # Create observe function which updates the second selectInput when the first selectInput is changed
      observe({
        
        updateSelectInput(
          session,
          inputId = "food_1",
          choices = food_table %>% filter(Food_category == input$cat_1) %>% pull(Food), 
          selected = input$food_1
        )
        
        updateSelectInput(
          session,
          inputId = "food_2",
          choices = food_table %>% filter(Food_category == input$cat_2) %>% pull(Food), 
          selected = input$food_2
        )
        
        
      }) # Observe close
    }    # Server close
    
    
    
    # Run the application 
    shinyApp(ui = ui, server = server)
    

    【讨论】:

      猜你喜欢
      • 2021-05-17
      • 2022-10-14
      • 2017-10-19
      • 2019-01-19
      • 2021-02-08
      • 1970-01-01
      • 2017-04-22
      • 2016-09-06
      • 2021-03-24
      相关资源
      最近更新 更多