0

I have been going through most of the Q&As related to dataframe manipulation within Shiny and I still don't understand how to do something which, in my mind, should be very simple. I don't have experience writing Shiny apps and I'm still struggling with concepts like reactive events.

I have a dataframe A, loaded into R. I want to be able to see a specific value in a specific column in the dataframe in the UI and then edit it. After I edit the dataframe, I want to close the Shiny app and then see the edited dataframe in the Environment tab of RStudio. How do I go about doing this?

suraju123
  • 3
  • 2

1 Answers1

2

I think this might be a workable example.

Assume df is your data frame (I used iris to test, commented out below). Create a reactiveVal to hold your data, and use for editing with datatable. After editing, you can store the data back into your global environment dataframe df with <<-. An alternative is to do this when exiting the shiny app (such as through the onStop or session$onSessionEnded method).

library(shiny)
library(DT)

#df <- iris

ui <- fluidPage(
  DT::dataTableOutput('data'),
)

server <- function(input, output) {
  
  rv <- reactiveVal(df)
  
  output$data <- DT::renderDataTable ({
    DT::datatable(rv(), editable = TRUE)
  })
  
  observeEvent(input$data_cell_edit, {
    info <- input$data_cell_edit
    newdf <- rv()
    newdf[info$row, info$col] <- info$value
    rv(newdf)
    df <<- rv()
  })
  
}

shinyApp(ui = ui, server = server)

Alternative with replacing global df on exiting (requires session):

server <- function(input, output, session) {
  
  rv <- reactiveVal(df)
  
  output$data <- DT::renderDataTable ({
    DT::datatable(rv(), editable = TRUE)
  })
  
  observeEvent(input$data_cell_edit, {
    info <- input$data_cell_edit
    newdf <- rv()
    newdf[info$row, info$col] <- info$value
    rv(newdf)
  })
  
  session$onSessionEnded(function() {
    df <<- isolate(rv())
  })
  
}

If you don't want to use reactive values, I suppose you could try the following. This can update your data.frame in the global environment as edits are made. Note that server = FALSE is added to handle changes in pages:

server <- function(input, output) {
  
  output$data <- DT::renderDT (df, editable = TRUE, server = FALSE)
  
  observeEvent(input$data_cell_edit, {
    info <- input$data_cell_edit
    df[info$row, info$col] <<- info$value
  })

}
Ben
  • 28,684
  • 5
  • 23
  • 45
  • Thank you for this very informative answer! I had one more question: why do I need to use reactiveVal? Is it because the Shiny server doesn't contain a mutable dataframe otherwise? – suraju123 Dec 30 '20 at 10:01
  • I usually am using reactive values to handle interactivity with inputs, etc. for other apps. I suppose you could do something else if you wanted to without `reactiveVal` (see my edited answer, last example). If you use `server = FALSE` you can make changes to your data frame in the global environment without reactive values, I believe this could work as well. – Ben Dec 30 '20 at 15:31