用R畫地圖資料
首先,從這裡下載中國地圖的GIS資料,這是一個壓縮包,完全解壓後包含三個檔案(bou2_4p.dbf、bou2_4p.shp和bou2_4p.shx),將這三個檔案解壓到同一個目錄下。
用R繪製地圖比較簡單。比如畫一下全國範圍的區域,可以用如下程式碼:
library(maptools) mydat = readShapePoly("china-province-border-data.tar/china/bou2_4p.shp") #地圖包位置,根據自己的角標位置設定 plot(mydat)
生成的圖如下:
但是,可以看出這樣繪製的地圖的形狀有些扁平。這是因為,在繪圖的過程中,預設把經度和緯度作為普通資料,均勻平等對待,繪製在笛卡爾座標系上造成的。其實,地球的球面圖形如何對映到平面圖上,在地理學上是有一系列不同的專業演算法的。地圖不應該畫在普通的笛卡爾座標系上,而是要畫在地理學專業的座標系上。
也可以安裝maps
和mapdata
這兩個包,然後輸入下面的命令:
install.packages(mapdata) install.packages("mapdata") library(maps) library(mapdata) map("china")
生成的圖如下:
其中map()
函式還可以加上很多引數,大致如下:
map(database = "world", regions = ".", exact = FALSE, boundary = TRUE, interior = TRUE, projection = "", parameters = NULL, orientation = NULL, fill = FALSE, col = 1, plot = TRUE, add = FALSE, namesonly = FALSE, xlim = NULL, ylim = NULL, wrap = FALSE, resolution = if (plot) 1 else 0, type = "l", bg = par("bg"), mar = c(4.1, 4.1, par("mar")[3], 0.1), myborder = 0.01, ...)
可以設定資料庫、地區、精確度、邊界等,在這裡就不一一詳述,具體的用法可以?map。
給地圖上色
在實際使用的過程中,我們往往會根據自己的需要對地圖中的某些省份著以特定的顏色,這時就可以通過調節plot
命令中的fg
引數來予以實現。
首先看看R繪製地圖的原理:
在繪製地圖時,每一個省市自治區或者島嶼都是用一個多邊形來表示的。之前的GIS資料,其實就是提供了每一個行政區其多邊形逐點的座標,然後R軟體通過順次連線這些座標,就繪製出了一個多邊形區域。在上面的資料中,一共包含了925個多邊形的資訊,之所以有這麼多是因為一些省份有很多小的附屬島嶼。在這925個多邊形中,每一個都對應一個唯一的ID,編號分別從1到925。
plot
命令中的fg
引數在本例中應該是一個長度為925的向量,其第i個分量的取值就代表了地圖中第i個多邊形的顏色。一個簡單的嘗試是執行下面這個命令看看效果:
plot(x,col=gray(924:0/924));
生成的圖如下所示:
於是自然就產生了一個問題:如何獲取某一個特定地區的ID,進而設定我們想要的顏色?事實上,在變數x中,就已經儲存了我們想要的資訊。在R中輸入“x[[2]]
”或“x$att.data
”,會得到一個925行7列的資料框,這其實是bou2_4p.dbf這個檔案中儲存的資訊,之前的read.shape()
函式雖然讀取的是bou2_4p.shp檔案,但在預設情況下會把dbf檔案的資訊也放到變數之中。對於這個資料框,其行名就是每一個區域的ID編號,第一列和第二列分別是面積和周長,最後一列是該區域所屬的行政區名,其它的列應該也是一些編號性質的變數。於是,通過查詢相應的行政區對應的行名,就可以對fg
引數進行賦值了。下面是我編的一個函式,用來生成所需的col向量:
getColor=function(mapdata,provname,provcol,othercol) { f=function(x,y) ifelse(x %in% y,which(y==x),0); colIndex=sapply(mapdata@data$NAME,f,provname); col=c(othercol,provcol)[colIndex+1]; return(col); }
其中mapdata
是存放地圖資料的變數,在上面的例子中就是x,provname
是需要改變顏色的地區的名稱,provcol
是對應於provname
的代表顏色的向量(名稱和數字均可),othercol
是其它地區的顏色。舉例如下:
provname=c("北京市","天津市","上海市","重慶市"); provcol=c("red","green","yellow","purple"); plot(x,col=getColor(x,provname,provcol,"white"));
生成的圖資料如下:
生成人口資料分佈圖
利用類似的方法就可以根據自己的需要對不同的區域進行著色,下面再舉一例。從國家統計局獲取2007年我國各地區的人口資料,然後根據人口的多少對各省份進行著色。程式如下:
provname=c("北京市","天津市","河北省","山西省","內蒙古自治區", "遼寧省","吉林省","黑龍江省","上海市","江蘇省", "浙江省","安徽省","福建省","江西省","山東省", "河南省","湖北省","湖南省","廣東省", "廣西壯族自治區","海南省","重慶市","四川省","貴州省", "雲南省","西藏自治區","陝西省","甘肅省","青海省", "寧夏回族自治區","新疆維吾爾自治區","臺灣省", "香港特別行政區"); pop=c(1633,1115,6943,3393,2405,4298,2730,3824,1858,7625, 5060,6118,3581,4368,9367,9360,5699,6355,9449, 4768,845,2816,8127,3762,4514,284,3748,2617, 552,610,2095,2296,693); provcol=rgb(red=1-pop/max(pop)/2,green=1-pop/max(pop)/2,blue=0); plot(x,col=getColor(x,provname,provcol,"white"),xlab="",ylab="");
生成的圖如下:
其中顏色越深的地方代表人口數越多,反之為人口數越少。
畫部分省地圖
在繪製地圖的過程中,還有一個比較有用的引數是recs
,它是一個由多邊形ID組成的向量,表示在地圖中只畫出這些ID所代表的區域。利用這個引數,就可以畫出某一部分的地圖,例如下面的例子是我國中部六省的地圖:
getID=function(mapdata,provname) { index=mapdata$att.data$NAME %in% provname; ids=rownames(mapdata$att.data[index,]); return(as.numeric(ids)); } midchina=c("河南省","山西省","湖北省","安徽省","湖南省","江西省"); plot(x, col = getColor(x, midchina, rep("green", 6), "white"), border = "white", xlab = "", ylab = "")
生成的圖:
用R畫中國地圖並標註城市位置
畫出的圖上仍然可以用points()
函式和text()
函式加上點和文字,而maptools
包中還提供了一個pointLabel()
函式,用來解決文字標籤的重疊問題。
par(mar=rep(0,4)) dat = read.csv(text = "城市,jd,wd 北 京,116.4666667,39.9 上 海,121.4833333,31.23333333 天 津,117.1833333,39.15 重 慶,106.5333333,29.53333333 哈爾濱,126.6833333,45.75 長 春,125.3166667,43.86666667 沈 陽,123.4,41.83333333 呼和浩特,111.8,40.81666667 石家莊,114.4666667,38.03333333 太 原,112.5666667,37.86666667 濟 南,117,36.63333333 鄭 州,113.7,34.8 西 安,108.9,34.26666667 蘭 州,103.8166667,36.05 銀 川,106.2666667,38.33333333 西 寧,101.75,36.63333333 烏魯木齊,87.6,43.8 合 肥,117.3,31.85 南 京,118.8333333,32.03333333 杭 州,120.15,30.23333333 長 沙,113,28.18333333 南 昌,115.8666667,28.68333333 武 漢,114.35,30.61666667 成 都,104.0833333,30.65 貴 陽,106.7,26.58333333 福 州,119.3,26.08333333 臺 北,121.5166667,25.05 廣 州,113.25,23.13333333 海 口,110.3333333,20.03333333 南 寧,108.3333333,22.8 昆 明,102.6833333,25 拉 薩,91.16666667,29.66666667 香 港,114.1666667,22.3 澳門,113.5,22.2") library(maps) library(mapdata) map("china", col = "darkgray", ylim = c(18, 54), panel.first = grid()) points(dat$jd, dat$wd, pch = 19, col = rgb(0, 0, 0, 0.5)) text(dat$jd, dat$wd, dat[, 1], cex = 0.9, col = rgb(0, 0, 0, 0.7), pos = c(2, 4, 4, 4, 3, 4, 2, 3, 4, 2, 4, 2, 2, 4, 3, 2, 1, 3, 1, 1, 2, 3, 2, 2, 1, 2, 4, 3, 1, 2, 2, 4, 4, 2)) axis(1, lwd = 0); axis(2, lwd = 0); axis(3, lwd = 0); axis(4, lwd = 0)
生成的圖:
ggplot2繪製地圖
以中國地圖為例,下載最新的ArcGIS向量地圖資料,這種地圖資料包含了很多資訊,這是畫地圖的基礎資料。下載地址:
http://download.csdn.net/detail/lgstarzkhl/9427677
用以下程式碼進行地圖繪製:
library(maptools) library(ggplot2) library(plyr) #讀取地圖檔案 china_map<-readShapePoly("C:/Users/feng/Desktop/chinaprovinceborderdata_tar_gz/china-province-border-data.tar/Lambert/省級行政區.shp") #提取用於繪圖的地圖資料 x<-china_map@data xs<-data.frame(x,id.1=seq(0:33)-1) #將地圖資料轉換為資料框 china_map1<-fortify(china_map) #新增一個id.1欄位,用於和上面的xs(各省市資料)糅合,合併 china_map1$id.1<-china_map1$id #去掉china_map1中的id欄位,避免在糅合資料的時候,出現兩個相同欄位id和id.1,保證只用id.1來糅合 china_map2<-china_map1[,-7] #糅合地圖資料 china_mapdata<-join(china_map2, xs, type = "full") #繪製地圖 ggplot(china_mapdata, aes(x = long, y = lat, group = group,fill=NAME))+ geom_polygon( )+ geom_path(colour = "grey40")+ scale_fill_manual(values=colours(),guide=FALSE)
生成的圖:
總結
使用R的地圖擴充套件包可以畫出各種樣式的地圖,具體的展現形態及結合方式還有待進一步挖掘。