Home > Blockchain >  Reset processed data after new file is uploaded
Reset processed data after new file is uploaded

Time:02-06

I am developing a Shiny app to process temperature data. Sometimes, temperatures loggers are set up in the lab and start measuring before actually being deployed in the field. Therefore, I need to allow the user to crop the data to the actual on-site measurements.

The upload and cropping are both triggered by actionButtons because they require other inputs (time format, delimiter etc.) I have not included in the MWE.

To avoid mixing up datasets, I would like the previous cropped data to be hidden (or better, set to NULL) if a new raw dataset is uploaded.

I tried the following:

ui

library("tidyverse") 
library("magrittr") 
library("DT")
library("xts") 
library("shiny") 
library("shinydashboard")

ui <- dashboardPage(
  skin = "green",
  dashboardHeader(title = "MWE"),
  dashboardSidebar(
    sidebarMenu(
      menuItem("Upload data", tabName = "upload")
      )
  ),
  dashboardBody(
    tabItems(
      tabItem(tabName = "upload",
              fluidRow(
                box(
                  title = "Upload settings",
                  width = 5,
                  fileInput("fname", "Data", buttonLabel = "Browse..."),
                  actionButton("uploadbtn", "Upload")
                ),
                box(
                  title = "Raw data",
                  width = 7,
                  DTOutput("raw_table")
                )
              ),
              fluidRow(
                uiOutput("crop_box"),
                box(
                  width = 8,
                  h4(strong("Do you wish to crop your data to the selected times?")),
                  br(),
                  actionButton("cropbtn", "Crop")
                )
              ),
              fluidRow(
                box(
                  title = "Cropped dataset",
                  width = 12,
                  DTOutput("cropped_table")
                )
              )
      )
    )
  )
)

server

server <- function(input, output, session) {
  
  uploaded <- reactiveVal(FALSE)
  observeEvent(input$uploadbtn, {
    uploaded(TRUE)
  })
  
  # Upload raw data
  raw <- bindEvent(reactive({
    req(input$fname)
    
    # Read in data as zoo object the convert to xts
    read.delim.zoo(file = input$fname$datapath,
                   sep = "\t",
                   skip = 0,
                   header = TRUE,
                   dec = ".",
                   drop = FALSE,
                   FUN = as.POSIXct,
                   tz = "",
                   format = "%Y.%m.%d %H:%M:%S") %>% as.xts
  }), 
  input$uploadbtn # Only upload once button is clicked
  )
  
  # Display raw data
  output$raw_table <- renderDT({
    req(raw())
    datatable(as.data.frame(raw()), options = list(scrollX = TRUE))
  })
  
  # Select beginning and end of dataset
  first_data <- reactive({
    raw() %>% first("1 days") %>% zoo
  })
  
  last_data  <- reactive({
    raw() %>% last("1 days")  %>% zoo
  })
  
  output$crop_box <- renderUI({
    box(
      width = 4,
      h4(strong("Select the start and end time of on-site measurements.")),
      sliderInput("onsite_start", "Start of on-site measurements",
                  min = as.POSIXct(min(index(first_data()))), 
                  max = as.POSIXct(max(index(first_data()))),
                  value = min(index(first_data())),
                  timeFormat = "%F %R"),
      sliderInput("onsite_end", "End of on-site measurements", 
                  min = as.POSIXct(min(index(last_data()))), 
                  max = as.POSIXct(max(index(last_data()))),
                  value = max(index(last_data())))
    )
  })
  
  cropped <- bindEvent(reactive({
    req(raw(), uploaded())
    start_indx <- index(raw()) >= as.POSIXct(input$onsite_start) # Get start
    end_indx   <- index(raw()) <= as.POSIXct(input$onsite_end) # Get end
    raw()[which(start_indx & end_indx), , drop = FALSE]
  }), 
  input$cropbtn # Only compute once button is clicked
  )
  
  output$cropped_table <- renderDT({
    req(cropped())
    cropped_data <- isolate(cropped())
    uploaded(FALSE)
    datatable(as.data.frame(cropped_data))
  })
  
  observeEvent(input$uploadbtn, {
    updateSliderInput(session = session, "first", value = 1)
    updateSliderInput(session = session, "last", value = 1)
    updateSliderInput(session = session, "onsite_start", value = as.POSIXct(min(index(first_data()))))
    updateSliderInput(session = session, "onsite_end", value = as.POSIXct(max(index(last_data()))))
  })
}

shinyApp(ui, server)

My plan was to use uploaded <- reactiveVal(TRUE) as a flag, and to set it to FALSE once the dataset had been cropped, so that it could be set to TRUE again with a new upload. Obviously this doesn't work as the cropped dataset still shows after a new upload. Note, however, that the updateSliderInputs work as expected when the upload button is clicked, so I gather the error must be in my strategy rather than purely my syntax.

I also tried

observeEvent(input$uploadbtn, {
  cropped <<- reactive(NULL)
})

but this obviously just results in nothing being displayed at all, even after clicking input$cropbtn. I struggle to see how to build a condition that fits my needs.

I have looked at Resetting data in R shiny app when file upload fields change, Shiny resetting and updating reactiveValues dataframe with two different buttons, r - How to reset reactiveValues, and shiny - How to invalidate ractive observer using code?. Unfortunately, they did not allow me to find a solution.

Please find sample data here and here (the same data with different dates so you can tell them apart easily).

CodePudding user response:

Try with a reactiveValues object that is set to NULL when a new data file is uploaded.

server <- function(input, output, session) {
  croppedd <- reactiveValues(data=NULL)
  # uploaded <- reactiveVal(FALSE)
  # observeEvent(input$uploadbtn, {
  #   uploaded(TRUE)
  # })
  
  # Upload raw data
  raw <- bindEvent(reactive({
    req(input$fname)
    
    # Read in data as zoo object the convert to xts
    read.delim.zoo(file = input$fname$datapath,
                   sep = "\t",
                   skip = 0,
                   header = TRUE,
                   dec = ".",
                   drop = FALSE,
                   FUN = as.POSIXct,
                   tz = "",
                   format = "%Y.%m.%d %H:%M:%S") %>% as.xts
  }), 
  input$uploadbtn # Only upload once button is clicked
  )
  
  # Display raw data
  output$raw_table <- renderDT({
    req(raw())
    datatable(as.data.frame(raw()), options = list(scrollX = TRUE))
  })
  
  # Select beginning and end of dataset
  first_data <- reactive({
    raw() %>% first("1 days") %>% zoo
  })
  
  last_data  <- reactive({
    raw() %>% last("1 days")  %>% zoo
  })
  
  output$crop_box <- renderUI({
    box(
      width = 4,
      h4(strong("Select the start and end time of on-site measurements.")),
      sliderInput("onsite_start", "Start of on-site measurements",
                  min = as.POSIXct(min(index(first_data()))), 
                  max = as.POSIXct(max(index(first_data()))),
                  value = min(index(first_data())),
                  timeFormat = "%F %R"),
      sliderInput("onsite_end", "End of on-site measurements", 
                  min = as.POSIXct(min(index(last_data()))), 
                  max = as.POSIXct(max(index(last_data()))),
                  value = max(index(last_data())))
    )
  })
  
  cropped <- bindEvent(reactive({
    req(raw(), uploaded())
    start_indx <- index(raw()) >= as.POSIXct(input$onsite_start) # Get start
    end_indx   <- index(raw()) <= as.POSIXct(input$onsite_end) # Get end
    raw()[which(start_indx & end_indx), , drop = FALSE]
  }), 
  input$cropbtn # Only compute once button is clicked
  )
  
  observe({
    croppedd$data <- cropped()
  })
  
  output$cropped_table <- renderDT({
    req(cropped())
    # cropped_data <- isolate(cropped())
    # uploaded(FALSE)
    datatable(as.data.frame(croppedd$data))
  })
  
  observeEvent(input$uploadbtn, {
    croppedd$data <- NULL
    # updateSliderInput(session = session, "first", value = 1)
    # updateSliderInput(session = session, "last", value = 1)
    updateSliderInput(session = session, "onsite_start", value = as.POSIXct(min(index(first_data()))))
    updateSliderInput(session = session, "onsite_end", value = as.POSIXct(max(index(last_data()))))
  })
}
  • Related