reference:
How to plot a Taiwan Map colored with Population by ggplot2
R语言中国地图绘制 用R画中国地图并标注城市位置
library(maptools)
## Loading required package: sp
## Checking rgeos availability: FALSE
## Note: when rgeos is not available, polygon geometry computations in maptools depend on gpclib,
## which has a restricted licence. It is disabled by default;
## to enable gpclib, type gpclibPermit()
library(ggplot2)
library(plyr)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:plyr':
##
## arrange, count, desc, failwith, id, mutate, rename, summarise,
## summarize
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
setwd("f:/R-notes/plot_map/") #确定文件路径
china_map <-readShapePoly("bou2_4p.shp") # 读取地图空间数据
## Warning: readShapePoly is deprecated; use rgdal::readOGR or sf::st_read
china_map <- fortify(china_map) #转化为数据框
## Regions defined for each Polygons
#china_data<-read.csv("chinaprovincecity.csv") #读取省会城市坐标
ggplot()+
geom_polygon(data=china_map, aes(x=long, y=lat, group=group),fill="grey95", colour="grey60",size=0.25)+ #中国地图
#geom_point(data=china_data, aes(x = jd,y = wd),size=4,fill="black", alpha=1,shape=21, colour="white")+ #散点图
coord_map("polyconic")
# + theme_nothing()#图表元素设定 这一行代码过时了
library(maptools);
mapdata=readShapePoly('bou2_4p.shp')
## Warning: readShapePoly is deprecated; use rgdal::readOGR or sf::st_read
plot(mapdata);
我们往往会根据自己的需要对地图中的某些省份着以特定的颜色,这时就可以通过调节plot命令中的col参数来予以实现。然而为了清楚地说明这部分的内容,我需要插播一段R绘制地图的原理。 在绘制地图时,每一个省市自治区或者岛屿都是用一个多边形来表示的。之前的GIS数据,其实就是提供了每一个行政区其多边形逐点的坐标,然后R软件通过顺次连接这些坐标,就绘制出了一个多边形区域。在上面的数据中,一共包含了925个多边形的信息,之所以有这么多是因为一些省份有很多小的附属岛屿。在这925个多边形中,每一个都对应一个唯一的ID,编号分别从1到25。
实际上python中用basemap画地图也是这个原理.多边形的个数不一定是925个,应该是900+. 读取bou2_4p.shp文件,在默认情况下会把dbf文件的信息也读取进来.
plot命令中的fg参数在本例中应该是一个长度为925的向量,其第i个分量的取值就代表了地图中第i个多边形的颜色。一个简单的尝试是运行下面这个命令看看效果:
plot(mapdata,col=gray(924:0/924));
# mapdata[2]; # mapdata@data
# mapdata[2][1,]
1:6 %in% 0:10
## [1] TRUE TRUE TRUE TRUE TRUE TRUE
0:10 %in% 1:6
## [1] FALSE TRUE TRUE TRUE TRUE TRUE TRUE FALSE FALSE FALSE FALSE
a = c(5,7,2,9)
ifelse(a %% 2 == 0,"even","odd")
## [1] "odd" "odd" "even" "odd"
x = 1:3
y = 2:4
print(x)
## [1] 1 2 3
print(y)
## [1] 2 3 4
which(x == y)
## integer(0)
x = c(1,3,4,5)
y = c(1,2,4,6)
print(x)
## [1] 1 3 4 5
print(y)
## [1] 1 2 4 6
which(x == y) # 返回相等元素的索引
## [1] 1 3
Embed this directly in the Rmarkdown script that contains the Chinese character comment(s): https://stackoverflow.com/questions/41717781/warning-input-string-not-available-in-this-locale
#Sys.setlocale('LC_ALL','C')
getColor=function(mapdata,provname,provcol,othercol){
f = function(x,y) ifelse(x %in% y,which(y==x),0);
# x是一个向量,y也是一个向量,如果x与y的对应位置的元素相同,则填充该元素在y中的索引,若不相同则记为0
colIndex=sapply(mapdata@data$NAME,f,provname);
#colIndex :925维的向量,不上色的地方对应的元素 存的是0,
#上色的地方对应的元素 存的是要上的颜色的对应的索引,
#注:索引从1开始
color_vec=c(othercol,provcol)[colIndex+1];
return(color_vec);
}
这一行比较难理解
f = function(x,y) ifelse(x %in% y,which(y==x),0);
用python改写下
def f(x,y):
"""
y == unique(y)
"""
res = []
for item in x:
has_equal_num = False
for idx,item_ in enumerate(y):
if item_ == item:
res.append(idx+1)
has_equal_num = True
break
if not has_equal_num:
res.append(0)
联想python中pandas的df.['列1']apply(f)
,对列中的每一行并行应用函数f()
f = function(x,y) ifelse(x %in% y,which(y==x),0);
sapply(mapdata@data$NAME,f,provname)
这两行配合起来,相当于对x的每个元素并行使用f函数,且参数y皆为provname,最后将每个函数调用返回的结果按顺序组装成向量
其中mapdata是存放地图数据的变量,在上面的例子中就是x,provname是需要改变颜色的地区的名称,provcol是对应于provname的代表颜色的向量(名称和数字均可),othercol是其它地区的颜色。举例如下:
othercol = 'white'
provcol=c("red","green","yellow","purple");
temp = c(othercol,provcol)
print(temp)
## [1] "white" "red" "green" "yellow" "purple"
colIndex = c(0,2,3,1,4,0,0,0)
t = colIndex + 1
print(t)
## [1] 1 3 4 2 5 1 1 1
color_vec=c(othercol,provcol)[t];
print(color_vec)
## [1] "white" "green" "yellow" "red" "purple" "white" "white" "white"
R语言中向量语法和python中numpy相当不一样,color_vec=c(othercol,provcol)[t]; 其实可以理解为
merge = othercol + provcol
color_vec = []
for idx in t:
color_vec.append(merge[idx])
provname=c("北京市","天津市","上海市","重庆市");
provcol=c("red","green","yellow","purple");
plot(mapdata,col=getColor(mapdata,provname,provcol,"white"));
注意provname一定要写地区的全称,写法可以参照下面这条命令生成的向量:
as.character(na.omit(unique(mapdata@data$NAME)));
由此生成的向量有33个元素,少了澳门特别行政区,这是这个数据中的一块瑕疵。在x$att.data的第899行有一个NA,不知道它代表的是否就是澳门。
利用类似的方法就可以根据自己的需要对不同的区域进行着色,下面再举一例。从国家统计局获取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(mapdata,col=getColor(mapdata,provname,provcol,"white"),xlab="",ylab="");
局部
此外,在绘制地图的过程中,还有一个比较有用的参数是recs,它是一个由多边形ID组成的向量,表示在地图中只画出这些ID所代表的区域。利用这个参数,就可以画出某一部分的地图,例如下面的例子是我国中部六省的地图:
http://f.dataguru.cn/thread-330558-1-1.html(用R画中国地图并标注城市位置)
getID=function(mapdata,provname){
index=mapdata@data$NAME %in% provname; # bool vector
ids=rownames(mapdata@data[index,]); # rownames 返回行号的向量
return(as.numeric(ids));
}
midchina=c("河南省","山西省","湖北省","安徽省","湖南省","江西省");
#plot(mapdata,recs=getID(mapdata,midchina),col="blue",ol="white",xlab="",ylab="");
新版本的maptools包的绘图函数已经取消了recs这个参数,替代方法如下:
midchina=c("河南省","山西省","湖北省","安徽省","湖南省","江西省");
plot(mapdata,col=getColor(mapdata,midchina,rep('blue',6),'white'),border="white",xlab="",ylab="")