Functional programming around leaflet with NSE

The plotly leaflet R package was created a little before rlang, and has its own non-standard evaluation (NSE) system, that as far as I can tell is mostly only documented in the examples. It's pretty temperamental, too—passing it a variable with the correct formula ~pal(BIR74) fails.

When NSE systems go sideways, the quickest way to get it to work is to rewrite all the code dynamically and then evaluate it. Here, wrap the whole plotly pipeline in quo with !! substitution wherever you like, then call quo_squash on it to collapse it to a single expression (instead of nested quosures), and then call eval_tidy on the whole lot to actually run it:

library(sf)
library(leaflet)
library(tidyverse)

nc <- st_read(system.file("shape/nc.shp", package="sf"))

plot_leaf_columns <- function(df, variable) {
    v <- enquo(variable)
    pal <- colorFactor(palette = "plasma", domain = pull(df, !!v) )
    
    rlang::eval_tidy(rlang::quo_squash(quo({
        df %>% 
            leaflet(width = "100%") %>% 
            addPolygons(color = ~pal(!!v))
    })))
}

plot_leaf_columns(nc, BIR74)
#> Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD27 +no_defs).
#> Need '+proj=longlat +datum=WGS84'

This is sort of a nuclear option, though; there's likely a simpler alternative if the leaflet NSE system is documented somewhere (beyond this). Really the leaflet interface should get updated to use rlang, but it'd be hard to do without breaking a lot of existing code.

5 Likes