0

since many days I can't solve my problem. At the beginning I get some data from API (I refresh API call every 5 sec to get the newest data). The data contain information about locations (lat and long) and some labels written to those locations. I want to create an object of selectInput and use choices assigned to labels. If I choose a label from a drop-down list in the selectInput object I want to filter simultaneously the next API call within 5 seconds. The main task is to filter the data visible on the map after choosing a value from the drop-down list.

Labels change every few minutes, but the location coordinates change every few seconds.

I'm using renderUI on server side and uiOutput on UI side. Looking forward for some help, thanks.

library("httr")
library("jsonlite")
library("shiny")
library("leaflet")
library("dplyr")


ui <- shinyUI(fluidPage(
  navbarPage("Title",
             tabPanel("MAP",

                      leafletOutput("mymap", width = "auto", height = "560px")
             )
  ),
  uiOutput("loc")
  )
  )

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

  autoInvalidate <- reactiveTimer(5000)

  reData <- eventReactive(autoInvalidate(), {

    # # example data
    # lat <- c(20.51,20.52,20.65)
    # long <- c(10.33,13.43,23.54)
    # labels <- c('John','Peter','Jolie')
    # data <- data.frame(lat, long, labels)

    # API call #1 response
    get_data <- GET(call1)
    get_data_text <- content(get_data, "text")
    get_data_json <- fromJSON(get_data_text, flatten = TRUE)
    data <- get_data_json$result

    # handling empty API response
    while(class(data) == "list"){
      Sys.sleep(1)
      get_trams <- GET(call1)
      get_data_text <- content(get_data, "text")
      get_data_json <- fromJSON(get_data_text, flatten = TRUE)
      data <- get_data_json$result
    }


    # saving data before filtering - purpose of getting labels for the drop-down list and
    # creating a sorted list for selectInput function
    list_of_vals <- data
    uniq_first_lines <- c("all", unique(as.character(sort(as.numeric(list_of_vals$FirstLine)))))
    sorted_factor <- factor(uniq_first_lines, levels=uniq_first_lines)
    my_new_list <- split(uniq_first_lines, sorted_factor)


    # filter data
    if(input$loc != "all") {
      data <- data %>%
      filter_at(
        vars(one_of("FirstLine")),
        any_vars(.==input$loc))
    }

    rownames(data) <- NULL


    return(list(data=data, my_new_list=my_new_list))
  }, ignoreNULL = FALSE)


  output$loc <-renderUI({
    selectInput("loc", label = h4("Choose location"),
                choices = reData()$my_new_list ,selected = "all"
    )
  })


  points <- eventReactive(autoInvalidate(), {
    cbind(reData()$trams_data$Lon, reData()$trams_data$Lat)
  },ignoreNULL = FALSE)

  labels <- eventReactive(autoInvalidate(), {
    paste("line: ", reData()$trams_data$FirstLine)
  },ignoreNULL = FALSE)

  output$mymap <- renderLeaflet({
    leaflet() %>%
      addTiles()
  })

  observeEvent(autoInvalidate(), {
    leafletProxy("mymap") %>%
      clearMarkers() %>%
      addMarkers(
        data = points(),
        label = labels()
      )
  },ignoreNULL = FALSE)
})


shinyApp(ui, server)
boplight
  • 93
  • 2
  • 8
  • Hum...I am not sure I understand. Why not simply put your `reactiveTimer(5000)` in a `reactive` dataset and also include your `selectInput()` argument? Also, your example is not reproducible. – MLavoie Aug 03 '18 at 21:29
  • @MLavoie You mean reactive dataset as the eventReactive function? I don't get it, where I should put that selectInput() argument. I understand reactives till some point, but here I have no idea what to do. up: I have added some example data structure, that's all what I can provide. – boplight Aug 03 '18 at 22:35

1 Answers1

0

I am going with a minimal example and with the small dataset you provided. You can adapt my example for your needs but I want to show you the use of a reactive dataset so you can filter by labels.

Are you looking for something like that:

library("httr")
library("jsonlite")
library("shiny")
library("leaflet")
library("dplyr")


# # example data
lat <- c(20.51,20.52,20.65)
long <- c(10.33,13.43,23.54)
labels <- c('John','Peter','Jolie')
data <- data.frame(lat, long, labels)


ui <- shinyUI(fluidPage(
  navbarPage("Title",
             tabPanel("MAP",
                      leafletOutput("mymap", width = "auto", height = "560px")
             )
  ),
  uiOutput("labels")
)
)

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


  output$labels <- renderUI({
       selectInput("labels", label = h4("Choose label"), choices = c("John", "Peter", "Jolie") ,selected = "John")

  })


  reData <- reactive({

    autoInvalidate <- reactiveTimer(5000)
    data <- data %>% dplyr::filter(input$labels == labels)

  })

  output$mymap <- renderLeaflet({
    leaflet(reData()) %>%
      setView(10, 20, zoom = 5) %>%
      addTiles() %>%
    addMarkers()
  })

#  observeEvent(autoInvalidate(), {
 #   leafletProxy("mymap") %>%
  #    clearMarkers() %>%
   #   addMarkers(
    #    data = points(),
     #   label = labels()
    #  )
#  },ignoreNULL = FALSE)


})


shinyApp(ui, server)
MLavoie
  • 9,671
  • 41
  • 36
  • 56
  • Thank you very much for your help. I have refactored the code using your idea and now it perfectly works as I wanted. Actually the main problem was in that API response, I was not sure if I should have placed the whole API data part outside the server function. Fortunately now I know how should I use reactive dataset. – boplight Aug 04 '18 at 15:26
  • Could you accept my answer? It would be appreciated :-) – MLavoie Aug 04 '18 at 21:12