7

I am trying to make a map of different regions in R with ggplot, where adjacent regions don't have the same color, something aking to what the five color theorem describes.

Regions are groups of californians counties, coded with a number (here the column c20). Using ggplot() and geom_map() with a qualitative scale to color the regions, the closest I get is there:

ggplot() + geom_map(data = data, aes(map_id = geoid, fill = as.factor(c20 %% 12)), 
                  map = county) + expand_limits(x = county$long, y = county$lat) +
coord_map(projection="mercator") +
scale_fill_brewer(palette = "Paired") +
geom_text(data = distcenters, aes(x = clong, y = clat, label = cluster, size = 0.2))

enter image description here

The problem is that adjacent counties from different regions (i.e. with a different number), will sometimes be of the same color. For instance, around Los Angeles, counties from regions 33 & 45 are the same color, and we don't visually differentiate the regions.

Is there a way to do that with ggplot?

jazzurro
  • 23,179
  • 35
  • 66
  • 76
Erispoe
  • 71
  • 2
  • Do you have a similar result, some adjacent counties having the same color, if you use a palette with more choices of colors? I seem to recall that some of the brewer palettes only have so many colors, and that might limit you. – lawyeR Feb 28 '15 at 11:19
  • So do you want an implementation of a colouring algorithm? That would be nothing to do with ggplot for starters... I've implemented (fairly naive versions of) such colouring algorithms in Python for QGIS. The "greedy" algorithm is probably the simplest to understand, but is not optimal (sometimes it ends up 7-colouring regions or more in pathological situations) – Spacedman Feb 28 '15 at 13:32
  • http://www.geeksforgeeks.org/graph-coloring-set-2-greedy-algorithm/ for the algorithm, in R there's code in package:spdep for adjacency computation and package:igraph for network analysis... – Spacedman Feb 28 '15 at 13:38

2 Answers2

3

Try this. It takes a spatial polygons data frame and returns a vector of colours for each element such that no two adjacent polygons have the same colour.

You need to install the spdep package first.

nacol <- function(spdf){
    resample <- function(x, ...) x[sample.int(length(x), ...)]
    nunique <- function(x){unique(x[!is.na(x)])}
    np = nrow(spdf)
    adjl = spdep::poly2nb(spdf)
    cols = rep(NA, np)
    cols[1]=1
    nextColour = 2

    for(k in 2:np){
        adjcolours = nunique(cols[adjl[[k]]])
        if(length(adjcolours)==0){
            cols[k]=resample(cols[!is.na(cols)],1)
        }else{
            avail = setdiff(nunique(cols), nunique(adjcolours))
            if(length(avail)==0){
                cols[k]=nextColour
                nextColour=nextColour+1
            }else{
                cols[k]=resample(avail,size=1)
            }
        }
    }
    return(cols)
}

Test:

  library(spdep)
  example(columbus)
  columbus$C = nacol(columbus)
  plot(columbus,col=columbus$C+1)
Spacedman
  • 92,590
  • 12
  • 140
  • 224
2

This is fairly late, but when searching for the same issue, I found a dev package called MapColoring. It does exactly what you asked for.

Richard
  • 56,349
  • 34
  • 180
  • 251
Puki Luki
  • 573
  • 1
  • 4
  • 13