[R] Help with map
Duncan Murdoch
murdoch at stats.uwo.ca
Sat May 5 04:24:39 CEST 2007
On 04/05/2007 9:00 PM, Alberto Vieira Ferreira Monteiro wrote:
> [for those that worry about these things, this _is_ a homework
> assignment. However, it's not an R homework, it's a Geography
> and History homework... and I want to use R to create a pretty
> map]
>
> Roger Bivand wrote:
>>> Is there any way to associate one color to each country?
>> Try:
>>
>> map_poly_obj <- map("worldHires", c("Argentina", "Brazil"), plot=FALSE,
>> fill=TRUE)
>> str(map_poly_obj)
>>
>> and you'll see that the component of interest is the named polygons, of
>> which there are 28, namely
>>
> Ok, I guess I can see what you mean. It worked, but I don't think
> this is a practical way to draw things.
>
> For example, suppose [this would help homework mentioned above] I
> want to draw a series of maps showing the evolution of Communism
> in the XX century. I would like to start with a 1917 map, showing most
> countries as in...
>
> map("worldHires")
>
> ... but with the Soviet Union in red. I don't see how I could mix the two
> maps (BTW, there's no Russia in worldHires, but there is a USSR...)
>
> map("worldHires"); map("worldHires", "USSR", col="red", fill=T)
>
>> map_poly_obj$names
>>
>> So you can build a matching colours vector, or:
>>
>> library(sp)
>> library(maptools)
>> IDs <- sapply(strsplit(map_poly_obj$names, ":"), function(x) x[1])
>> SP_AB <- map2SpatialPolygons(map_poly_obj, IDs=IDs,
>> proj4string=CRS("+proj=longlat +datum=wgs84"))
>>
>> but
>>
>> plot(SP_AB, col=c("cyan", "green"))
>>
>> still misses, because some polygons have their rings of coordinates in
>> counter-clockwise order, so:
>>
>> pl_new <- lapply(slot(SP_AB, "polygons"), checkPolygonsHoles)
>> slot(SP_AB, "polygons") <- pl_new
>> # please forget the assignment to the slot and do not do it unless you can
>> # replace what was there before
>>
>> plot(SP_AB, col=c("cyan", "green"), axes=TRUE)
>>
>> now works. Moreover, SP_AB is a SpatialPolygons object, which can be
>> promoted to a SpatialPolygonsDataFrame object, for a data slot holding a
>> data.frame with row names matching the Polygons ID values:
>>
>> sapply(slot(SP_AB, "polygons"), function(x) slot(x, "ID"))
>>
>> So adding a suitable data frame gets you to the lattice graphics method
>>
>> spplot(SP_AB, "my_var")
>>
>> Hope this helps,
>>
> So, in the above mentioned case, I could do something like:
>
> library(mapdata)
> commies <- c("USSR", "Mongolia")
> # Mongolia was the 2nd communist country, in 1925
> map_poly_obj <- map("worldHires", plot=FALSE)
> map_poly_commies <- map("worldHires", commies,
> plot=FALSE, fill=TRUE)
> plot(map_poly_obj, type="l")
> polygon(map_poly_commies, col="red", border="black")
>
> I guess I can keep going, unless there is a simpler solution.
Here's the sloppy code I used to put together the map in the persp3d
example in rgl 0.71. I've just made a few edits; I hope it still runs.
The idea is to do a lot of calculations on a vector of colours, then
plot them all at once.
> library(mapdata)
>
> names <- map("worldHires", plot=FALSE, namesonly=TRUE)
> countries <- gsub(":.*", "", names) # the first part of the name
> lakes <- grep("Lake", names)
> lakes <- lakes[-15]
> lakes <- unique(c(lakes, grep("Ozero", names),
> grep("Vodokh", names),
> grep("Nuur", names),
> grep("Ostrov Ol'khon", names),
> grep("Hayk", names),
> grep("Lago", names))) # The map doesn't distinguish these
>
> seas <- grep("Sea", names)
> nfld <- grep("^Newfoundland$", names) # nfld should be coloured as Canada
> canada <- grep("^Canada$", names)
> svalbard <- grep("Svalbard", names) # Svalbard coloured as Norway
> norway <- grep("^Norway$", names)
>
> nums <- as.numeric(factor(countries))
> N <- max(nums)
> set.seed(3)
> col <- hcl(h=sample((1:N)*360/N),
> c=sample(seq(35,45,len=N)),
> l=sample(seq(75,85,len=N)))[nums] # random colours by country
> col[c(lakes,seas)] <- "white" # with lakes and seas white
> col[nfld] <- col[canada]
> col[svalbard] <- col[norway]
>
> png(width=2200, height=2200, file='world.png')
> map('worldHires', fill = TRUE, col = col, ylim=c(-90,90))
> abline(h=c(-90, 90))
> abline(v=c(-180.05, 180.05))
> dev.off()
I hope this gives you some ideas.
Duncan Murdoch
More information about the R-help
mailing list