Convert geographical maps from map() function to objects of class SpatialPolygons

The function map() (maps package), combined with the “worldHires” database from the mapdata package, allows creating a wide variety of geographical maps of world coastlines and national boundaries. The mapdata package contains the full database, approximately 2 million points.

Unfortunately, object returned by the map() function are solely “graphical object” and GIS manipulations and calculations are not possible; for example, values of a raster layer for a specific polygon (e.g. national boundaries) could not be extracted. Moreover, when user is familiar with raster, gdal and sp packages, defining the map projection to use are not simple; which is not achieved by the use of “CRS” of coordinate reference system arguments.

The SpacializedMap() function operates as the map() function, but creates georeferenced map of class SpatialPolygons. User defines the map database and, if needed, the name of the polygon to draw, (i.e. national boundaries, states, islands, etc.). Refer to the map() help page for more details on optional arguments (exact argument can be very usefull). SpatialPolygons thus created, can be transformed to a new coordinate reference system by the use of the spTransform() function (rgdal package).

The SpacializedMap() function helps creating nice figures and maps.
Feel free to use or comment!!

The Function:

SpacializedMap=function(database="world",regions=".",...){
#Create objects of class SpatialPolygons from geographical maps from map() function 
#BBORGY 08/20/2014
require(maps)
require(sp)
require(mapdata)
k=map(database=database,regions=regions,plot=F,fill=T,...)
pol=vector("list",length(unique(k$names)))
w.start=c(1,which(is.na(k$x))+1)
w.end=c(which(is.na(k$x))-1,length(k$x));w=1
for(j in 1:length(unique(k$names))){
pol[[j]]=vector("list",sum(k$names==unique(k$names)[j]))
for(i in 1:sum(k$names==unique(k$names)[j])){
pol[[j]][[i]]=Polygon(cbind(k$x[c(w.start[w]:w.end[w],w.start[w])],k$y[c(w.start[w]:w.end[w],w.start[w])]))
w=w+1}
pol[[j]]=Polygons(pol[[j]],unique(k$names)[j])}
pol=SpatialPolygons(pol,proj4string=CRS("+init=epsg:4326"))
return(pol)}

Example 1:

library(rgdal)
par(mfrow=c(2,2),mar=c(2,2,2,2))
pol_WGS84=SpacializedMap('state')
plot(pol_WGS84,axes=T);mtext("USA WGS 84 / Latlong",cex=.8)
pol_NAD87=spTransform(pol_WGS84,CRS("+init=epsg:3413"))
plot(pol_NAD87,axes=T);mtext("USA WGS 84 / NSIDC Polar Stereographic North",cex=.8)
pol_WGS84=SpacializedMap('worldHires','China',exact=T)
plot(pol_WGS84,axes=T);mtext("CHINA WGS 84 / Latlong",cex=.8)
pol_NAD87=spTransform(pol_WGS84,CRS("+init=epsg:3413"))
plot(pol_NAD87,axes=T);mtext("CHINA WGS 84 / NSIDC Polar Stereographic North",cex=.8)

spatializeMap_1

Example 2:

library(raster)
MAT=raster("bio1.bil")
X11(10,5)
par(mar=rep(2.5,4))
image(MAT,main="Mean Annual Temperature",col=rev(heat.colors(12)),xlab="",ylab="")
map("world",add=T,lwd=2)
box()

spatializeMap_2

The raster layer of mean annual temperature can be downloaded here on the WorldClim website.

Example 3:

pol=SpacializedMap('worldHires','Canada',exact=F)
pol_rasterized=rasterize(pol,MAT)
pol_rasterized=crop(pol_rasterized,extent(c(-145,-45,40,85)))
MAT=crop(MAT,extent(c(-145,-45,40,85)))
values(MAT)[is.na(values(pol_rasterized))]=NA
X11(20,8)
par(mfrow=c(1,2),mar=rep(2.5,4))
image(matrix(1),xlim=c(-145,-45),ylim=c(40,85),col="lightblue",main="Mean Annual Temperature in Canada (WGS 84 / Latlong)",cex.main=.8)
image(MAT,add=T,col=rev(heat.colors(12)))
plot(SpacializedMap('worldHires','USA'),col="grey",add=T,lwd=2)
plot(SpacializedMap('worldHires','Greenland'),col="grey",add=T,lwd=2)
plot(SpacializedMap('worldHires','Canada'),add=T,lwd=2)
box()
MAT=projectRaster(MAT,crs=CRSargs(CRS("+init=epsg:3413")))
image(matrix(1),xlim=c(-5e+6,0),ylim=c(-5.5e+6,.5e+6),col="lightblue",main="Mean Annual Temperature in Canada (WGS 84 / NSIDC Polar Stereographic North)",cex.main=.8)
image(MAT,add=T,col=rev(heat.colors(12)))
plot(spTransform(SpacializedMap('worldHires','USA'),CRS("+init=epsg:3413")),col="grey",add=T,lwd=2)
plot(spTransform(SpacializedMap('worldHires','Greenland'),CRS("+init=epsg:3413")),col="grey",add=T,lwd=2)
plot(spTransform(SpacializedMap('worldHires','Canada'),CRS("+init=epsg:3413")),add=T,lwd=2)
box()
spatializeMap_3

 

Add text in the corner of a plot

Adding text to a plot is not really tricky, and the function text() allows to easily draw a string at given coordinates which can, for example, be identified by the function locator(). However, when you want to draw the same information over several plots while maintaining graphical homogeneity among these plots, accurately identifying where each label has to be drawn appears to be quiet hard and especially if these plots have different ranges over x and y axis or if string length are different.

The following function cornerText() allows to simply add a string in the corner of a plot by automatically identifying appropriate coordinates. The function takes into account x and y ranges of an existing plot, string length and the desired space between the text and the border of the plot (dx and dy arguments). Every arguments of text() (excepted x, y, and labels) can be supplied.

Try it and see how conerText() makes it easy!!!

If some R developers want to improve this code, please contact me!!

conerText=function(txt,corner=c(1:4)[1],dx=.01,dy=.01,cex=1,font=NULL,vfont=NULL,…){
#ADD TEXT TO A PLOT IN THE SELECTED CORNER
#txt : the text to draw.
#corner : the selected corner: 1 = top left, 2 = top right, 3 = bottom right, 4 = bottom left.
#dx & dy : proportion of the plot over x and y axis between text and borders.
#cex, font, vfont and … : other graphical parameters of the text() function.
#feel free to use it!!! B. BORGY
if(length(txt)!=1) stop(“txt has to be a vector of length equal to 1”)
if(!is.character(txt)) txt=as.character(txt)
if(!(corner %in% 1:4)) stop(“corner has to be a integer: 1, 2, 3 or 4”)
if(!is.numeric(cex)|cex<=0) stop(“cex has to be a numeric value > 0”)
if(!is.numeric(dx)) stop(“dx has to be a numeric value”)
if(!is.numeric(dy)) stop(“dy has to be a numeric value”)
if(dx<0) stop(“dx has to be in [0,0.5]”);if(dx>.5) stop(“dx has to be in [0,0.5]”)
if(dy<0) stop(“dy has to be in [0,0.5]”);if(dy>.5) stop(“dy has to be in [0,0.5]”)
brd=par()$usr
u=strwidth(txt,cex=cex,font=font,vfont=vfont)/2+dx*(brd[2]-brd[1])
v=strheight(txt,cex=cex,font=font,vfont=vfont)/2+dy*(brd[4]-brd[3])
xy=list(c(brd[1]+u,brd[4]-v),c(brd[2]-u,brd[4]-v),c(brd[2]-u,brd[3]+v),c(brd[1]+u,brd[3]+v))
text(xy[[corner]][1],xy[[corner]][2],txt,cex=cex,font=font,vfont=vfont,…)}

 

#2 examples:

plot(runif(100)~runif(100))
conerText(“HELLO”)
conerText(“HELLO”,corner=2,col=2,cex=2,font=3)
conerText(“HELLO”,corner=3,col=3,cex=3,vfont=c(“script”,”bold”))
conerText(“HELLO”,corner=4,col=4,cex=4,font=2,dx=.05,dy=.05)

X11(10,5)
par(mfrow=c(1,2))
x=runif(100)*10
y=((runif(100)-.5)*15)+5+x*2
plot(y~x)
lm1=lm(y~x);abline(lm1,col=2)
txt1=paste(“R² =”,round(summary(lm1)$adj,2))
conerText(txt1,cex=1.5,col=2)
txt2=paste(“y = “,paste(round(coef(lm1),2),collapse=” + “),”*x”,sep=””)
conerText(txt2,corner=3,cex=1.5,font=3)
x=runif(100)*5
y=((runif(100)-.5)*3)+10+x*4
plot(y~x)
lm1=lm(y~x);abline(lm1,col=2)
txt1=paste(“R² =”,round(summary(lm1)$adj,2))
conerText(txt1,cex=1.5,col=2)
txt2=paste(“y = “,paste(round(coef(lm1),2),collapse=” + “),”*x”,sep=””)
conerText(txt2,corner=3,cex=1.5,font=3)