21

I am using the example here for discussion: ggplot map with l

library(rgdal)
library(ggplot2)
library(maptools)

# Data from http://thematicmapping.org/downloads/world_borders.php.
# Direct link: http://thematicmapping.org/downloads/TM_WORLD_BORDERS_SIMPL-0.3.zip
# Unpack and put the files in a dir 'data'

gpclibPermit()
world.map <- readOGR(dsn="data", layer="TM_WORLD_BORDERS_SIMPL-0.3")
world.ggmap <- fortify(world.map, region = "NAME")

n <- length(unique(world.ggmap$id))
df <- data.frame(id = unique(world.ggmap$id),
                 growth = 4*runif(n),
                 category = factor(sample(1:5, n, replace=T)))

## noise
df[c(sample(1:100,40)),c("growth", "category")] <- NA


ggplot(df, aes(map_id = id)) +
     geom_map(aes(fill = growth, color = category), map =world.ggmap) +
     expand_limits(x = world.ggmap$long, y = world.ggmap$lat) +
     scale_fill_gradient(low = "red", high = "blue", guide = "colorbar")

Gives the following results: enter image description here

I would like to map one variable to the left "half" of a country and a different variable to the right "half" of the country. I put "half" in quotes because it's not clearly defined (or at least I'm not clearly defining it). The answer by Ian Fellows might help (which gives an easy way to get the centroid). I'm hoping for something so that I can do aes(left_half_color = growth, right_half_color = category) in the example. I'm also interested in top half and bottom half if that is different.

If possible, I would also like to map the individual centroids of the halves to something.

Community
  • 1
  • 1
Xu Wang
  • 10,199
  • 6
  • 44
  • 78
  • 7
    You may want to consider having two maps side-by-side. Might be a lot more intuitive to look at and interpret than this splitting of the country. – Marc in the box Nov 04 '12 at 21:31

1 Answers1

27

This is a solution without ggplot that relies on the plot function instead. It also requires the rgeos package in addition to the code in the OP:

EDIT Now with 10% less visual pain

EDIT 2 Now with centroids for east and west halves

library(rgeos)
library(RColorBrewer)

# Get centroids of countries
theCents <- coordinates(world.map)

# extract the polygons objects
pl <- slot(world.map, "polygons")

# Create square polygons that cover the east (left) half of each country's bbox
lpolys <- lapply(seq_along(pl), function(x) {
  lbox <- bbox(pl[[x]])
  lbox[1, 2] <- theCents[x, 1]
  Polygon(expand.grid(lbox[1,], lbox[2,])[c(1,3,4,2,1),])
})

# Slightly different data handling
wmRN <- row.names(world.map)

n <- nrow(world.map@data)
world.map@data[, c("growth", "category")] <- list(growth = 4*runif(n),
                 category = factor(sample(1:5, n, replace=TRUE)))

# Determine the intersection of each country with the respective "left polygon"
lPolys <- lapply(seq_along(lpolys), function(x) {
  curLPol <- SpatialPolygons(list(Polygons(lpolys[x], wmRN[x])),
    proj4string=CRS(proj4string(world.map)))
  curPl <- SpatialPolygons(pl[x], proj4string=CRS(proj4string(world.map)))
  theInt <- gIntersection(curLPol, curPl, id = wmRN[x])
  theInt
})

# Create a SpatialPolygonDataFrame of the intersections
lSPDF <- SpatialPolygonsDataFrame(SpatialPolygons(unlist(lapply(lPolys,
  slot, "polygons")), proj4string = CRS(proj4string(world.map))),
  world.map@data)

##########
## EDIT ##
##########
# Create a slightly less harsh color set
s_growth <- scale(world.map@data$growth,
  center = min(world.map@data$growth), scale = max(world.map@data$growth))
growthRGB <- colorRamp(c("red", "blue"))(s_growth)
growthCols <- apply(growthRGB, 1, function(x) rgb(x[1], x[2], x[3],
  maxColorValue = 255))
catCols <- brewer.pal(nlevels(lSPDF@data$category), "Pastel2")

# and plot
plot(world.map, col = growthCols, bg = "grey90")

plot(lSPDF, col = catCols[lSPDF@data$category], add = TRUE)

enter image description here

Perhaps someone can come up with a good solution using ggplot2. However, based on this answer to a question about multiple fill scales for a single graph ("You can't"), a ggplot2 solution seems unlikely without faceting (which might be a good approach, as suggested in the comments above).


EDIT re: mapping centroids of the halves to something: The centroids for the east ("left") halves can be obtained by

coordinates(lSPDF)

Those for the west ("right") halves can be obtained by creating an rSPDF object in a similar way:

# Create square polygons that cover west (right) half of each country's bbox
rpolys <- lapply(seq_along(pl), function(x) {
  rbox <- bbox(pl[[x]])
  rbox[1, 1] <- theCents[x, 1]
  Polygon(expand.grid(rbox[1,], rbox[2,])[c(1,3,4,2,1),])
})

# Determine the intersection of each country with the respective "right polygon"
rPolys <- lapply(seq_along(rpolys), function(x) {
  curRPol <- SpatialPolygons(list(Polygons(rpolys[x], wmRN[x])),
    proj4string=CRS(proj4string(world.map)))
  curPl <- SpatialPolygons(pl[x], proj4string=CRS(proj4string(world.map)))
  theInt <- gIntersection(curRPol, curPl, id = wmRN[x])
  theInt
})

# Create a SpatialPolygonDataFrame of the western (right) intersections
rSPDF <- SpatialPolygonsDataFrame(SpatialPolygons(unlist(lapply(rPolys,
  slot, "polygons")), proj4string = CRS(proj4string(world.map))),
  world.map@data)

Then information could be plotted on the map according to the centroids of lSPDF or rSPDF:

points(coordinates(rSPDF), col = factor(rSPDF@data$REGION))
# or
text(coordinates(lSPDF), labels = lSPDF@data$FIPS, cex = .7)
BenBarnes
  • 19,114
  • 6
  • 56
  • 74
  • Thank you for your great answer (and for the updates). If I follow the advice on the following website, will that allow me to combine what you have done but for ggplot2? https://github.com/hadley/ggplot2/wiki/plotting-polygon-shapefiles – Xu Wang Nov 12 '12 at 09:40
  • @XuWang, You should be able to plot the `lSPDF` and `rSPDF` shapefiles using the linked instructions, but AFAIK you will run into problems if you want different `fill` mappings for each of the halves. – BenBarnes Nov 12 '12 at 09:49