mcharl02
mcharl02

Reputation: 128

Most efficient way to control filtering of points on leaflet map in shiny

I'm developing a shiny app that features a leaflet map. The source dataset for the map includes latitude, longitude, and several other variables. I am giving users of the app radio buttons, sliders, checkboxes, etc. which relate to these other variables with the effect of controlling which points appear on the map.

I am including a basic example of my code below. I am currently pre-splitting my dataset into subsets which can then be called into leaflet via a reactive expression (based on what the user selects). This is just a simple example with only 4 subsets, so it may not seem bad here. However, in my actual use case, the potential combinations of filters that the app-user could select will be much more.

Is it advisable to create ALL the potential sub-datasets that might be filtered to in a Global.R script? Or should filtering be done on the fly within a reactive expression?

Additionally, is there an alternative to using a giant nested ifelse expression (like the relatively small one I have below)? That has been getting out of hand as I add more user filtering options to my actual app. I don't fully understand the order in which a reactive expression is updated, when it could depend on multiple inputs.

The motivation for my question may be clearer if I shared a giant piece of code with all the filtering permutations, but wanted to provide a simpler example first:

    library(shiny)
    library(leaflet)
    library(dplyr)

    # Generating dummy data for demonstration
    member <- 1:10
    lat <- c(39.8, 39.6, 39.7, 39.78, 39.82, 39.74, 39.72, 38.9, 37.43, 38.0)
    lon <- c(-86.1, -86.2, -86.3,-86.4,-86.5,-86.6,-86.7,-86.8,-86.9, -87)
    group <- c("a","a","a","b","b","a","a","a","b","b")
    year <- c(1,0,0,1,0,1,0,0,1,0)
    data <- data.frame(member, lat, lon, group, year)

    # Creating data subsets for plotting
    groupA_y1 <- data %>% filter(group == "a", year == 1)
    groupA_y0 <- data %>% filter(group=="a", year == 0)
    groupB_y1 <- data %>% filter(group=="b", year == 1)
    groupB_y0<-data %>% filter(group=="b", year == 0)


    ui <- fluidPage(
      leafletOutput("mymap"),
      radioButtons("group", "Group:", c("A", "B"), selected = "A"),
      radioButtons("year", "Year", c(1,0), selected = 1)
    )



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

       output$mymap <- renderLeaflet({
         leaflet() %>%
         addProviderTiles("CartoDB.Positron", 
                           options = providerTileOptions(noWrap = TRUE)) %>%
          setView(lng = -85.00, lat = 39.00, zoom = 6)
       })


   zerg <-reactive({
     test<-ifelse(input$group=="A" & input$year==1, return(groupA_y1),
            ifelse(input$group=="A" & input$year==0, return(groupA_y0),
                   ifelse(input$group=="B" & input$year==1, return(groupB_y1),
                          return(groupB_y0))))
     return(test)
   })



  observe({
    dataset<- zerg()

    leafletProxy("mymap", data = dataset) %>%
      clearMarkers() %>%
      addCircleMarkers(~lon, ~lat, layerId=~member,
                       stroke=FALSE, fillOpacity=0.9, fillColor="Red") 

  })
}

shinyApp(ui, server)

Upvotes: 4

Views: 1985

Answers (1)

NicE
NicE

Reputation: 21425

For the filtering, I guess it depends how much time each filtering actually takes. If it only takes a few seconds, it's probably ok for the user to wait. If it takes 20s and you need to wait every time you change a parameter, it could be good to do the filtering at the beginning where you can have a loading sign for a minute or so.

For the ifelse, you could use a dataframe to directly get the dataset you want. For example, using the code you posted, you could do, in the global part:

chooseDataset <- data.frame(group=rep(c("a","b"),each=2),year=rep(c(1,0),2))
chooseDataset$dataset <- paste0("group",toupper(chooseDataset$group),"_y",chooseDataset$year)

and in the observe where you have the leafletProxy:

dataset<- with(chooseDataset,chooseDataset[group==input$group & year=input$year,"dataset"])

Upvotes: 1

Related Questions