简体   繁体   English

有没有办法在 shiny 中将选择器/选择输入与可编辑的反应式 DT 结合使用?

[英]Is there a way to use picker/selectInput in conjunction with an editable, reactive DT in shiny?

I have struggled with the following issue and have found no suitable solution on SO.我一直在努力解决以下问题,并且在 SO 上找不到合适的解决方案。

Here is what I require from my DataTable这是我对 DataTable 的要求

  1. I would like to edit my DataTable (achieved)我想编辑我的数据表(已实现)
  2. Filter the data in DataTable with my edits intact.在我的编辑完好无损的情况下过滤 DataTable 中的数据。 Currently, my edits disappear after I change the filters目前,我的编辑在我更改过滤器后消失
  3. Save whole DataTable as RDS rather than just the current displayed data based on filters.将整个 DataTable 保存为 RDS,而不仅仅是基于过滤器的当前显示数据。 Currently, I just save the current displayed DataTable based on filters目前,我只是根据过滤器保存当前显示的 DataTable

Thank you for your help in advance!提前谢谢你的帮助!

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) 

Edit:编辑:

see here看这里

You need to use updatePickerInput() to update the choices available based on the edits.您需要使用updatePickerInput()根据编辑更新可用的选项。 Also, define row id to keep the modified data.此外,定义行 id 以保留修改后的数据。 Using reset you can return to the original datatable.使用重置您可以返回到原始数据表。 Try this尝试这个

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) 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM