5

I am trying to plot a geological map using the spplot function in R. For every unit I already assigned a specific color in the col-column of the SpatialPolygonsDataFrame. Now I would like to plot the polygons from the shapefile filling the polygons with the colours according to col-column.

Example Data based on How do I change the polygon fill color and border color for SpatialPolygons objects?

# create data.frame
df <- data.frame(GEOLOGY = c("Quarternary","Tertiary"), col = c("yellow","green"))
# create polygons
Srs1 = Polygons(list(Polygon(cbind(c(2,4,4,1,2),c(2,3,5,4,2)))), "1")
Srs2 = Polygons(list(Polygon(cbind(c(5,4,2,5),c(2,3,2,2)))), "2")
# create spdf
SpDF <- SpatialPolygonsDataFrame( SpatialPolygons(list(Srs1,Srs2)),  df )
# plot spdf
spplot(SpDF, zcol = "GEOLOGY", col.regions = "col")

which results in

Error in .local(obj, ...) : length of col.regions should match number of factor levels

I also tried:

spplot(SpDF, zcol = "GEOLOGY", col.regions = SpDF$col)

which plots the spdf but with wrong colours - red and black?

Any ideas how to plot the correct colours in the correct polygons?


@cengel's suggestion works fine.

After that I added 1 more polygon to my map

df <- data.frame(GEOLOGY = c("Quarternary","Tertiary","Quarternary"), col =  c("yellow","green","yellow"))

Srs1 = Polygons(list(Polygon(cbind(c(2,4,4,1,2),c(2,3,5,4,2)))), "1")
Srs2 = Polygons(list(Polygon(cbind(c(5,4,2,5),c(2,3,2,2)))), "2")
Srs3 = Polygons( list (Polygon(  cbind( c(5,5,4.5,5), c(2,3,2.5,2) ))), "3")

SpDF <- SpatialPolygonsDataFrame( SpatialPolygons(list(Srs1,Srs2, Srs3)), df )
## plot with labels for polygons
spplot(SpDF, zcol = "GEOLOGY", col.regions = as.vector(SpDF$col),
   sp.layout = list(
    list("sp.text", loc = coordinates(SpDF)[1,], txt = SpDF$GEOLOGY[1],cex=0.6),
    list("sp.text", loc = coordinates(SpDF)[2,], txt = SpDF$GEOLOGY[2],cex=0.6),
    list("sp.text", loc = coordinates(SpDF)[3,], txt = SpDF$GEOLOGY[3],cex=0.6)))

removed the typo. Now the Quarterary polgons get a green fill and the Tertiary polygon and yellow fill colour which is not according to the data.frame. It seems to pure coincidence if the colours match?

2

2 Answers 2

4

The problem is that col.regions expects a vector with values or names for colors and you are giving it factors. When you build your dataframe your string vectors are (by default) turned into factors and the levels of the factors are (by default) ordered, in this case alphabetically. This is the reason why the mapping of the colors to the categories is off. In order to allow a correct color mapping for multiple categories, I would suggest the following.

# create a table to map colors to geo-categories
lookupTable <- unique(df)

# match the different geo-categories with the lookup table 
# and retrieve the corresponding color value into a vector
colRegions <- as.vector(lookupTable$col[match(levels(SpDF$GEOLOGY), lookupTable$GEOLOGY)])

# then use it to plot
spplot(SpDF, zcol = "GEOLOGY", col.regions = colRegions)
5
  • Thank you for this suggestion, it works fine but a new problem emerges when I add more polygons to the map - see edited question
    – sdb
    Commented Oct 13, 2014 at 8:52
  • @sdb thanks for pointing this out. Note that you have a typo in your first line of your second example: df <- data.frame ..... (There is an r missing in the second "Quaternary"). If you correct this, you still have two factors (Quarternary and Tertiary) and you need to assign two colors (yellow and green) to each of those. You can use levels to extract a vector of factors. I have edited my answer to account for this.
    – cengel
    Commented Oct 13, 2014 at 16:45
  • A typo... I am ashamed! I already tried the use of level but it didn't work before because of the typo. Still, if the polygons are plotted now the colors are not according to the units in the data.frame? Meaning that the Quaternary polgons got a green fill and the Tertiary polygon an yellow fill colour? I could use rev() or something but in the end it would be pure coincidence if the fill colours match the assigned units? Especially with more units it will get messy.
    – sdb
    Commented Oct 15, 2014 at 14:04
  • @sdb: thanks for catching this! I have again edited my example to map the categories to the colors, which should also work for more units.
    – cengel
    Commented Oct 15, 2014 at 23:24
  • Perfect! Thanks to the last edit, I was now able to plot the real shapefile with correct colors corresponding to the actual geological unit.
    – sdb
    Commented Oct 16, 2014 at 8:33
4

I had a similar problem with needing colors defined by unique values, but did not have pre-defined colors for discrete levels, as in the original question. Instead, I had a range of unique numbers (0 to 1), each needing its own color, and needed to plot a color ramp with the largest value as the darkest color. Here was my solution, based off the above answer, which may help others with a similar situation. This should work with any range of unique values.

library(rgdal)
library(maptools)

# Import the polygon as a Spatial data frame
DaysOver = readShapeSpatial("DaysClosedOverlapSum.shp")

# Define the color ramp
# http://www.0to255.com/ is a helpful website for selecting colors manually
manual.col = colorRampPalette(c("#f7f6fd","#4635d0"))

# Find the unique colors to use from the color ramp, 
# based on the data frame values of interest (in this case, the column called 
# 'Prop' had the values I needed to plot)
color.match = manual.col(length(unique(DaysOver$Prop)))

# Sort the values of interest (in this case, 'Prop')
lookupTable = sort(unique(DaysOver$Prop))

# Match the colors to the sorted unique values in the polygon
# and assign them to a new column in the polygon data
# so that they plot smallest values as lightest and largest values as darkest
DaysOver$color = color.match[match(DaysOver$Prop, lookupTable)]

# Plot the final product!
plot(DaysOver, col=DaysOver$color, border="light gray", lwd=0.5)

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.