Search code examples
rggplot2geospatialr-leaflet

Make smooth contours in when using leaflet and tmaps in R


I am using the script below to make to make interactive leaflet map. However, the contours have sharp changes and are not smooth and round. How can I edit this code to achieve that?

The data and code is from this link: https://adelieresources.com/2022/10/making-contour-maps-in-r/

    Sta_den <- eks::st_kde(df) # calculate density
    contours <- eks::st_get_contour(Sta_den, cont=c(20,40,60,80)) %>% 
      mutate(value=as.numeric(levels(contlabel)))
    pal <- colorBin("YlOrRd", contours$contlabel, bins = c(20,40,60,80), reverse = TRUE)
    
    pal_fun <- leaflet::colorQuantile("YlOrRd", NULL, n = 4)
    
    p_popup <- paste("Density", as.numeric(levels(contours$contlabel)), "%")
    
    leaflet::leaflet(contours) %>% 
      leaflet::addTiles() %>% # OpenStreetMap by default
      leaflet::addPolygons(fillColor = ~pal_fun(as.numeric(contlabel)),
                           popup = p_popup, weight=2)%>% 
      leaflet::addLegend(pal = pal, values = ~contlabel, group = "circles", position = "bottomleft",title="Density quantile")

Solution

  • The problem seems to be that you have a lower-than-desired resolution of 2D density. This can be controlled with the gridsize argument of eks::st_kde.

    For example, if we only calculate density over a 10 by 10 grid, the contours look horribly jagged:

    Sta_den <- eks::st_kde(df, gridsize = c(10, 10))
    

    enter image description here

    If we set the grid to be 500 x 500, then the calculation takes a lot longer, but the end result is perfect:

    Sta_den <- eks::st_kde(df, gridsize = c(500, 500))
    

    enter image description here

    The default value is somewhere in between.

    Other things you can try is reducing smoothFactor inside leaflet::addPolygons, and actually smoothing the contour lines themselves using smoothr::smooth

    Sta_den <- eks::st_kde(df, gridsize = c(100, 100))
    contours <- eks::st_get_contour(Sta_den, cont = c(20,40,60,80)) %>% 
      mutate(value=as.numeric(levels(contlabel)))
    pal <- colorBin("YlOrRd", contours$contlabel, bins = c(20,40,60,80), 
                    reverse = TRUE)
    
    pal_fun <- leaflet::colorQuantile("YlOrRd", NULL, n = 4)
    
    p_popup <- paste("Density", as.numeric(levels(contours$contlabel)), "%")
    
    leaflet::leaflet(smoothr::smooth(contours)) %>% 
      leaflet::addTiles() %>% # OpenStreetMap by default
      leaflet::addPolygons(fillColor = ~pal_fun(as.numeric(contlabel)),
                           popup = p_popup, weight=2, smoothFactor = 0.5) %>% 
      leaflet::addLegend(pal = pal, values = ~contlabel, group = "circles", 
                         position = "bottomleft",title="Density quantile")
    

    enter image description here