Is there a way in R leaflet to assign different icons to certain locations?

I'm working on a shiny app for a local school district that will display a flag for schools that shouldn't have recess based on air pollutant conditions. The app will filter for one specific day and I've added a column called recess that, based on air pollutants, is labelled either "Stay Inside!" or "Play On!". I've then created an icon list - a child playing icon for "Play on!" and a danger icon for "Stay Inside!".

Where I'm having trouble is with the function. I'm trying to get it to tell leaflet to display the child playing icon for the schools that can have recess that day and a danger icon for the schools that shouldn't have recess that day.

Here's an example of the code I'm using:

# Load Libraries
library(tidyverse)
library(leaflet)

# Vectors
Schools <- c("CHS", "BHS", "DHS")
latitude <- c(60, 61, 62)
longitude <- c(100, 101, 102)
recess <- c("Stay Inside!", "Play on!", "Play on!")

# Data frame
bad_air <- data.frame(Schools, latitude, longitude, recess)

# Map Icons
recessIcons <- awesomeIconList(
  child = makeAwesomeIcon(icon = "child", library = "fa", 
                          markerColor = "blue"),
  danger = makeAwesomeIcon(icon = "exclamation", library = "fa", 
                           markerColor = "darkred")
)

# Function to grab map icon
getrecessIcon <- function(bad_air){
  sapply(bad_air$recess, function(recess){
    if(bad_air$recess == "Stay Inside"){
      recessIcons$child
    } else {
      recessIcons$danger
    }
  })
}

# Build Leaflet Map
leaflet(bad_air) %>%
  addProviderTiles(providers$CartoDB.Positron) %>% 
  addAwesomeMarkers(~longitude,
                    ~latitude,
                    icon = ~getrecessIcon(bad_air),
                    label = ~Schools,
                    labelOptions = labelOptions(noHide = F))

Then I get this error:

Warning messages:
1: In if (bad_air$recess == "Stay Inside") { :
  the condition has length > 1 and only the first element will be used
2: In if (bad_air$recess == "Stay Inside") { :
  the condition has length > 1 and only the first element will be used
3: In if (bad_air$recess == "Stay Inside") { :
  the condition has length > 1 and only the first element will be used

Where am I going wrong? Any help is greatly appreciated!

For the specific error, it is related to the function

getrecessIcon <- function(bad_air){
sapply(bad_air$recess, function(recess){
if(bad_air$recess == "Stay Inside"){
recessIcons$child
} else {
recessIcons$danger
}
})
}

Instead of taking elements from recess one at a time, it is asking if all recess from bad_air is equal to "Stay Inside". The warning will go away if you put update the function as below.

getrecessIcon <- function(bad_air){
sapply(bad_air$recess, function(recess){
if(recess == "Stay Inside"){
recessIcons$child
} else {
recessIcons$danger
}
})
}

However, this will not get the view you described as the results from getrecessIcon(bad_air) is a matrix, where the icon argument is expecting an icon list. The code below can remove the getrecessIcon() and directly have dynamic icons based on recess column content.

library(tidyverse)
library(leaflet)

Schools <- c("CHS", "BHS", "DHS")
latitude <- c(60, 61, 62)
longitude <- c(100, 101, 102)
recess <- c("Stay Inside!", "Play on!", "Play on!")

bad_air <- data.frame(Schools, latitude, longitude, recess,stringsAsFactors = F)

recessIcons <- awesomeIconList(
"Stay Inside!" = makeAwesomeIcon(icon = "child", library = "fa",
markerColor = "blue"),
"Play on!" = makeAwesomeIcon(icon = "exclamation", library = "fa",
markerColor = "red")
)

leaflet(bad_air) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addAwesomeMarkers(~longitude,
~latitude,
icon = ~ recessIcons[recess],
label = ~Schools,
labelOptions = labelOptions(noHide = F))

2 Likes

You may consider converting your plain data frame to a {sf} data frame; it would make the leaflet call more concise. I am not sure I have not messed up your lat / lon data (this is literally middle of nowhere, in Russia to boot..)

# Load Libraries
library(tidyverse)
library(leaflet)
library(sf)

# Vectors
Schools <- c("CHS", "BHS", "DHS")
latitude <- c(60, 61, 62)
longitude <- c(100, 101, 102)
recess <- c("Stay Inside!", "Play on!", "Play on!")

# Data frame
bad_air <- data.frame(Schools, latitude, longitude, recess) %>%
  sf::st_as_sf(coords = c("longitude", "latitude"), crs = 4326)

# list of icons
recessIcons <- awesomeIconList(
  "Stay Inside!" = makeAwesomeIcon(
    icon = "child",
    library = "fa",
    markerColor = "blue"
  ),
  "Play on!" = makeAwesomeIcon(
    icon = "exclamation",
    library = "fa",
    markerColor = "red"
  )
)
# Build Leaflet Map
leaflet(bad_air) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addAwesomeMarkers(icon = ~ recessIcons[recess])

Screenshot from 2020-07-18 21-49-31

1 Like

Thank you so much! That worked!

Thank you! This ended up working as well! More than one way to skin the cat as they say.

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