2

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?

3
  • In order to make changes to the underlying data sets permanent you can add an actionButton that contains logic to write the contents of the variables in memory for the current session back to the file system the same way you do when you create the dummy CSVs. Commented Nov 14, 2022 at 18:18
  • @br00t Thanks for the suggestions. For my actual application, I have to do a lot of tidying of the files prior to getting to the row deletion point. The table isn't really important here but the plots and statistics that depend upon the contents of the table. If there is a way to save the deletion without making new files that would be preferred. Commented Nov 14, 2022 at 18:33
  • 1
    This may help you get to what you want. Delete Rows from Shiny DT Commented Nov 14, 2022 at 18:33

1 Answer 1

3
+50

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)
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks this works great here! In my actual application I am having some trouble implementing it however. The list 'table_list' value from this example is actually a reactive() expression in my actual code derived from other reactive expressions. So when I try to run this example I get the error Error in table_list: unused argument (tmp_table_list). Is there a way to convert a reactive expression to reactiveVal()?
Please see my follow up question stackoverflow.com/questions/74525623/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.