0

Goal: I would like for the user to upload their own data frame, specify the columns in their data frame that provide "Name", "Longitude", and "Latitude" data, then create a table using DataTable (DT package).

Issue: The data frame appears on the render table after the user makes the selections, but when they attempt to sort each column or interact with the data, or even change a selection for "Name", "Longitude", or "Latitude", the following error message appears on the console:

ERROR: [on_request_read] parse error

Here's my code for the ui and server pages I have (note: I am using dashboardPage for layout):

Reproducible Example

ui <- dashboardPage(

  dashboardHeader(title = "Test") , 

  dashboardSidebar(
    sidebarMenu(
      menuItem("Selections", tabName = "selections"),
      menuItem("Data Table", tabName = "dataTable")
    )
  ),

  dashboardBody(
    tabItems(
      tabItem(
        tabName = "selections",
        selectInput("mapChoice", 
                    label = "Choose a map:", 
                    choices = c("", 
                                "New Map from Data Table"),
                    selected = ""),

        conditionalPanel("input.mapChoice == 'New Map from Data Table'",
          fileInput("userData",
                    label = "Choose CSV File", 
                    accept=c('text/csv', 
                             'text/comma-separated-values,text/plain', 
                             '.csv')),               

          uiOutput("newMapUI")
        ), 
        ###############################################
        # Bookmark widget
        shinyURL.ui(width = "400px")
        ###############################################
      ), 

      tabItem(
        tabName = "dataTable",
        DT::dataTableOutput("table")
      )
    )
  )


  )


server <- function(input, output, session) {
  ############################################################
  # Add in function for saving and recording urls as bookmarks
  shinyURL.server(session)
  ############################################################

  userData <- reactive({

    path <- input$userData

    if (is.null(path))
      return (NULL)

    results <- read.csv(file = path$datapath, 
                        header = TRUE, 
                        stringsAsFactors = FALSE)
    results

  })

  output$newMapUI <- renderUI({


    list(

      # Specify the column for labeling
      if (!is.null(userData())) {
        selectizeInput("nameCol", 
                       label = "Choose the column to be used for
                       point labels: ", 
                       choices = c(names(userData())),
                       multiple = TRUE,
                       options = list(placeholder = 'Name', 
                                      maxItems = 1))
      }, 

      # Specify longitude column
      if (!is.null(userData())) {
        selectizeInput("lonCol", 
                       label = "Choose the column containing longitude
                       values: ", 
                       choices = c(names(userData())),
                       multiple = TRUE,
                       options = list(placeholder = 'Longitude', 
                                      maxItems = 1))
      }, 
      # Specify latitude column
      if (!is.null(userData())) {
        selectizeInput("latCol", 
                       label = "Choose the column conatining latitude
                       values: ", 
                       choices = c(names(userData())),
                       multiple = TRUE,
                       options = list(placeholder = 'Latitude', 
                                      maxItems = 1))
      }

    )



  })

  nameCol <- reactive({
    as.character(input$nameCol)
  })

  lonCol <- reactive({
    as.character(input$lonCol)
  })

  latCol <- reactive({
    as.character(input$latCol)
  })



  newUserData <- reactive({

    if (is.null(userData())) 
      return (NULL)

    # Create the new data frame:
    if (length(nameCol()) != 0 &&
        length(lonCol()) != 0 &&
        length(latCol()) != 0) {

      userData <- userData()

      name <- nameCol()
      lonCol <- lonCol()
      latCol <- latCol()

      results <- data.frame(Name = userData[, name], 
                            Longitude = userData[, lonCol], 
                            Latitude = userData[, latCol])

      results$Name <- as.character(results$Name)
      results$Longitude <- as.numeric(results$Longitude)
      results$Latitude <- as.numeric(results$Latitude)

    }

    results

  })

  mapData <- reactive({

    data <- data.frame()

    if (input$mapChoice == "New Map from Data Table") {

      if (length(nameCol()) != 0 &&
          length(lonCol()) != 0 &&
          length(latCol() != 0)) {
        data <- newUserData()
      }
    }
      data
    })

  output$table <- DT::renderDataTable({

    datatable(mapData(), 
              extensions = c('Buttons', 'FixedHeader', 'Scroller'), 
              options = list(dom = 'Bfrtip', 
                             buttons = list('copy', 'print', 
                                            list(extend = 'csv', 
                                                 filename = 'map data', 
                                                 text = 'Download') 
                             ), 
                             scrollX = TRUE, 
                             pageLength = nrow(mapData()), 
                             fixedHeader = TRUE, 
                             deferRender = FALSE, 
                             scrollY = 400, 
                             scroller = FALSE, 
                             autowidth = TRUE
              )
    )

  }
  ) # End of table render

  }

shinyApp(ui = ui, server = server)

Note: If I attempted to use this data for a plot, that will also not work. (Plotting the points on a map is my end goal).

Update1: For some dumb reason, this snippet app runs perfectly fine as expected, yet these lines of code are directly from my application. I will continue to update as more things occur.

Update2: After heavy searching and debugging, I finally caught the source of the error message via help of the js provided by the browser while running the app. The error is trying to use shinyURL in combination with DT and fileInput. My guess is that shinyURL is attempting to save a url, which is entirely too long for the browser, and which provides info that the user gave. In other words, it might be trying to save the fileInput data with the url info..? I'm adding the shinyURL function to the example above, so that it will provide the exact same error message I was stuck on. I don't need a solution immediately, but I am curious about what's really happening. (Lines that produce error are highlighted with ### above and below.

creutzml
  • 404
  • 5
  • 14
  • Can you make a smaller [reproducible example](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example)? For instance, is the `fileInput` relevant to this discussion, or will any dataset work for testing (and please choose one)? It would be helpful if this were something I can copy/paste into a single file (such as using `shinyApp`). Lastly, please include explicit code to include non-base packages you are using (i.e., `library(shiny)`, `library(shinydashboard)`). – r2evans Aug 18 '16 at 20:02
  • Yes. My apologies. I had struggled with providing the right level of detail, because this is one small snippet of an application that involves over 4000 lines of code. The file input is what seems to be the root of the issue. (I'll post reproducible example above) Displaying a data frame given in the 'Shiny App/data' gives no errors. – creutzml Aug 18 '16 at 20:13
  • Good to know, thanks. Have you tried putting `browser()` in each of your (large) `reactive` blocks to see where exactly the problem is? (BTW: you might be able to use `validate(need(! is.null(userData()), FALSE))` and preclude your tests of `is.null(...)` multiple times. See `?validate` for more info.) – r2evans Aug 18 '16 at 20:17
  • I'm actually not familiar with `browser()`, so I will have to take some time to investigate that. Also, thanks for the tip! – creutzml Aug 18 '16 at 20:48
  • Ooh ooh ooh, it's not hard and it is (in my opinion) a *fundamental* debugging utility. "R Gurus" know how to use other functions -- often lower-level -- but this is quick and relatively easy once you get the hang of it. Perhaps check out a recent [article at RStudio](https://support.rstudio.com/hc/en-us/articles/205612627-Debugging-with-RStudio), even if you aren't using RStudio it might be helpful. – r2evans Aug 18 '16 at 20:52
  • Alrighty, I will get back you on it some time tomorrow. Currently banging my head against the wall! You can imagine my disbelief when I created a reproducible example only to find that it worked as expected in the example but not in the real app. – creutzml Aug 18 '16 at 21:21
  • Soooo many questions I've started, hit exactly what you did, and found the culprit. (And the posted went unposted.) Though it's arduous, going from the now-functional reproducible example, add bit-by-bit of more functionality, and you'll find the problem area. Similar to doctoral dissertations (which I don't have ... yet?), it's as much the *process* as it is the actual *knowledge*. – r2evans Aug 18 '16 at 21:24
  • Sorry, are you saying you have found a solution to the error? Or were you just able to add things and then reproduce the error? And now you are suggesting that I should keeping adding bit by bit until I find the section that triggers the error? ... – creutzml Aug 18 '16 at 21:39
  • No, I was commiserating. I was saying that I've done that with questions of my own. – r2evans Aug 18 '16 at 21:42
  • OooOOoo. I understand now. Hopefully I find my solution soon! – creutzml Aug 18 '16 at 21:43
  • @r2evans ... See above for the second update. I found the lines of code tripping the error: shinyURL functions. So I pasted the new code, which trips the exact error message. Let me know what you think and how I could work around this/solve the issue. THANKS! – creutzml Aug 19 '16 at 12:45

1 Answers1

1

Solution

The issue was expected in my latest update, the combination of the user uploaded file and the interaction of the data frame in DT caused the URL generate by shinyURL to be entirely too long.

To find a work around that allows shinyURL to still be in the application, I did some investigating and discovered that DT output creates its own input objects such as input$tableId_rows_current, which tried to save all of the indices of the table every time the user interacted with. So, as soon as the data frame was too large, any interaction with it would pass a url query error, which showed up on the console in R Studio as ERROR [on_request_read] parse error.

Luckily, shinyURL also has an inherent way of ignoring user selected inputs. How? Just simply place a "." at the beginning of the input ID when creating new widgets. Or, in the case of DT table output, place a period at the beginning of your data table output ID, so that all of the inherent DT inputs are ignored.

Code Solution:

ui <- dashboardPage(

  dashboardHeader(title = "Test") , 

  dashboardSidebar(
    sidebarMenu(
      menuItem("Selections", tabName = "selections"),
      menuItem("Data Table", tabName = "dataTable")
    )
  ),

  dashboardBody(
    tabItems(
      tabItem(
        tabName = "selections",
        selectInput("mapChoice", 
                    label = "Choose a map:", 
                    choices = c("", 
                                "New Map from Data Table"),
                    selected = ""),

        conditionalPanel("input.mapChoice == 'New Map from Data Table'",
#########################################################
# Add in a period before file input ID
#########################################################
          fileInput(".userData",
                    label = "Choose CSV File", 
                    accept=c('text/csv', 
                             'text/comma-separated-values,text/plain', 
                             '.csv')),               

          uiOutput("newMapUI")
        ), 
        # # Bookmark widget
        shinyURL.ui(width = "400px")
      ), 

      tabItem(
        tabName = "dataTable",
########################################################
# Add in a period before data table output ID
########################################################
        DT::dataTableOutput(".table")
      )
    )
  )


  )


server <- function(input, output, session) {

  # # Add in function for saving and recording urls as bookmarks
  shinyURL.server(session)

  userData <- reactive({

    path <- input$.userData

    if (is.null(path))
      return (NULL)

    results <- read.csv(file = path$datapath, 
                        header = TRUE, 
                        stringsAsFactors = FALSE)
    results

  })

  output$newMapUI <- renderUI({


    list(

      # Specify the column for labeling
      if (!is.null(userData())) {
        selectizeInput("nameCol", 
                       label = "Choose the column to be used for
                       point labels: ", 
                       choices = c(names(userData())),
                       multiple = TRUE,
                       options = list(placeholder = 'Name', 
                                      maxItems = 1))
      }, 

      # Specify longitude column
      if (!is.null(userData())) {
        selectizeInput("lonCol", 
                       label = "Choose the column containing longitude
                       values: ", 
                       choices = c(names(userData())),
                       multiple = TRUE,
                       options = list(placeholder = 'Longitude', 
                                      maxItems = 1))
      }, 
      # Specify latitude column
      if (!is.null(userData())) {
        selectizeInput("latCol", 
                       label = "Choose the column conatining latitude
                       values: ", 
                       choices = c(names(userData())),
                       multiple = TRUE,
                       options = list(placeholder = 'Latitude', 
                                      maxItems = 1))
      }

    )



  })

  nameCol <- reactive({
    as.character(input$nameCol)
  })

  lonCol <- reactive({
    as.character(input$lonCol)
  })

  latCol <- reactive({
    as.character(input$latCol)
  })



  newUserData <- reactive({

    if (is.null(userData())) 
      return (NULL)

    # Create the new data frame:
    if (length(nameCol()) != 0 &&
        length(lonCol()) != 0 &&
        length(latCol()) != 0) {

      userData <- userData()

      name <- nameCol()
      lonCol <- lonCol()
      latCol <- latCol()

      results <- data.frame(Name = userData[, name], 
                            Longitude = userData[, lonCol], 
                            Latitude = userData[, latCol])

      results$Name <- as.character(results$Name)
      results$Longitude <- as.numeric(results$Longitude)
      results$Latitude <- as.numeric(results$Latitude)

    }

    results

  })

  mapData <- reactive({

    data <- data.frame()

    if (input$mapChoice == "New Map from Data Table") {

      if (length(nameCol()) != 0 &&
          length(lonCol()) != 0 &&
          length(latCol() != 0)) {
        data <- newUserData()
      }
    }
      data
    })

  output$.table <- DT::renderDataTable({

    datatable(mapData(), 
              extensions = c('Buttons', 'FixedHeader', 'Scroller'), 
              options = list(dom = 'Bfrtip', 
                             buttons = list('copy', 'print', 
                                            list(extend = 'csv', 
                                                 filename = 'map data', 
                                                 text = 'Download') 
                             ), 
                             scrollX = TRUE, 
                             pageLength = nrow(mapData()), 
                             fixedHeader = TRUE, 
                             deferRender = FALSE, 
                             scrollY = 400, 
                             scroller = FALSE, 
                             autowidth = TRUE
              )
    )

  }
  ) # End of table render

  }

shinyApp(ui = ui, server = server)
creutzml
  • 404
  • 5
  • 14