Leaflet in R - How to color sites from parameters that may contain a list?

Is there a way to color a site on a leaflet addCircleMarkers() map based on values from a list / the first value from a list / look for a specific value from a list? etc etc

This is an example of data structure I'm working with, where we may encounter a site with duel purposes, and I've been trying to develop a method to show it on a map within R. Ideally, we don't want to change the data structure and this is a very watered down sample (e.g., can't add a value of "farm, house" = "green").

This sample code used the colorfactor from leaflet to assign predetermined colors based on a value. On the 3rd case in this sample data, I need that 3rd sit to either turn "blue" for farm, or "red for house (depends on the kind of filter I'll develop later on to search for sites with specific values).

###################################################################################
###################################################################################
# Libraries
library(dplyr) 
library(leaflet)

###################################################################################
###################################################################################
# InputData & Functions
Map_DF <- data.frame("Point_ID" = 1:3,
                     "Latitude" = c(38.10, 38.20, 38.30),
                     "Longitude" = c(-107.10, -107.20, -107.30),
                     "PointUse" = c("farm", "house", "farm, house"))

PointUsePalette <- colorFactor(palette = c("blue", "red"),
                               domain = c("farm", "house"))

###################################################################################
###################################################################################
# Leaflet Map
leaflet() %>% 
  addProviderTiles(
    providers$CartoDB.Positron
    ) %>%
  setView(
    lng = -107.20, 
    lat = 38.20, 
    zoom = 11
    ) %>%
  addCircleMarkers(
    data = Map_DF,
    lat = ~Latitude,
    lng = ~Longitude,
    radius = 5,
    color = ~PointUsePalette(PointUse),
    popup = ~PointUse
  )
  

The leaflet circle markers can have only a single color; not a combination of two or more.

This translates to a need to create a some sort of mapping between your values and colors values; examples of mapping include:

  • farm = red, house = blue, farm + house = purple (a special value, a mix of the two)
  • farm = red, house = blue, farm + house = blue (because house trumps farm; or vice versa)
  • primary color in one base group, and secondary in the other group; baseGroups have radio button functionality so your user could switch between primary and secondary use. It would be easy to fill both primary and secondary use by the same value for single use locations.

As we are at a speculative level I can't tell whether one of the three is more appropriate for your use case.

But the way I understand your question it is not so much about {leaflet} and more about managing your entity dimensions in general - the same logic would apply if you tried to assing color via a {ggplot2} call.

1 Like

Hi @jlacko, your're probably right about it being more of a a question of how to we manage our entity dimensions in general. In reality, we are having trouble expressing similar issues with our data, particularly when it comes to mapping out the sites, as we deal with alot of 1-to-many relationships.

For example, in our full data sample, we have 29 values for our 'PointUse' category, with some sites only possessing 1 value, while others can posses any combination up to those 29 choices. Still, being able to color code sites is still one of our top requests from clients, even if it has to mean that *farm + house = blue because house trumps farm (if only for mapping reasons) (there will be other filters included in our final app so the client knows the shown sites include their selected filter choices, even if the color seems wrong).

Something akin to to the second approach would probably work best for us (e.g., farm = red, house = blue, farm + house = blue because house trumps farm; or vice versa).

In such case you might consider something like this piece of code: it is built on dplyr::case_when() and makes use of the fact that case when will stop on the first condition that evaluates TRUE - i.e. once a house is detected in the PointUse column the color is set (a house trumps a farm). In this way a clear hierarchy can be implemented.

For implementation with a varying number of categories it might be easier to implement a dummy variable with TRUE / FALSE values. Something like is house?- yes or no. This would result in a large number of columns, but that is not necessarily a bad thing and can be maintained programatically - as opposed to the case_when structure proposed below, which would require manual editing of levels.

library(dplyr)
library(stringr)

Map_DF <- data.frame("Point_ID" = 1:3,
                     "Latitude" = c(38.10, 38.20, 38.30),
                     "Longitude" = c(-107.10, -107.20, -107.30),
                     "PointUse" = c("farm", "house", "farm, house"))

Map_DF <- Map_DF %>% 
  mutate(color = case_when(str_detect(PointUse, "house") ~ "blue",
                           str_detect(PointUse, "farm") ~ "red",
                           TRUE ~ "a default"))
print(Map_DF)
  Point_ID Latitude Longitude    PointUse color
1        1     38.1    -107.1        farm   red
2        2     38.2    -107.2       house  blue
3        3     38.3    -107.3 farm, house  blue

library(leaflet)
leaflet(Map_DF) %>% 
  addProviderTiles("Stamen.Toner") %>% 
  addCircleMarkers(color = Map_DF$color,
                   stroke = FALSE)

Thanks @jlacko, I think that will get us off the ground for now.

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