41

My shiny app allows user to upload a csv by using fileInput and stored as an reactive object df_data. I then created a numericInput for user to enter a row number to delete from the data frame. However, I got an error about evaluation nested too deeply: infinite recursion / options(expressions=)?.

Below is my code for ui.R.

shinyUI(fluidPage(
  titlePanel("amend data frame"),

  mainPanel(
    fileInput("file", "Upload file"),

    numericInput("Delete", "Delete row:", 1, step = 1),
    actionButton("Go", "Delete!"),

    tableOutput("df_data")
  )
))

And below is my code for server.R.

shinyServer(function(input, output) {
  df_data <- reactive({
    read.csv(input$file$datapath)
  })

  df_data <- eventReactive(
    input$Go,
    df_data()[-input$Delete,]
  )

  output$df_data <- renderTable(df_data())
})

I have solved the problem by assigning the subsetted data frame to a new reactive data frame called, say, df_data2. But I want to make the user able to keep deleting different rows by inputting values in Delete row and press the Go button. Then this solution will not work as I will have to assign df_data3, df_data4 ... and I couldn't predict in advance how many times the user will press the Go button.

I am a new user to shiny for about 2 weeks and I have been searching for solutions about this for a week. Is there anyone who can help me? A million thanks !!

Lawrence Lee
  • 668
  • 1
  • 7
  • 8

1 Answers1

78

Below is a working solution. I created a reactiveValues to store the dataframe. When a file is chosen, the dataframe gets populated. When the delete button is pressed, that same dataframe gets a row deleted. The table always outputs whatever that dataframe object is holding. I hope this code can be a good learning material

runApp(shinyApp(
ui=(fluidPage(
  titlePanel("amend data frame"),

  mainPanel(
    fileInput("file", "Upload file"),

    numericInput("Delete", "Delete row:", 1, step = 1),
    actionButton("Go", "Delete!"),

    tableOutput("df_data_out")
  )
)),
server = (function(input, output) {
  values <- reactiveValues(df_data = NULL)

  observeEvent(input$file, {
    values$df_data <- read.csv(input$file$datapath)
  })

  observeEvent(input$Go, {
    temp <- values$df_data[-input$Delete, ]
    values$df_data <- temp

  })

  output$df_data_out <- renderTable(values$df_data)
})))
DeanAttali
  • 25,268
  • 10
  • 92
  • 118
  • Thank you! That works very well! I would like to further ask that why it is necessary to use `observeEvent()` but not `observe()`. What is the difference between the two? Thank you! – Lawrence Lee May 29 '15 at 04:17
  • 6
    You could use regular `observe`. The main difference is that `observeEvent` takes as an argument what reactive to listen to, so any other reactive values inside the expression are by default isolated. Also, it doesn't get fired when the reactive is NULL, which is often what you want when dealing with inputs (otherwise you usually end up with the first line inside an `observe` being `if (is.null(input$xxx)) return()`) – DeanAttali May 29 '15 at 04:54
  • I'm glad you think so :) – DeanAttali May 29 '15 at 08:05
  • 1
    so there isn't a solution that just uses the reactive expression. You need to use reactiveValues – MySchizoBuddy Jun 03 '16 at 18:26
  • Is the solution described still the advised method of doing this? The question and answer are currently a few years old so maybe a confirmation of whether this is still the advised solution would be nice. – Jochem Mar 19 '19 at 11:56
  • 1
    @Jochem, I don't know if that's the best way, but this solution still holds. (august, 2020) – Luis Aug 08 '20 at 03:07