1
votes

Is there a way to build a custom qualitative color palette that maps category values to color values?

I am trying to build a basic leaflet map in Shiny that colors property parcels (polygons) by their land use (factor). Usually this is simple but I need specific colors for specific categories.

For example, parcels with a land use of 'Commercial' need to be the color '#FF4C4C'. There are about 10 land use categories.

I have tried splitting the data into different layers:

leaflet() %>%
addPolygons(data=parcels[parcels$category == 'Commercial',], fillColor = '#FF4C4C') %>%
addPolygons(data=parcels[parcels$category == 'Residential',], fillColor = '#E9E946')

And so forth but slicing the large SpatialPolygonsDataFrame ten times is slow and consumes a lot of resources. An added problem is that these categories have sub-categories that will need to be shown later, sometimes up to 20 sub-categories, and slicing the spdf 10+20 times won't do.

All of the documentation and stackoverflow questions I have found focus on defining the ranges between two or more colors, but I don't want ranges. I want an exact mapping between factor levels and specific color codes.

I hope there is a simple answer to this. I was hoping I could do something like:

lu_pal <- c('Residential' = '#E9E946', 'Commercial' = '#FF4C4C')

and find a magical function to turn that list into my palette.

2

2 Answers

2
votes
parcels$category <- as.factor(parcel$category)

factpal <- colorFactor(c("#FF4C4C", "#E9E946"), parcels$category)

leaflet(parcels) %>%
  addPolygons(stroke = FALSE, smoothFactor = 0.2, fillOpacity = 1,
              color = ~factpal(category))
0
votes

You could do something like this:


Data creation:

library(leaflet)
library(sp)
library(sf)

Sr1 = Polygon(cbind(c(2,4,4,1,2),c(2,3,5,4,2)))
Sr2 = Polygon(cbind(c(5,4,2,5),c(2,3,2,2)))
Sr3 = Polygon(cbind(c(4,4,5,10,4),c(5,3,2,5,5)))
Sr4 = Polygon(cbind(c(5,6,6,5,5),c(4,4,3,3,4)), hole = TRUE)

Srs1 = Polygons(list(Sr1), "s1")
Srs2 = Polygons(list(Sr2), "s2")
Srs3 = Polygons(list(Sr3, Sr4), "s3/4")
SpP = SpatialPolygons(list(Srs1,Srs2,Srs3), 1:3)

SpF <- st_as_sf(SpP)
SpF$category  <- c("Commercial", "Residential", "Residential")

Note: I am switching the SpatialPolygonsDataFrame to a SimpleFeature from the sf package, which is easier and faster to handle/manipulate.

So, you define a matching data.frame, with the colors for each category. Then you use the merge function and you define which columns to merge on. In this example the Polygon SpF has the column category and the matching dataframe has the column cat. By merging, the new Shapefile NewSp will also have the column col which holds the colors. And you just pass those colors to leaflet.

matching = data.frame(
  cat = c("Commercial", "Residential"),
  col = c("#FF4C4C", "#E9E946")
)

NewSp <- base::merge(SpF, matching, by.x ="category", by.y="cat")

leaflet() %>% 
  addTiles() %>% 
  addPolygons(data=NewSp, color=NewSp$col, opacity = 1, fillOpacity = 0.6)