ZT_Geo
ZT_Geo

Reputation: 413

Delete rows from data frames in shiny using DataTable (server side)

I have a shiny application where I read in multiple .csv files (dummy .csvs for this example) and store them as a list of data frames which can be selected with a drop down tab. When a file is selected using the drop down tab a table is displayed using renderDT and a scatter plot using the values in that table is also shown. You can use the dummy csv's created in your directory to try this.

library(DT)
library(shiny)
library(data.table)

# create dummy CSVs -------------------------------------------------------
DF1 <- data.frame(x = 1:3, y = 2:4)
DF2 <- data.frame(x = 4:2, y = 5:7)
DF3 <- data.frame(x = 7:9, y = 8:10)
DF4 <- data.frame(x = 10:8, y = 11:13)

mapply(
  write.csv,
  x = list(DF1, DF2, DF3, DF4),
  file = list("DF1.csv", "DF2.csv", "DF3.csv", "DF4.csv"),
  row.names = FALSE
)

# shiny app ---------------------------------------------------------------
ui <- fluidPage(sidebarLayout(
  sidebarPanel(
    fileInput(
      "files",
      "Choose File",
      multiple = TRUE,
      accept = c(
        "text/csv",
        "text/comma-separated-values,text/plain",
        ".dp_txt",
        ".is_txt"
      )
    ),
    
    selectizeInput(
      inputId = "selected_table",
      label = "Table Selection",
      choices = NULL,
      selected = NULL,
      multiple = FALSE
    ),
    
    
  ),
  mainPanel(DTOutput("table"), plotOutput("plot"))
))

server <- function(input, output, session) {
  observeEvent(input$files, {
    freezeReactiveValue(input, "selected_table")
    updateSelectizeInput(session,
                         inputId = "selected_table",
                         choices = input$files$name,
                         server = TRUE)
  })
  
  
  table_list <- reactive({
    req(input$files)
    setNames(lapply(input$files$datapath, function(x) {
      fread(x)
    }),
    input$files$name)
  })
  
  
  
  output$table <- renderDT({
    req(table_list(), input$selected_table)
    table_list()[[input$selected_table]]
  }, server = FALSE)
  
  
  output$plot <- renderPlot({
    temp <- table_list()[[input$selected_table]]
    plot(temp$x, temp$y)
    
  })
}

shinyApp(ui, server)

How can I delete rows of data for individual data frames and the corresponding point on the plot? Basically, when a row is deleted I want the row to be deleted on the server side so that any other plots or tables depending on that original table are also updated. Lastly, I want this deletion to remain permanent so that when switching through the different dataframes the rows/points you deleted don't come back when return to that dataframe. How can I do this?

Upvotes: 2

Views: 127

Answers (1)

ismirsehregal
ismirsehregal

Reputation: 33417

This seems to be a follow-up on my earlier answer here.

Once you need to modify a reactive in multiple places, we need to use reactiveVal or reactiveValues.

Please check the observeEvent(input$deleterow, ... call:

library(DT)
library(shiny)
library(data.table)

# create dummy CSVs -------------------------------------------------------
DF1 <- data.frame(x = 1:3, y = 2:4)
DF2 <- data.frame(x = 4:2, y = 5:7)
DF3 <- data.frame(x = 7:9, y = 8:10)
DF4 <- data.frame(x = 10:8, y = 11:13)

mapply(
  write.csv,
  x = list(DF1, DF2, DF3, DF4),
  file = list("DF1.csv", "DF2.csv", "DF3.csv", "DF4.csv"),
  row.names = FALSE
)

# shiny app ---------------------------------------------------------------
ui <- fluidPage(sidebarLayout(
  sidebarPanel(
    fileInput(
      "files",
      "Choose File",
      multiple = TRUE,
      accept = c(
        "text/csv",
        "text/comma-separated-values,text/plain",
        ".dp_txt",
        ".is_txt"
      )
    ),
    selectizeInput(
      inputId = "selected_table",
      label = "Table Selection",
      choices = NULL,
      selected = NULL,
      multiple = FALSE
    ),
  ),
  mainPanel(DTOutput("table"),
            actionButton("deleterow", "Delete row(s)"),
            plotOutput("plot"))
))

server <- function(input, output, session) {
  observeEvent(input$files, {
    freezeReactiveValue(input, "selected_table")
    updateSelectizeInput(session,
                         inputId = "selected_table",
                         choices = input$files$name,
                         server = TRUE)
  })
  
  table_list <- reactiveVal()
  
  observeEvent(input$files, {
    req(input$files)
    table_list(setNames(lapply(input$files$datapath, function(x) {
      fread(x)
    }),
    input$files$name))
  })
  
  observeEvent(input$deleterow, {
    if(!is.null(input$table_rows_selected)){
      tmp_table_list <- table_list()
      tmp_table_list[[input$selected_table]] <- table_list()[[input$selected_table]][-input$table_rows_selected]
      table_list(tmp_table_list)
    }
  })
  
  output$table <- renderDT({
    req(table_list(), input$selected_table)
    table_list()[[input$selected_table]]
  }, server = FALSE)
  
  output$plot <- renderPlot({
    temp <- table_list()[[input$selected_table]]
    req(NROW(temp) > 0)
    plot(temp$x, temp$y)
  })
}

shinyApp(ui, server)

Upvotes: 3

Related Questions