我在 R 里画地图(二)
Nov 18, 2019
1 minute read

在R语言中绘制地图,尤其是可交互式的地图的另一个利器是 leaflet 包。 这次我会借着我刚刚完成的一个小项目来讲解这一内容,目标是仿制美国 CDC 官网上的一张图——是的,我们的「战场」从中国转移到了美国。

数据准备

官网上有相关数据的下载。除此之外,我们还需要美国的 shapefile 文件。 一般来说,国外的地图文件去 GADM 上下载问题就不是很大。 接下来,对于这一任务来说,可以通过 ArcGis 方便地将包含各州数据 csv 文件 join 到地图文件上。 这一步唯一要注意的就是地图文件对应字段的类型(一般来说是 Text)要与各州数据类型一致。

在这一系列的上一篇文章中,我当时将这一 merge 过程在 R 里用代码写了出来。 这两种方法都可以,如果需要批量绘制地图的话,当然还是之前代码的方法更好。

leaflet 绘制地图

leaflet 实在是绘制地图的一大利器。它不仅强大,还足够简单。 在 Youtube 上面也有太多相关的教学视频,每一讲大概2-3分钟,看起来也不累。 使用 40 行左右的代码就可以生成我们需要的地图:

library(leaflet)
library(rgdal)
library(sf)
library(htmltools)
library(htmlwidgets)

USA_data <- st_read("map2/USA_data.shp")

# 4个分类的配色定义
pal <- colorFactor(
  palette = c('#fff5f0', '#b4b4b4', '#fb6a4a', '#fcbba1'),
  domain = US$category
)

# 每个州显示的标签内容
USA_data$label <- paste("<p><b>", USA_data$NAME, "</b></p>",
                  "Category: ", USA_data$category, "<br>",
                  "Percent Change From 2016-2017: ", USA_data$change, "<br>",
                  "Statistically ignificant: ",USA_data$significan, "<br>",
                  "2016 Number: ", USA_data$X2016number, "<br>",
                  "2016 Rate: ", USA_data$X2016rate, "<br>",
                  "2017 Number: ", USA_data$X2017number, "<br>",
                  "2017 Rate: ", USA_data$X2017rate)

# 绘制地图并保存
my_map <- leaflet(USA_data) %>%
  addPolygons(color = "#444444", weight = 1, smoothFactor = 0.5,
              opacity = 1.0, fillOpacity = 0.5,
              fillColor = ~pal(category),
              highlightOptions = highlightOptions(color = "white", weight = 2,
                                                  bringToFront = TRUE),
              label=lapply(USA_data$label, HTML),
              labelOptions = labelOptions(textsize = "15px")) %>%
  addLegend(position="bottomright", pal=pal, values=~category, title="Category", opacity=1) %>%
  setView(lng=-98.134, lat=38.053, zoom=4)
saveWidget(widget=my_map, file="my_map.html")

这段代码的核心部分在于一开始使用 sf 包的 st_read() 读取 shapefile 格式的地图文件。 之后使用 leaflet 生成对应的地图对象,再使用类似 ggplot 里面的绘图思路加上各个图层。 addPolygons 方法里面提供了很多参数和选项,包括鼠标悬浮时的高亮选择,悬浮时候的标签和标签的样式。 这样,我们就可以在 USA_data$label 中定义好想要的标签内容,再结合标签样式达到图中的效果了。

阿拉斯加和夏威夷

当然,如果你照着上面的代码绘制,会发现结果和上图有一些不同。 那是因为按照现实地图中的经纬度绘制,阿拉斯加和夏威夷会分别出现在地图的左上角后左下角,导致整个地图显示十分不和谐。 但我们也不能直接不绘制这两个州。 所以一般通用的方式是将这两个州经过一定的坐标变换放置在图中的合适位置。

而不得不说国外有专门处理这一地图的 R 包:albersusa。 这个包里提供了 usa_sf() 这一函数,可以取用美国大陆的指定州,实在好用。 这一部分代码我就不再贴出。

leaflet 与 R shiny

leafletR shiny 结合起来使用也实在是异常顺滑,逼格满满。 最让人舒服的一点是,R shiny 也异常清晰易懂,也存在大量官方和民间教程可供学习。 我可以在地图的左上角放置选项框,并对选中分类的州进行高亮显示:

最后,不得不感叹,在 leaflet 包的强大加持下,交互式地图可视化也能变得如此轻松愉快。 这竟然也让上一期的 ggplot 落后得有点像上个时代的产物。不过当然这是一句玩笑话。 一切都越来越有意思了。