R Shiny – Conditionally Adding Markers to Map in R Leaflet and Shiny

leaflet-rrshiny

I am trying to add some markers to a leaflet map in R based on conditions that I select from an selectInput command. The selectInput command lets the user choose three different numbers (1, 2 or 4). Based on this number the respective marker should be added to the leaflet map. In the end I am attempting to only add one marker based on the selected number of selectInput.

My problem: I am trying to use ifelse() statements, but I get an error that the argument could not be interpreted as a logical condition. I am assuming that this might be linked to the piping of my leaflet command? My code with some sample data is below.

library(shiny)

# create some sample data containing lat/lon coordinates
data1 <- as.data.frame(cbind(c(46.5728, 46.5729, 46.5730, 46.5731),c(6.9385,6.9386,6.9387, 6.9388)))
colnames(data1) <- c("Lat", "Lon")
data2 <- as.data.frame(cbind(c(46.4728, 46.4729, 46.4730, 46.4731),c(6.8385,6.8386,6.8387, 6.8388)))
colnames(data2) <- c("Lat", "Lon")
data4 <- as.data.frame(cbind(c(46.3728, 46.3729, 46.3730, 46.3731),c(6.7385,6.7386,6.7387, 6.7388)))
colnames(data2) <- c("Lat", "Lon")

ui <- fluidPage(
  tabsetPanel(tabPanel("TEST PANEL",
                       fluidRow(leafletOutput("Map", height = 500),
                       wellPanel(fluidRow(selectInput("Number", "Select number:", c(1,2,4))))))))

server <- function(input,output, session){
  output$Map <- renderLeaflet({
    m <- leaflet() %>%
      addProviderTiles('Esri.WorldImagery', options = providerTileOptions(maxNativeZoom=19,maxZoom=100)) %>% 
      if(input$map == "1"){
        addCircleMarkers(data = data1, 
                       lat =  data1$Lat, 
                       lng =  data1$Lon, 
                       radius = 4, col = rgb(215,48,39, max = 255))
      }
      if(input$map == "2"){
      addCircleMarkers(data = data2, 
                       lat =  data2$Lat, 
                       lng =  data2$Lon, 
                       radius = 4, col = rgb(233,25,78, max = 255))
      }
      if(input$map == "4"){
      addCircleMarkers(data = data4, 
                       lat =  data4$Lat, 
                       lng =  data4$Lon, 
                       radius = 4, col = rgb(23,25,78, max = 255))
      }
      addScaleBar(position = "bottomleft", options = scaleBarOptions()) %>%
      leaflet::addLegend("topright", 
                         colors =c(rgb(215,48,39, max = 255),  rgb(233,25,78, max = 255), rgb(23,25,78, max = 255)),
                         labels= c("No 1", "No 2","No 4"),
                         title= "Number",
                         opacity = 1) %>%
      addMeasure(primaryLengthUnit = "meters", decPoint = ".")
    m
  })
}

shinyApp(ui, server)

Best Answer

Are you trying to put if statements into a magritrr piping chain? A little experiment will show this does not work:

> z = 1
> 2 %>% sqrt() %>% if(z==1){log()} %>% if(z==2){sqrt()} %>% sqrt
[1] TRUE

You can't put logic like that in magrittr pipe chains, so take it outside.

In your case, put something like this outside the leaflet pipe:

  if(input$map == "1"){
     mapdata = data1
     mapcol = rgb(215,48,39, max = 255)
  }
  if(input$map == "2"){
     mapdata = data2
     mapcol = rgb(....blah)
  }
  etc etc

Then in your pipe its:

    leaflet... %>% 
    addCircleMarkers(data = mapdata, 
                   lat =  mapdata$Lat, 
                   lng =  mapdata$Lon, 
                   radius = 4, col = mapcol) %>%

Some further investigation shows you can put if in a pipe if you wrap it in cotton-wool:

> 2 %>% (if(z==1){log}else{sqrt})
[1] 0.6931472

but just because you can doesn't mean you should. Keep logic out of pipes.

Another way of doing this is to build the piped object gradually. Something like:

 # start
 m = leaflet()
 # conditional bits
 if(a==1){
    m = m %>% foo()
 }
 if(a==2){
    m = m %>% bar()
 }
 # bits at the end
 m = m %>% baz()

 m # is now my pipe result