转摘技巧 | 如何使用R语言的常用工具包绘制双变量填充地图
之前本号转载了DataCharm公众号的一篇推送:
- [转载 | 双变量映射地图可视化绘制方法]
(https://mp.weixin.qq.com/s?__biz=Mzg2MjU1NjQ4NQ==&idx=1&mid=2247484033&scene=21&sn=7ffaaae29489601e61877c4463f45dad#wechat_redirect)
这篇推送使用了biscale
工具包绘制了双变量填充地图。近来,小编发现使用常用的绘图工具包也能很便捷的绘制这种地图,而且灵活性更强一些。
1 示例数据
本篇使用的示例数据和上面转载的推送一样,关于数据的介绍可以点击上面的推送链接查看。
go
library(tidyverse)
data <- socviz::county_data
albersusa::counties_sf(proj = "laea") %>%
mutate(fips = as.character(fips)) %>%
left_join(data, by = c("fips" = "id")) -> usa
- 示例数据来自
socviz
和albersusa
两个工具包,目前它们都只能通过github安装。不会安装的读者可以在公众号后台发送关键词"示例数据"获取。
2 准备工作
灵感来自Nature上的一篇论文:
- Dwyer-Lindgren, L., Cork, M.A., Sligar, A. et al. Mapping HIV prevalence in sub-Saharan Africa between 2000 and 2017. Nature, 570, 189--193 (2019). https://doi.org/10.1038/s41586-019-1200-9
这篇论文绘制的双变量填充地图是这样的:

要想绘制这样的地图,关键是要定义两个方向的渐变颜色,这里直接使用了上述论文所定义的颜色,然后使用sf
工具包的网格生成函数制作了图例,后续只要把这个图例与主图拼接在一起就行了。
go
library(sf)
# 选择颜色
colors <- list(c(249, 244, 248), c(205, 216, 236),
c(177, 203, 230), c(138, 181, 223),
c(239, 212, 219), c(202, 190, 210),
c(175, 176, 207), c(131, 160, 204),
c(237, 170, 179), c(197, 163, 187),
c(157, 145, 183), c(130, 142, 190),
c(234, 129, 143), c(192, 130, 155),
c(161, 129, 166), c(121, 122, 170))
colors <- sapply(colors, function(x)
do.call('rgb', c(as.list(x), maxColorValue = 255)))
comb <- outer(1:4, 1:4, paste0) %>% c()
coldf <- data.frame(col = colors, comb = comb) %>%
mutate(col = as.character(col))
# 生成网格
pts <- rbind(c(0,0), c(0, 4),c(4,4), c(4,0), c(0,0))
sfc <- st_sfc(st_polygon(list(pts)))
grid <- st_make_grid(sfc, n = c(4,4))
Legend <- st_sf(geom = grid, label = coldf$col)
Legend$col <- coldf$col
# 可视化
plot(st_geometry(Legend), col = Legend$col, border = NA)

通过给矢量对象及其属性变量一个固定的命名,在更换绘图数据或变量时只需在下面代码中相应位置修改即可:
go
Shp <- usa %>%
mutate(Var01 = hh_income) %>%
mutate(Var02 = travel_time)
- 这里和转载推文一样,使用
hh_income
和travel_time
作为绘图映射变量。
生成示例对象的边界、将属性变量由连续变量转换为分类变量:
go
Border <- st_union(Shp)
Shp %>%
mutate(A = as.numeric(cut(Var01, include.lowest = T,
breaks = quantile(Var01, na.rm = T,
probs = c(0, 0.25,
0.5, 0.75, 1)))),
B = as.numeric(cut(Var02, include.lowest = T,
breaks = quantile(Var02, na.rm = T,
probs = c(0, 0.25,
0.5, 0.75, 1)))),
comb = paste0(A, B)) %>%
left_join(coldf, by = "comb") -> Shp
- 这里使用的是四分位分类法,如果有需要在
probs
参数中可以修改相应的分位数,或者选用其他分类方法。
3 常用工具包
R语言中常用的绘图系统主要是基础绘图系统graphics
和ggplot2
两种,另外,tmap
是专门绘制地图的工具包。本文分别使用这三个常用工具包来绘制双变量填充地图。
3.1 graphics
绘制方法如下:
go
# 主图
par(fig = c(0,0.9,0,1), plt = c(0,1,0.05,1), family = "mono")
plot(st_geometry(Shp), col = Shp$col, border = NA)
plot(Border, cex = 1, lwd = 2, add = T)
# 图例
par(fig = c(0.85,1,0.1,0.35), plt = c(0,1,0.1,1))
par(new = T, mgp = c(0,0,-2))
plot(st_geometry(Legend), col = Legend$col, border = NA)
mtext("hh_income", side = 1)
mtext("travel_time", side = 2)

使用
graphics
工具包中的函数绘制地图需要加载sf
工具包;通过
par
函数的fig
参数控制主图和图例的位置,该参数的元素使用的是相对尺度,即把内边框的长、宽作为1个单位长度,具体可见推文[graphics | 基础绘图系统(二)------ 绘图参数及par函数](https://mp.weixin.qq.com/s?__biz=Mzg2MjU1NjQ4NQ==&idx=1&mid=2247484941&scene=21&sn=b18bfa0e0602f8c9091d306057c6c3fc#wechat_redirect)
中的布局参数;
mtext
函数中需要修改相应的变量或标签名称。
3.2 ggplot2
绘制方法如下:
go
library(ggplot2)
# 主图
ggplot(Shp) +
geom_sf(aes(fill = I(col)), col = NA) +
theme_void() +
theme(text = element_text(family = "mono"))-> main
# 图例
ggplot(Legend) +
geom_sf(aes(fill = I(col)), col = NA) +
labs(x = "hh_income", y = "travel_time") +
theme_void() +
theme(text = element_text(family = "mono"),
axis.title = element_text(),
axis.title.y = element_text(angle = 90)) -> legend
# 组合
library(cowplot)
ggdraw() +
draw_plot(main, 0, 0, 0.9,1) +
draw_plot(legend, 0.75, 0.05, 0.25, 0.25)

拼接
ggplot2
工具包绘制的图形需要借助cowplot
工具包,因此需要对主图和图例分别进行命名;
draw_plot
函数同样使用的是相对尺度的坐标方式。
3.3 tmap
绘制方式如下:
go
library(tmap)
# 主图
tm_shape(Shp) +
tm_fill(col = "col") +
tm_shape(Border) +
tm_borders(lwd = 2) +
tm_compass(position = c(0.75, 0.85), size = 2.5) +
tm_scale_bar(position = c(0.6, 0.01), text.size = 0.8) +
tm_legend(show = F) +
tm_layout(frame = F, fontfamily = "mono") -> main
main
# 图例
tm_shape(Legend) +
tm_fill("col") +
tm_xlab("hh_income") +
tm_ylab("travel_time") +
tm_layout(frame = F, fontfamily = "mono") -> legend
legend

主图 
图例
tmap
作为专门的地图绘制工具包,其语法结构类似于ggplot2
,因此对于习惯使用ggplot2
绘图的读者很容易入门和掌握。
目前小编还没发现完美拼接tmap
绘制的地图的方法,tmap_arrage
函数达不到相应的效果:
go
tmap_arrange(main, legend, ncol = 2,
widths = c(0.75, 0.25))

- 该函数只能将主图和图例拼接成并列的两列,而不能将图例缩小放到右下角;替代方法是分别导出主图和图例,然后使用Adobe Illustrator软件进行手动调整。
4 比较
4.1 优劣比较
这三个工具包各有优劣:
-
graphics
使用自有参数就可以实现灵活的图形拼接功能,运行速度也较快,但是绘制地图时无法添加指北针和比例尺等地图要素; -
ggplot2
是比较流行的绘图工具包,其绘制地图的功能可能有限,但它有诸多拓展包,从而可以实现灵活拼接、添加指北针和比例尺等功能,不过这也增加了其学习难度; -
tmap
作为专业的地图绘制工具包,可以很方便地添加各种地图要素,缺点是它的图形拼接功能比较有限,而且加载该工具包极为耗时。
4.2 颜色参数比较
这三个工具包中的绘图函数都拥有多个与颜色相关的参数,辨析如下:
-
graphics
中的plot
函数,col
参数不能用于映射,其取值只能是颜色编码,并按照行序依次循环赋予给相应的空间单元;palette
参数用于映射,并结合breaks
和nbreaks
参数使用;border
参数用于给空间单元的边界上色。这里使用的是col
参数并设置border = NA
,以消除内部边界; -
ggplot2
中的geom_sf
函数,fill
和col
参数均有映射和非映射两种用法,其中前者用于空间单元的填充色,后者用于给边界上色。这里使用fill
的映射用法并设置col = NA
,以消除内部边界; -
tmap
中的tm_fill
函数,该函数只针对填充色进行设置,col
参数有映射和非映射两种用法,无论是否映射,其取值都需要加引号""
;palette
参数为非映射用法,用于为col
参数的映射提供对应的颜色编码;若col
参数映射的变量本身就是颜色编码时,则会忽略palette
参数;设置边界需要调用tm_border
函数。这里设置col = "col"
,其中col变量本身为颜色编码,不调用tm_border
函数则默认不显示边界。
往期推荐阅读:
-
[《数据处理通识》专辑-base | 使用apply族函数进行向量化运算]
(https://mp.weixin.qq.com/s?__biz=Mzg2MjU1NjQ4NQ==&idx=1&mid=2247484528&scene=21&sn=599c4bc30cdb4bb4b7e38d7b4df4fe5e#wechat_redirect)
-
[《制表与可视化》专辑-ggplot2 | ggplot2作图语法入门]
(https://mp.weixin.qq.com/s?__biz=Mzg2MjU1NjQ4NQ==&idx=1&mid=2247486538&scene=21&sn=4692d9129a2e3b46f84fc77444d67096#wechat_redirect)
-
[《数学模型》专辑-car | 线性回归(三)------残差分析和异常点检验]
(https://mp.weixin.qq.com/s?__biz=Mzg2MjU1NjQ4NQ==&idx=1&mid=2247486695&scene=21&sn=c055ffd59a67911ed71b740b8424fd59#wechat_redirect)
-
[《地理计算与分析》专辑-spdep | 如何在R语言中计算空间自相关指数]
(https://mp.weixin.qq.com/s?__biz=Mzg2MjU1NjQ4NQ==&idx=1&mid=2247486134&scene=21&sn=4c2905d6bb37084a9606cf4e7d57f78b#wechat_redirect)

```
===========================
【来源: CSDN】
【作者: R语言学堂】
【原文链接】 https://blog.csdn.net/weixin_54000907/article/details/117138180
声明:转载此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与本网联系,我们将及时更正、删除,谢谢。
```