Adding Multiple Polygons via Loop in R Shiny Map Using Leaflet

Edit: This was a bit of a simplistic one. Turns out I was just not familiar with the piping construct %>%. This operator simply passes output from one process/function to the next. The whole construct needs to be assigned to a variable in this case the same variable for any changes to persist.
<hr>
48 hours later! So after the pain this has caused me, I decided to try save someone else from agony.

A simple use case. You are displaying a map in shiny. You have multiple layers of which multiple polygon layers need to be interactive. So you create your map, maybe add a base map to it, a mapserver raster tile and your country level polygon like so:
    
map <- leaflet(data=ctryPoly0) %>%
       addTiles %>%
       addPolygons(layerId = "adm0", 
       fill = FALSE,
       stroke = TRUE,
       weight=3,
       smoothFactor = 0.7,
       opacity = 1,
       color="green")

A sample would look like this:




That prints a nice looking country map. But now comes the good part. You want to add a series of sub-national administrative levels so you try a simple loop over them like this:


        for (iterAdmLevel in 1:lyrNum)
        {
          ctryPoly <- readOGR(getPolyFnamePath(countries),
 getCtryShpLyrName(countries, iterAdmLevel))
         
          ctryPoly <- spTransform(ctryPoly, wgs84)
         
          for (iterPoly in 1:nrow(ctryPoly@data))
          {
            if (iterPoly %in% selected)
            {
              map %>% addPolygons(data = ctryPoly[iterPoly,], 
              layerId = as.character(ctryPoly@data[iterPoly,paste0('NAME_',iterAdmLevel)]),
              fill = FALSE, stroke = TRUE,
              weight=iterAdmLevel+1,
              smoothFactor = 0.7, opacity = 1,
              color="green")
            }
          }
        }
 Seems legit right? Until you get the very same country-level output for the map. Interestingly, debugging this code by running each loop manually seems to work. Note we are adding polygon 1 in the shapefile manually:
 map %>% addPolygons(data = ctryPoly[1,],
 layerId = as.character(ctryPoly@data[1,paste0('NAME_',1)]),
 fill = FALSE, stroke = TRUE, weight=1+1,
 smoothFactor = 0.7, 
 opacity = 1, 
 color="green") 
 

At least the first time around. Until, you try to print the whole map and get the initial country-level map.



What is going on? It seems the map is displaying but not storing the new polygons that we are adding. So it turns out that different from all the code samples I have seen, you must assign the map with the added polygon back into the map variable like so:

 map <- map %>% addPolygons(data = ctryPoly[1,],
 layerId = as.character(ctryPoly@data[1,paste0('NAME_',1)]),
 fill = FALSE, stroke = TRUE, weight=1+1,
 smoothFactor = 0.7, 
 opacity = 1, 
 color="green") 

A small change, but it makes all the difference. So the final code to incorporate the additional polygon layers would be:

       
        for (iterAdmLevel in 1:lyrNum)
        {
          ctryPoly <- readOGR(getPolyFnamePath(countries),
 getCtryShpLyrName(countries, iterAdmLevel))
         
          ctryPoly <- spTransform(ctryPoly, wgs84)
         
          for (iterPoly in 1:nrow(ctryPoly@data))
          {
            if (iterPoly %in% selected)
            {
              map <- map %>% addPolygons(data = ctryPoly[iterPoly,], 
              layerId = as.character(ctryPoly@data[iterPoly,paste0('NAME_',iterAdmLevel)]),
              fill = FALSE, stroke = TRUE,
              weight=iterAdmLevel+1,
              smoothFactor = 0.7, opacity = 1,
              color="green")
            }
          }
        }

Finally, the end product as desired:
 

I am yet to find any instructions or code examples that show this construct. Instead I assumed that the

map %>% addpolygons(...)
 
construct permanently added my polygons to the map. Hope this saves somebody some agony :)

Comments