连续删除 Shiny DT 中的行 table

Consecutively deleting rows in Shiny DT table

我有一个闪亮的应用程序,用户可以在其中上传自己的数据。我的目标是显示一个带有 DT 的交互式 table,允许用户控制显示哪些列和哪些行。最终,用户应该能够下载他们上传的所有数据(在实际应用程序中完成了一些处理步骤)或仅下载他们在当前 selection 中看到的数据。因此,我需要复制上传的数据框,而不是就地编辑它。

我的问题是我可以使列 select 可用,我也可以删除 selected 行,但我找不到保存 selected 的方法之间的行。例如:当用户首先 select 第 1、2 和 3 行并单击“排除行”时,这些行消失了,但是当他们随后单击第 4 行和第 5 行并单击“排除行”时,第 4 行和5 消失了 但 1,2 和 3 弹回来了

这是我到目前为止尝试过的方法:

# Reproducible example

# Define UI
ui <- fluidPage(

  navbarPage("Navbar",
    tabPanel("Upload Data",
             fileInput(inputId = "file", label = "Upload your .csv file",
                                                  accept = "text/csv"),
             actionButton("submit","Use this dataset")
    ),

    tabPanel("Check Table",

             sidebarPanel("Settings",

                          checkboxGroupInput("show_vars", "Select Columns to display:",

                                             choices = c("type",
                                                         "mpg",
                                                         "cyl",
                                                         "disp",
                                                         "hp",
                                                         "drat",
                                                         "wt",
                                                         "qsec",
                                                         "vs",
                                                         "am",
                                                         "gear",
                                                         "carb"
                                                         ),

                                             selected = c("type",
                                                          "mpg",
                                                          "cyl",
                                                          "disp",
                                                          "hp",
                                                          "drat",
                                                          "wt",
                                                          "qsec",
                                                          "vs",
                                                          "am",
                                                          "gear",
                                                          "carb"
                                             )),

                          tags$br(),
                          tags$br(),

                          actionButton("excludeRows", "Exlcude selected Rows")),

             mainPanel(DTOutput("frame"))),

    tabPanel("Show Selection",
             textOutput("selection"))

  )

)

# Define server logic
server <- function(input, output, session) {

  # Parsing the uploaded Dataframe according to the right input
  data <- eventReactive(input$submit, {read.csv(input$file$datapath)})

  # Render the whole dataframe when a new one is uploaded
  observeEvent(input$submit, {output$frame <- renderDT(datatable(data()[,c(input$show_vars)]))})

  # Making an internal copy for selection purposes
  CopyFrame <- eventReactive(data(),{data()})

  # excluding selected rows
  observeEvent(input$excludeRows,{

    if (exists("SelectFrame()")) {

      # Updating SelectFrame from SelectFrame
      SelectFrame <- eventReactive(input$excludeRows,{SelectFrame()[-c(input$frame_rows_selected),c(input$show_vars)]})

    } else {

      # creating SelectFrame for the first time from CopyFrame
      SelectFrame <- eventReactive(input$excludeRows,{CopyFrame()[-c(input$frame_rows_selected),c(input$show_vars)]})

    }

    # updating plot
    output$frame <- renderDT(datatable(SelectFrame()))

  })

  # show Selection
  output$selection <- renderText(input$frame_rows_selected)

}

# Run the application
shinyApp(ui = ui, server = server)

您可以轻松地为这个可重现的示例创建一个示例文件:

names(mtcars)[1] <- "type"
write.csv(mtcars, file = "testfile.csv")

也许您可以使用 reactiveValues 来存储您编辑的数据框。加载新的 csv 文件时,存储在 rv$data 中。然后,当您排除行时,您可以每次修改数据框并将 rv$data 替换为结果。您的 output$frame 可以仅显示此修改后的 rv$data 并且仅显示通过 input$show_vars 选择的列。这对你有用吗?

server <- function(input, output, session) {
  
  rv <- reactiveValues(data = NULL)
  
  observeEvent(input$submit, {
    rv$data <- read.csv(input$file$datapath)
  })
  
  observeEvent(input$excludeRows,{
    rv$data <- rv$data[-c(input$frame_rows_selected),c(input$show_vars)]
  })
  
  output$frame <- renderDT({
    datatable(rv$data[c(input$show_vars)])
  })
  
}

这是一个适用于原始数据帧行号的解决方案:

library(shiny)
library(DT)

# Define UI
ui <- fluidPage(
  
  navbarPage("Navbar",
             tabPanel("Upload Data",
                      fileInput(inputId = "file", label = "Upload your .csv file",
                                accept = "text/csv"),
                      actionButton("submit","Use this dataset")
             ),
             
             tabPanel("Check Table",
                      
                      sidebarPanel("Settings",
                                   
                                   checkboxGroupInput("show_vars", "Select Columns to display:",
                                                      
                                                      choices = c("type",
                                                                  "cyl",
                                                                  "disp",
                                                                  "hp",
                                                                  "drat",
                                                                  "wt",
                                                                  "qsec",
                                                                  "vs",
                                                                  "am",
                                                                  "gear",
                                                                  "carb"
                                                      ),
                                                      
                                                      selected = c("type",
                                                                   "cyl",
                                                                   "disp",
                                                                   "hp",
                                                                   "drat",
                                                                   "wt",
                                                                   "qsec",
                                                                   "vs",
                                                                   "am",
                                                                   "gear",
                                                                   "carb"
                                                      )),
                                   
                                   tags$br(),
                                   tags$br(),
                                   
                                   actionButton("excludeRows", "Exlcude selected Rows")),
                      
                      mainPanel(DTOutput("frame"))),
             
             tabPanel("Show Selection",
                      textOutput("selection"))
             
  )
  
)

# Define server logic
server <- function(input, output, session) {
  
  # initialise index which rows are shown
  rows_shown <- reactiveVal()
  
  # Parsing the uploaded Dataframe according to the right input
  data <- eventReactive(input$submit, {
    data <- read.csv(input$file$datapath)
    data <- cbind(data, data.frame(row_number = seq_len(nrow(data))))
    data
    })
  
  # Making an internal copy for selection purposes
  CopyFrame <- eventReactive(input$submit, {data()})
  
  observeEvent(input$submit, {
    # set up row index
    rows_shown(seq_len(nrow(data())))
  })
  
  # excluding selected rows
  observeEvent(input$excludeRows,{
    # use an extra column for the row numbers to refer to the row number of the
    # original dataframe and not the subsetted one
    actual_row_numbers <- CopyFrame()[rows_shown(), "row_number"][input$frame_rows_selected]
    row_index <- !rows_shown() %in% actual_row_numbers
    new_rows <- rows_shown()[row_index]
    rows_shown(new_rows)
  })
  
  # show Selection
  output$selection <- renderText(input$frame_rows_selected)
  
  # show dataframe
  output$frame <- renderDT({
    datatable(CopyFrame()[rows_shown(), input$show_vars])
    })
  
}

# Run the application
shinyApp(ui = ui, server = server)