ZT_Geo
ZT_Geo

Reputation: 413

Manipulate list data within shiny reactive function

I have a shiny application which reads in multiple csv/txt files, combines them into a list and reactively outputs the data table of the selected file. See below.

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


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"))
))

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)
}

shinyApp(ui, server)

However, I want to take the raw data-frames within the list through ~20 transformations (the same transformations for each data frame) prior to outputting the selected data table. I would like to do this for all of the data tables not just one I am outputting as I plan to make a summary tab. I will also need to do things like make new lists from the original list during this data processing.

As a basic example lets say I want to start by removing the first two rows from every data-frame within my list prior to outputting the selected table using something like lapply(list_of_df, function(x) as.data.frame(x[-c(1,2),])). How would I go about doing this with the shiny app example given above?

Upvotes: 1

Views: 437

Answers (1)

ismirsehregal
ismirsehregal

Reputation: 33580

We can simply add another reactive which is based on the table_list.

Here the first column is dropped:

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

# create dummy CSVs -------------------------------------------------------
DF1 <- data.frame(x = 1:3, y = letters[1:3])
DF2 <- data.frame(x = 4:6, y = letters[4:6])
DF3 <- data.frame(x = 7:9, y = letters[7:9])
DF4 <- data.frame(x = 10:12, y = letters[10:12])

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"),
            DTOutput("filtered_table"))
))

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)
  })
  
  filtered_table_list <- reactive({
    req(table_list())
    lapply(table_list(), function(DT) {
      DT[, -c(1)]
    })
  })
  
  output$table <- renderDT({
    req(table_list(), input$selected_table)
    table_list()[[input$selected_table]]
  }, server = FALSE)
  
  output$filtered_table <- renderDT({
    req(filtered_table_list(), input$selected_table)
    filtered_table_list()[[input$selected_table]]
  }, server = FALSE)
}

shinyApp(ui, server)

PS: If not yet done, check out library(data.table) for fast and memory efficient data manipulation:

https://cran.r-project.org/web/packages/data.table/vignettes/datatable-intro.html

https://s3.amazonaws.com/assets.datacamp.com/blog_assets/datatable_Cheat_Sheet_R.pdf

Upvotes: 1

Related Questions