The question is probably not too hard, but I couldn't find the words to properly google it.
I'm building a function in R that makes a leaflet map. The user will be able to chose the field he wants to use for colors in the form of a simple function argument field_color = "AREA"
where AREA
is the field name in the sf
object.
Here is a reproducible example:
library(sf)
library(leaflet)
# preparing the shapefile
nc <- st_read(system.file("gpkg/nc.gpkg", package="sf"), quiet = TRUE) %>%
st_transform(st_crs(4326)) %>%
st_cast('POLYGON')
# setting the colors
colpal <- colorNumeric(palette = "plasma", domain=nc$AREA, n=10)
# making the first map like in your example:
leaflet(nc) %>%
addTiles() %>%
addPolygons(color = ~colpal(AREA))
This code works and gives :
But in the preceding example, AREA
is unquote. If I want it an argument, I need to call it that way:
chosen_field = "AREA"
# setting the colors
colpal2 <- colorNumeric(palette = "plasma", domain=nc[[chosen_field]], n=10)
# making the first map like in your example:
leaflet(nc) %>%
addTiles() %>%
addPolygons(color = ~colpal2(chosen_field))
Error in UseMethod("rescale") :
no applicable method for 'rescale' applied to an object of class "character"
That way, I could set chosen_field
to the value I want to automatically change the color. However, it's not working and I get an error. I have a feeling it's some king of problem with Non Standard Evaluation or something but I don't really understand all of that. I played around function like quo
, enquo
, quo_name
etc. without success.
What is the proper way to make that work?
Honestly, I'd suggest just sidestepping the issue by "pre-computing" your color data outside of the pipe, just as you've already pre-computed your color palette. That may feel inelegant, but then I'd argue that the convolutions magrittr et al. are forcing you into here are at least as awkward. Additionally, the approach I'm suggesting is exactly that used by the "pros" here in their production of this example leaflet app.
Specifically, I'd use something like this:
library(sf)
library(leaflet)
## User-selected parameter
chosen_field <- "AREA"
## Shapefile preparation
nc <- st_read(system.file("gpkg/nc.gpkg", package="sf"), quiet = TRUE) %>%
st_transform(st_crs(4326)) %>%
st_cast('POLYGON')
## Color setup
colpal <- colorNumeric(palette = "plasma", domain=nc[[chosen_field]], n=10)
colorData <- nc[[chosen_field]]
## Putting it all together
leaflet(nc) %>%
addTiles() %>%
addPolygons(color = ~colpal(colorData))
Alternatively, if you must do it the "rlang way", here is another solution, modeled off of the discussion recorded here. See how much more unreadable this is, though?
library(sf)
library(leaflet)
## User-selected parameter
chosen_field <- "AREA"
## Prep user-selected parameter for passage into pipe
v <- as.symbol(chosen_field)
v <- enquo(v)
## Shapefile preparation
nc <- st_read(system.file("gpkg/nc.gpkg", package="sf"), quiet = TRUE) %>%
st_transform(st_crs(4326)) %>%
st_cast('POLYGON')
## Color setup
colpal <- colorNumeric(palette = "plasma", domain=nc[[chosen_field]], n=10)
colorData <- nc[[chosen_field]]
## Putting it all together
rlang::eval_tidy(rlang::quo_squash(quo({
leaflet(nc) %>%
addTiles() %>%
addPolygons(color = ~colpal(!!v))
})))