avatar

目录
R画地理分布图:罗宾森投影法(Robinson projection)

前言


这张图来自1000 Genomes Project Consortium. A global reference for human genetic variation[J]. Nature, 2015, 526(7571): 68-74.

这张地理分布图去除了南北极,以及国家之间的分界线,再在地图图层上加了饼图展示地理分布和分类信息。我决定我也画一个。。。

我使用过maps包等,画出来的图都觉得不够好看,这里用ggplot(主要是geom_polygon函数)用罗宾逊投影(Robinson projection) 坐标系画世界地图,当然,这里参考了网上很多文章,链接我都放在文章末尾了。

地图数据

地球上的大陆在图上是一个一个多边形,我们这里主要用geom_polygon多边形绘图函数完成工作,首先得下载地图数据。

下载后解压到工作目录下的文件夹中,如

  • /workdir/ne_110m_graticules_all
  • /workdir/ne_110m_land

R 包准备

我们需要rgdal包来读取地图数据文件。

r
1
2
3
4
install.packages("rgdal") #用来读地图数据,以下代码记得只能用1.4-8版本
install.packages("ggplot2")
install.packages("reshape")
install.packages("scatterpie")

画图

世界地图(罗宾逊投影)

文章的地图中,大海的颜色是white,陆地的颜色是 #B4D9A2,陆地的border是 #0F8538

r
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#加载R包、设置工作目录
library(rgdal)
library(ggplot2)
library(reshape)
library(scatterpie)
setwd("/workdir/")

# read shapefile
#这里输入应该是刚才解压的文件夹名称
wmap <- readOGR(dsn="ne_110m_land", layer="ne_110m_land")
# convert to dataframe
wmap_df <- fortify(wmap)
# reproject from longlat to robinson
wmap_robin <- spTransform(wmap, CRS("+proj=robin"))
wmap_df_robin <- fortify(wmap_robin)
# create a blank ggplot theme
theme_opts <- list(theme(panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
panel.background = element_blank(),
plot.background = element_rect(fill="white"),
panel.border = element_blank(),
axis.line = element_blank(),
axis.text.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks = element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
plot.title = element_text(size=22)))
# plot map
ggplot(wmap_df_robin, aes(long,lat, group=group,fill=hole)) +
geom_polygon(colour="#0F8538",lwd=0.05) +
coord_equal() +
theme_opts +
scale_fill_manual(values=c("#B4D9A2", "white"), guide="none")

ggsave("test.pdf", width=16, height=9)

效果图如下

世界地图(罗宾逊投影)+ 边框

r
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#读取边框数据
bbox <- readOGR("ne_110m_graticules_all", layer="ne_110m_wgs84_bounding_box")
bbox_df<- fortify(bbox)

#转换坐标系
bbox_robin <- spTransform(bbox, CRS("+proj=robin")) # reproject bounding box
bbox_robin_df <- fortify(bbox_robin)
#画图
ggplot(bbox_robin_df, aes(long,lat, group=group)) +
geom_polygon(fill="white",colour="black",lwd=0.05) +
geom_polygon(data=wmap_df_robin, aes(long,lat, group=group, fill=hole),colour="#0F8538",lwd=0.05) +
coord_equal() +
theme_opts +
scale_fill_manual(values=c("#B4D9A2", "white"), guide="none")

ggsave("test1.pdf", width=16, height=9)

效果图如下

这个图中还可以添加经纬线,以及国界线

r
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#读入国家边界线
countries <- readOGR("ne_110m_admin_0_countries", layer="ne_110m_admin_0_countries")
countries_robin <- spTransform(countries, CRS("+init=ESRI:54030"))
countries_robin_df <- fortify(countries_robin)

bbox <- readOGR("ne_110m_graticules_all", layer="ne_110m_wgs84_bounding_box")
bbox_df<- fortify(bbox)
bbox_robin <- spTransform(bbox, CRS("+proj=robin")) # reproject bounding box
bbox_robin_df <- fortify(bbox_robin)

ggplot(bbox_robin_df, aes(long,lat, group=group)) +
geom_polygon(fill="white",colour="black",lwd=0.05) +
geom_polygon(data=wmap_df_robin, aes(long,lat, group=group, fill=hole),colour="#0F8538",lwd=0.05) +
geom_polygon(data=countries_robin_df, aes(long,lat, group=group, fill=hole)) +
geom_path(data=countries_robin_df, aes(long,lat, group=group, fill=hole), color="black", size=0.3) +
coord_equal() +
theme_opts +
scale_fill_manual(values=c("#B4D9A2", "white"), guide="none")

世界地图(罗宾逊投影)+ 边框 + 点图

背景画好了,我们得开始展现我们的样本的信息,比如样本的地理分布,该地区取样的多少用圆点的大小来衡量。

r
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#我准备了以下数据,一共34个样本,分布在5个地方,有他们的经纬度信息
# country,weidu,jingdu,geshu
# USA,38.000000,-97.000000,9
# EGY,27.000000,30.000000,1
# IND,20.000000,77.000000,2
# CHN,35.000000,105.000000,6
# AUS,-27.000000,133.000000,16

mydata = read.csv("jingweidu_34.txt",head=T)
head(mydata)
# country weidu jingdu geshu
# 1 USA 38 -97 9
# 2 EGY 27 30 1
# 3 IND 20 77 2
# 4 CHN 35 105 6
# 5 AUS -27 133 16

#转换为robinson 坐标系,S4 project
places_robin_df <- project(cbind(mydata$jingdu, mydata$weidu),
proj="+init=ESRI:54030")
#生成数据框
places_robin_df <- as.data.frame(places_robin_df)

#修改列名,增加数量一列
names(places_robin_df) <- c("LONGITUDE", "LATITUDE")
places_robin_df$num <- mydata$geshu

#画图:注意画图顺序
ggplot(bbox_robin_df, aes(long,lat, group=group)) +
geom_polygon(fill="white",colour="black",lwd=0.05) +
geom_polygon(data=wmap_df_robin, aes(long,lat,
group=group,
fill=hole),
colour="#0F8538",
lwd=0.05) +
geom_point(data=places_robin_df, aes(LONGITUDE,
LATITUDE,
group=NULL,
fill=NULL,
size=num),
color="#808080",
alpha=I(8/10))+
coord_equal() +
theme_opts +
scale_fill_manual(values=c("#B4D9A2", "white"), guide="none") +
scale_size_continuous(range=c(5,20), guide="none")

ggsave("test2.pdf", width=16, height=9)

效果图如下

世界地图(罗宾逊投影)+ 边框 + 分组点图

点图都画出来,分组点图也就简单了,在输入数据中加入分组信息(group)。

r
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
mydata= read.csv("jingweidu_34_g.txt",head=T)
head(mydata)
# country weidu jingdu geshu group
# 1 USA 38 -97 9 g1
# 2 EGY 27 30 1 g1
# 3 IND 20 77 2 g1
# 4 CHN 35 105 6 g2
# 5 AUS -27 133 16 g2

places_robin_df <- project(cbind(mydata$jingdu, mydata$weidu),
proj="+init=ESRI:54030")
places_robin_df <- as.data.frame(places_robin_df)


names(places_robin_df) <- c("LONGITUDE", "LATITUDE")
places_robin_df$num <- mydata$geshu

#增加分组信息
places_robin_df$group <- mydata$group

#画图
ggplot(bbox_robin_df, aes(long,lat, group=group)) +
geom_polygon(fill="white",colour="black",lwd=0.05) +
geom_polygon(data=wmap_df_robin, aes(long,lat,
group=group,
fill=hole),
colour="#0F8538",
lwd=0.05) +
geom_point(data=places_robin_df, aes(LONGITUDE,
LATITUDE,
group=NULL,
fill=NULL,
size=num,
color=group),
alpha=I(8/10))+
#指定分组的颜色
scale_color_manual(values=c("#808080","#D2B48C")) +
coord_equal() +
theme_opts +
scale_fill_manual(values=c("#B4D9A2", "white"), guide="none") +
scale_size_continuous(range=c(5,20), guide="none")

ggsave("test3.pdf", width=16, height=9)

效果图如下

世界地图(罗宾逊投影)+ 边框 + 饼图

首先整理你的样本信息为下图样式(当然,这不是必须的,也可以直接整理成画图的格式)。

每一行代表一个样本,第三列代表分组

r
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
mydata <- read.table("jingweidu_34_scatterpie.txt", head=T)
head(mydata)
# Latitude Longitude Sub.population value
# 1 38 -97 Cluster2 1
# 2 38 -97 Cluster2 1
# 3 38 -97 Cluster3 1
# 4 38 -97 Cluster3 1
# 5 38 -97 Cluster1 1
# 6 38 -97 Cluster1 1
mydata_reshape<- cast(mydata,Latitude+Longitude~Sub.population)
#指定饼图的半径,25指的是梯度,700000是基础半径,
#因为罗宾逊投影坐标都比较大,如果这里小了,你就看不到饼图
mydata_reshape$radius=(((mydata_reshape$Cluster1+
mydata_reshape$Cluster2+
mydata_reshape$Cluster3)%/%25)+700000)
head(mydata_reshape)
# Latitude Longitude Cluster1 Cluster2 Cluster3 radius
# 1 -27 133 4 3 3 7e+05
# 2 20 77 0 1 0 7e+05
# 3 27 30 1 0 0 7e+05
# 4 38 -97 4 3 2 7e+05
places_robin_df <- project(cbind(mydata_reshape$Longitude,
mydata_reshape$Latitude),
proj="+init=ESRI:54030")
places_robin_df <- as.data.frame(places_robin_df)
names(places_robin_df) <- c("LONGITUDE", "LATITUDE")
#这里只分为三类,可以改写成循环
places_robin_df$Cluster1 <- mydata_reshape$Cluster1
places_robin_df$Cluster2 <- mydata_reshape$Cluster2
places_robin_df$Cluster3 <- mydata_reshape$Cluster3
places_robin_df$radius <- mydata_reshape$radius
head(places_robin_df)
# LONGITUDE LATITUDE Cluster1 Cluster2 Cluster3 radius
# 1 12167617 -2887685 4 3 3 7e+05
# 2 7145228 2139038 0 1 0 7e+05
# 3 2744575 2887685 1 0 0 7e+05
# 4 -8527867 4063508 4 3 2 7e+05
ggplot(bbox_robin_df, aes(long,lat, group=group)) +
geom_polygon(fill="white",colour="black",lwd=0.05) +
geom_polygon(data=wmap_df_robin, aes(long,lat,
group=group,
fill=hole),
colour="#0F8538",
lwd=0.05) +
geom_scatterpie(aes(x=LONGITUDE, y=LATITUDE,r=radius),
data=places_robin_df,
cols=c("Cluster1","Cluster2","Cluster3"),
color="black",
alpha=1,lwd=0)+
coord_equal() +
theme_opts +
#颜色分别是 饼图的颜色,大陆的颜色,里海的颜色
scale_fill_manual(values=c("#DCDCDC","#808080","#FFFF00","#B4D9A2","white"),
guide="none")

ggsave("test4.pdf", width=16, height=9)

效果图如下

只显示部分地图

直接对画图用的bbox_robin_df wmap_df_robin 两个数据框进行过滤就行,但是我用的这个地图的数据,两个点的距离有点远,所以边界显示效果不是很好。

r
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#都对纬度进行过滤
bbox_robin_df<-bbox_robin_df[which(bbox_robin_df$lat >= -2.929533e+06),]
wmap_df_robin <- wmap_df_robin[which(wmap_df_robin$lat >= -2887685),]
places_robin_df <- places_robin_df[which(places_robin_df$LATITUDE >= -2887684),]
#画图
ggplot(bbox_robin_df, aes(long,lat, group=group)) +
geom_polygon(fill="white",colour="black",lwd=0.05) +
geom_polygon(data=wmap_df_robin, aes(long,lat,
group=group,
fill=hole),
colour="#0F8538",
lwd=0.05) +
geom_scatterpie(aes(x=LONGITUDE, y=LATITUDE,r=radius),
data=places_robin_df,
cols=c("Cluster1","Cluster2","Cluster3"),
color="black",
alpha=1,lwd=0)+
coord_equal() +
theme_opts +
scale_fill_manual(values=c("#DCDCDC","#808080","#FFFF00","#B4D9A2","white"),
guide="none")

ggsave("test5.pdf", width=16, height=9)

效果图如下

追加更新:改变地图中心

r
1
2
3
4
#第一步转换的时候,将下面这一句:
wmap_robin <- spTransform(wmap, CRS("+proj=robin"))
#换成下面这一句(这里将地图中心变为中国):
wmap_robin <- spTransform(wmap, CRS("+proj=robin +lon_0=150 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"))

总结

到这里我们模仿也就完成基本完成了,我觉得还有用是添加国界线,但是这里加上就少了简洁美了。
还可以优化的是,找个更好的地图数据,让边界更好看。
剩下的就是按照自己需求改改图了

参考

文章作者: Cong FENG
文章链接: https://fengcong97.cn/posts/9035f4a6/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Cong FENG's Blog

评论