Shiny, Leaflet crashes with addPolygons on server but not locally

I am trying to build a map with leaflet that includes US Population Density by County 2019 (from the US Census Bureau). The strange thing is that I have no problem running my code locally on MacOS 11.1 but when I deploy this code to a container with CentOS7, it crashes without any good logs (have tried persisting logs, too--nothing useful).

I have isolated the problem to the "addPolygons" block. If I comment this block out, the code deploys/runs on our K8s cluster.

Things I have tried:

  • Switched from using rgdal::readOGR(...) to sf::st_read(...) to read in the shapefile
  • Moving the addPolygons(..) block outside of the renderLeaflet(..) block and into an observer/leafletProxy block.
  • Increasing the K8s resource requests/limits to a ridiculous amount (up to 8Gi and 8 cpu cores)
  • Profiling the code with profvis to see if I have a memory leak (does not appear to be that way although I will admit I am a total R beginner and probably have really inefficient code)
  • Tried rmapshaper::mr_simplify(..) on the shapefile--seems to actually be slower/still doesn't work on server

Any other ideas?

server.R:

library(glue)
library(httr)
library(leaflet)
library(jsonlite)
library(RJSONIO)
library(sf)
library(shiny)

options(stringsAsFactors=FALSE)

county_data_shapefile_path = "./us_counties_cb"
us_counties <- sf::st_read(dsn=path.expand(county_data_shapefile_path))

function(input, output, session) {
  output$map <- renderLeaflet({

      leaflet(us_counties, options=leafletOptions(preferCanvas = TRUE)) %>%
      setView(lng = -117.35, lat = 33.15, zoom = 8)  %>%

      # higher zIndex rendered on top
      addMapPane(name = "maplabels", zIndex = 500) %>%
      addMapPane(name = "pop_density", zIndex = 200) %>%
      addMapPane(name = "basemap", zIndex = 100) %>%

      addProviderTiles("CartoDB.PositronNoLabels",
                       options = leafletOptions(pane = "basemap")) %>%
      addProviderTiles("CartoDB.PositronOnlyLabels",
                       options = leafletOptions(pane = "maplabels")) %>%
      
      ## THIS IS CURRENTLY CRASHING WHEN DEPLOYED TO K8s:
      # addPolygons(
      #   stroke       = FALSE,
      #   smoothFactor = 0.3,
      #   fillOpacity  = 0.6,
      #   fillColor    = ~pal(log(us_counties$B01001_cal)),
      #   options      = leafletOptions(pane="pop_density"),
      #   group        = "Pop. Density"
      # ) %>%
    
      addLayersControl(
        overlayGroups = c("Pop. Density"),
        options = layersControlOptions(collapsed = FALSE)
      ) %>%
      addLegend(pal = pal, values = ~us_counties$B01001_cal, opacity = 1,
                title = "Pop/sq-km: US Counties")
  })
}

ui.R:

library(DT)
library(leaflet)
library(shinycssloaders)

fluidPage(
  fluidRow(
    column(12,
           withSpinner(leafletOutput(outputId = "map", width = "100%", height = "600px"))
    )
  )
  )

Note: Have removed some parts like some addCircles blocks in renderLeaflet() that appear to be inconsequential to this issue

You seem to have tried most of the same stuff that I would... Since your problem is not easily reproducible I am shooting blind, but what I would do in addition is:

  • consider a different source of the counties shapefile; tigris::counties() is my favorite, and it has added benefit of being easier to reproduce in a code snippet / as you do not rely on a big file to be downloaded
  • US counties are numerous and detailed; a resources issue remains a possibility. I would try deploying a version based on the lower 48 states, just to rule out the resources issue / btw it may be a good idea to check your counties shapefile if it contains any far flung areas / think American Samoa, Puerto Rico or even Alaska; in mapping these are known troublemakers and often need a special approach

@jlacko thank you for the ideas! Going to give the tigris::counties()a try.

@jlacko Thank you again for the ideas. I was able to get it working with tigris::counties() with some tweaks!

Using tigris::counties() also failed to render all US county/equivalent polygons but, when narrowing the scope to just a handful of US states, it worked perfect. Must have been a resource issue after all.

I also like how much easier/cleaner tigris is--it seems to be much more user-friendly in terms of fast-prototyping with regards to control/granularity.

Since this data is relatively static, would be nice to have custom mapTiles or layers that have this information pre-loaded without having to hit tigris/ CB data repo each build. I bet there's a way...that will be my next project ::joy::

1 Like

Glad to be of service!

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.