【问题标题】:Is there a way to use picker/selectInput in conjunction with an editable, reactive DT in shiny?有没有办法将选择器/selectInput 与闪亮的可编辑、反应式 DT 结合使用?
【发布时间】:2021-05-08 05:20:46
【问题描述】:

我一直在努力解决以下问题,但在 SO 上找不到合适的解决方案。

这是我对 DataTable 的要求

  1. 我想编辑我的数据表(已完成)
  2. 在我的编辑完好无损的情况下过滤 DataTable 中的数据。目前,我的修改会在我更改过滤器后消失
  3. 将整个 DataTable 保存为 RDS,而不仅仅是基于过滤器显示的当前数据。目前,我只是根据过滤器保存当前显示的DataTable

提前感谢您的帮助!

df <- iris

species <- unique(as.character(df$Species))
width <- unique(df$Petal.Width)
#==========================================UI=======================================================#
ui = navbarPage("CSAT & SA", theme = shinytheme("flatly"),
                tabPanel("Sentiment Analysis",
                         sidebarLayout(
                           sidebarPanel(
                             pickerInput(inputId = "species",
                                         label = "Species", selected = species,
                                         choices = species, multiple = T, 
                                         options = list(`actions-box` = TRUE, `deselect-all-text` = "None...",
                                                        `select-all-text` = "Select All", `none-selected-text` = "None Selected")),
                             pickerInput(inputId = "width",
                                         label = "Petal Width", selected = width,
                                         choices = width, multiple = T, 
                                         options = list(`actions-box` = TRUE, `deselect-all-text` = "None...",
                                                        `select-all-text` = "Select All", `none-selected-text` = "None Selected")),
                             width = 2, 
                             actionButton(inputId = "save", label = "Save"), 
                             actionButton(inputId = "update", label = "Update")
                           ),
                           mainPanel(
                             h2("Iris"), fluidRow(
                               tabPanel("Iris", DT::dataTableOutput("x1"),
                                        width = 12)
                             )))))
#==========================================SERVER=======================================================#

server <- function(input, output, session) {
  
  SA <- reactive({
    df<-df %>%
      filter(Species %in% input$species) %>%
      filter(Petal.Width %in% input$width)
  }) 
  
  
  rec_val = reactiveValues(df = NULL)
  
  
  observe({
    rec_val$SA <- SA()
  })
  
  output$x1 = renderDT(SA(),  selection = 'none', editable = list(target = 'cell', disable = list(columns=c(0,1,2))))
  
  proxy = dataTableProxy('x1')
  
  observeEvent(input$x1_cell_edit, {
    info = input$x1_cell_edit
    str(info)
    i = info$row
    j = info$col   
    v = info$value
    rec_val$SA[i, j] <<- DT::coerceValue(v, rec_val$SA[i, j])
    replaceData(proxy, rec_val$SA, resetPaging = FALSE)
  })
  
  observeEvent(input$save, {
    saveRDS(rec_val$SA, "somewhere.rds") # write new data out
    
  })

  
  
}

shinyApp(ui = ui, server = server) 

编辑:

see here

【问题讨论】:

    标签: r shiny datatable dt


    【解决方案1】:

    您需要使用updatePickerInput() 根据编辑更新可用的选项。此外,定义行 id 以保留修改后的数据。使用重置,您可以返回到原始数据表。试试这个

    library(shinythemes)
    dat <- iris
    
    species <- unique(as.character(dat$Species))
    width <- unique(dat$Petal.Width)
    #==========================================UI=======================================================#
    ui = navbarPage("CSAT & SA", theme = shinytheme("flatly"),
                    tabPanel("Sentiment Analysis",
                             sidebarLayout(
                               sidebarPanel(
                                 pickerInput(inputId = "species",
                                             label = "Species", selected = species,
                                             choices = as.list(species), multiple = T, 
                                             options = list(`actions-box` = TRUE, `deselect-all-text` = "None...",
                                                            `select-all-text` = "Select All", `none-selected-text` = "None Selected")),
                                 pickerInput(inputId = "width",
                                             label = "Petal Width", selected = width,
                                             choices = as.list(width), multiple = T, 
                                             options = list(`actions-box` = TRUE, `deselect-all-text` = "None...",
                                                            `select-all-text` = "Select All", `none-selected-text` = "None Selected")),
                                 width = 2, 
                                 actionButton(inputId = "save", label = "Save"), 
                                 actionButton(inputId = "reset", label = "Reset")
                               ),
                               mainPanel(
                                 h2("Iris"), fluidRow(
                                   tabPanel("Iris", DT::dataTableOutput("x1"), DTOutput("x2"),
                                            width = 12)
                                 )))))
    #==========================================SERVER=======================================================#
    
    server <- function(input, output, session) {
      
      SA <- reactive({
        row_id <- c(1:nrow(dat))
        data <- data.frame(dat,row_id)
        data
      })
      
      rv = reactiveValues(df = NULL)
      
      observe({
        rv$df <- SA() %>%
          filter(Species %in% isolate(input$species)) %>%
          filter(Petal.Width %in% isolate(input$width))
      })
      
      observeEvent(input$species, {
                      df1 <- SA()         ### orig data
                      df2 <- rv$df        ### modified data
                      if (is.null(df2)){
                        rvdf <- SA()
                      }else{
                        vn <- colnames(df1)
                        vnx <- paste0(vn,".x")
                        vny <- paste0(vn,".y")
    
                        rvdf <- left_join(df1, df2, by="row_id") %>% transmute(var1 = get(!!vnx[1]), var2 = get(!!vnx[2]), var3 = get(!!vnx[3]),
                                                                                var4 = ifelse(is.na(get(!!vny[4])), get(!!vnx[4]), get(!!vny[4])),
                                                                                var5 = get(!!vnx[5]),  # ifelse(is.na(get(!!vny[5])), get(!!vnx[5]), get(!!vny[5])),
                                                                                row_id)
    
                        colnames(rvdf) <- vn
                      }
                      rv$df <- rvdf  %>%
                        filter(Species %in% input$species) %>% 
                        filter(Petal.Width %in% input$width)
    
      })
      
      observeEvent(input$width, {
        df1 <- SA()         ### orig data
        df2 <- rv$df        ### modified data
        if (is.null(df2)){
          rvdf <- SA()
        }else{
          
          vn <- colnames(df1)
          vnx <- paste0(vn,".x")
          vny <- paste0(vn,".y")
          ###    keep modified data, if present; if not, keep original data
          rvdf <- left_join(df1, df2, by="row_id") %>% transmute(var1 = get(!!vnx[1]), var2 = get(!!vnx[2]), var3 = get(!!vnx[3]),
                                                                  var4 = ifelse(is.na(get(!!vny[4])), get(!!vnx[4]), get(!!vny[4])),  ##  keep modified data
                                                                  var5 = get(!!vnx[5]),  # ifelse(is.na(get(!!vny[5])), get(!!vnx[5]), get(!!vny[5])),
                                                                  row_id)
          
          colnames(rvdf) <- vn
          
        }
        rv$df <- rvdf  %>%
          filter(Species %in% input$species) %>% 
          filter(Petal.Width %in% input$width)
        
      })
      
      output$x1 <- renderDT(rv$df,  selection = 'none',
                           editable = list(target = 'cell', disable = list(columns=c(0,1,2))),
                           options = list(
                             columnDefs = list(
                               list(
                                 visible = FALSE,
                                 targets = 6
                               )
                             )
                           )
                           )
      
      proxy <- dataTableProxy('x1')
      
      observeEvent(input$x1_cell_edit, {
        info = input$x1_cell_edit
        str(info)
        i = info$row
        j = info$col   
        v = info$value
        
        rv$df[i, j] <<- DT::coerceValue(v, rv$df[i, j])
        
        #replaceData(proxy, rv$df, resetPaging = FALSE)
        
      })
      
      observeEvent(input$save, {
        #choicess <- as.list(unique(c(as.character(rv$df[,5]), as.character(SA()[,5]))))
        choicesp <- as.list(unique(c(rv$df[,4], SA()[,4])))
        # updatePickerInput(session, inputId = "species", choices = choicess, selected=choicess)
        updatePickerInput(session, inputId = "width", choices = choicesp, selected=choicesp)
        saveRDS(rv$df, "somewhere.rds") # write new data out
        
        df3 <- readRDS("C:/My Disk Space/_My Work/RStuff/GWS/somewhere.rds")
        output$x2 <- renderDT({
          df3
        })
        
      })
      observeEvent(input$reset, {
        rv$df <- SA()
        # choicess <- unique(as.character(rv$df[,5]))
        choicesp <- unique(SA()[,4])
        # updatePickerInput(session, inputId = "species", choices = choicess, selected=choicess)
        updatePickerInput(session, inputId = "width", choices = choicesp, selected=choicesp)
      })
      
    }
    
    shinyApp(ui = ui, server = server) 
    

    【讨论】:

    • 你好@YBS,一切都很好。但是,保存更改后过滤器功能似乎无法正常工作。如果我过滤以进行编辑,我将不再能够返回未应用我的更改的过滤器。再次感谢!
    • 您可能需要根据您的用例调整程序。我不确定您要做什么。另外,请注意,由于 Species 是具有 3 个因子级别的字符,您无法编辑这些值;如果这样做,它将显示空白 (na)。
    • 用户可能希望使用不同的过滤器组合进行许多更改。目前,这是不可能的。用户只能应用一个过滤器,基于一个过滤器进行编辑,保存编辑,然后使用不同的过滤器进行其他更改,必须重新加载数据。用截图查看我的编辑。尽管有 Setosa AND Virginica 的过滤器,但花瓣宽度更改的第一个 DT 仅显示 Setosa 的值。
    • @ttam10,请查看更新后的代码。您可能需要稍微调整一下以满足您的需求。您确实需要单击保存按钮来保存更改,这将显示过滤器的更新选项。请注意,我只为petal.width 列实现了这个。如有必要,您需要更新以对其他列(在 transmute 中)实施相同的操作。底部的表格用于显示保存的内容。你可以删除它。
    • 无缝运行。泰!
    猜你喜欢
    • 2019-10-25
    • 2017-12-31
    • 2014-02-23
    • 2020-09-30
    • 2019-04-05
    • 2022-01-12
    • 2021-12-25
    • 2017-03-15
    相关资源
    最近更新 更多