4

There are some examples to create custom markers in leaflet, but most of them are only for one variable. However, there are lots of data with several factors, which is better to visualize with different shapes and colors.

Here is the dummy data, how to polt markers with different shapes and colors?

lat1= 36+runif(n=5,min=-1,max=1)
lon1 =-115+runif(n=5,min=-1,max=1)

lat2= 35+runif(n=5,min=-0.5,max=0.5)
lon2 =-110+runif(n=5,min=-0.5,max=0.5)

lat3= 34+runif(n=5,min=-0.5,max=0.5)
lon3 =-112+runif(n=5,min=-0.5,max=0.5)

data_all=rbind(data.frame(Longitude=lon1,Latitude=lat1,Group=1),
           data.frame(Longitude=lon2,Latitude=lat2,Group=2),
           data.frame(Longitude=lon3,Latitude=lat3,Group=3))
data_all$color <- rep(c("red", "green", "gray"), 5)
Lee Jim
  • 365
  • 3
  • 16

1 Answers1

10

Just a small note : according to the help page, "grey" is not a supported color, whereas "gray" is... so I changed it.

data_all$color <- rep(c("red", "green", "gray"), 5)

I used this page for help ; you can try the following method, using awesomeIcons, with icons and colors defined in the dataset (using the Bootstrap Glyphicons library)

# add icon label column
data_all <- data_all %>%
  mutate(icon = case_when(
    Group == 1 ~ "home",
    Group == 2 ~ "cog",
    Group == 3 ~ "camera"))

# create awesome icons
my_icons <- awesomeIcons(icon = data_all$icon,
                         markerColor = data_all$color,
                         library = "glyphicon")

# leaflet using AwesomeMarkers
data_all %>% 
  leaflet() %>% 
  addTiles() %>% 
  addAwesomeMarkers(lng = ~ Longitude, lat = ~ Latitude, icon = ~ my_icons[Group])

EDIT
if you want specific icons, my best option is to create your own list of icons, and associate it to your data (afaik, you can't direclty add color to the addMarkers arguments).

The following works, but it probably wouldn't perform well on a huge dataset (see the different comments in the code).

# add "group_color" column as a factor variable : this will be associated to the icons' list
data_all2 <- data_all %>%
  mutate(Group = case_when(
    Group == 1 ~ "triangle",
    Group == 2 ~ "circle",
    Group == 3 ~ "square"),
    group_color = as.factor(paste(Group, color, sep = "_")))

# # Make a list of icons. We'll index into it based on name.
# /!\ order of icons MUST BE THE SAME as the order of the factor "group_color"
my_icons2 <- iconList(
  circle_gray <- makeIcon(iconUrl = "https://www.freeiconspng.com/uploads/black-circle-icon-23.png",
                          iconWidth = 18, iconHeight = 18),
  circle_green <- makeIcon(iconUrl = "https://www.freeiconspng.com/uploads/green-circle-icon-28.png",
                           iconWidth = 18, iconHeight = 18),
  circle_red <- makeIcon(iconUrl = "https://www.freeiconspng.com/uploads/red-circle-icon-1.png",
                         iconWidth = 18, iconHeight = 18),
  square_gray <- makeIcon(iconUrl = "https://www.freeiconspng.com/uploads/black-square-frame-23.png",
                          iconWidth = 18, iconHeight = 18),
  square_green <- makeIcon(iconUrl = "https://www.freeiconspng.com/uploads/green-square-1.png",
                             iconWidth = 18, iconHeight = 18),
  square_red <- makeIcon(iconUrl = "https://www.freeiconspng.com/uploads/red-square-png-14.png",
                         iconWidth = 18, iconHeight = 18),
  triangle_gray <- makeIcon(iconUrl = "https://www.freeiconspng.com/uploads/triangle-png-28.png",
                            iconWidth = 18, iconHeight = 18),
  triangle_green <- makeIcon(iconUrl = "https://www.freeiconspng.com/uploads/green-normal-triangle-png-8.png",
                             iconWidth = 18, iconHeight = 18),
  triangle_red <- makeIcon(iconUrl = "https://www.freeiconspng.com/uploads/red-triangle-png-20.png",
                           iconWidth = 18, iconHeight = 18)
)

# leaflet using addMArkers
data_all2 %>% 
  leaflet() %>% 
  addTiles() %>% 
  # for some reason, we have to use the 'as.numeric' version of the factor, I don't really know why
  addMarkers(lng = ~ Longitude, lat = ~ Latitude, icon = ~ my_icons2[as.numeric(group_color)], 
             popup = ~ paste0("Group = ", Group, "<br>Color = ", color))

Result :
colored_icons

EDIT2
A less cumbersome solution could to combine the second solution with addCircleMarkers : these are not colored icons, bu icons over different colors.

my_icons2 <- iconList(
  circle = makeIcon(iconUrl = "https://www.freeiconspng.com/uploads/black-circle-icon-23.png",
                          iconWidth = 18, iconHeight = 18),
  square = makeIcon(iconUrl = "https://www.freeiconspng.com/uploads/black-square-frame-23.png",
                          iconWidth = 18, iconHeight = 18),
  triangle = makeIcon(iconUrl = "https://www.freeiconspng.com/uploads/triangle-png-28.png",
                            iconWidth = 18, iconHeight = 18)
)

# using original data_all dataframe
# leaflet using addCirleMarkers and addMArkers
data_all %>% 
  leaflet() %>% 
  addTiles() %>% 
  # specific circle color according to the 'color' column
  addCircleMarkers(lng = ~ Longitude, lat = ~ Latitude, color = ~ color, fillColor = ~ color, opacity = 0.8, radius = 15, fillOpacity = 0.8) %>% 
  # specific icon shape according to the 'Group' column
  addMarkers(lng = ~ Longitude, lat = ~ Latitude, icon = ~ my_icons2[Group], 
             popup = ~ paste0("Group = ", Group, "<br>Color = ", color))

You should get something like this : not colored icons, but something understandable enough. icons_over_colored_circles

Hope this helps.

Matt Dzievit
  • 527
  • 3
  • 10
i94pxoe
  • 577
  • 3
  • 11
  • Your code works well. But if I want to use dot and triangle for shapes, how to map the colors? Thanks – Lee Jim Mar 04 '19 at 15:55
  • One more question, if I want use a function like follows, how to modify the code: `pchIcons = function(pch = 1, width = 30, height = 30, bg = "transparent", col = "black", ...) { n = length(pch) files = character(n) # create a sequence of png images for (i in seq_len(n)) { f = tempfile(fileext = '.png') png(f, width = width, height = height, bg = bg) par(mar = c(0, 0, 0, 0)) plot.new() points(.5, .5, pch = pch[i], col = col[i], cex = min(width, height) / 8, ...) dev.off() files[i] = f } files }` – Lee Jim Mar 06 '19 at 00:44
  • So it's possible to create custom shapes and colors. – Lee Jim Mar 06 '19 at 02:25
  • @LeeJim, you should probably ask the person who wrote this code in the first place https://stackoverflow.com/questions/41372139/using-diamond-triangle-and-star-shapes-in-r-leaflet?answertab=active#tab-top – i94pxoe Mar 07 '19 at 08:00
  • FYI Your edit2 doesn't work as written. You need to either add the factor and as.numeric for the Group ...my_icons2[Group] ..... like you did previously, or you need to just assign the different shapes as a name for the iconList: circle = .... square = .... triangle = .... that worked for me (the assigned the name so I can just reference the group directly from the iconList. my_icons["triangle"] ) – Matt Dzievit Jun 27 '23 at 20:55