使用R绘制带南海诸岛附图的中国地图
2026年3月17日
在科研中绘制标准中国地图是非常重要的。自然资源部提供了标准地图服务,可以绘制简单的分层设色专题图。但是比较麻烦,Bug也挺多的。如何在R中绘制这幅图呢?
首先,我们使用 tmap 包的 v4 版本,这个包是一个强大的绘制地图的包,可以有效处理地图投影等问题。而且 v4 版本进行了大量重构,还有一些新功能的加入,整体要比以前好用很多。
```R
install.packages("tmap")
```
然后从[天地图](https://www.tianditu.gov.cn/)上下载标准矢量地图,是 GeoJSON 格式的。藏得比较深。登陆后,进入【服务中心控制台】,左侧菜单【个性化地图】-【数据资源】,进入【数据资源共享】页面,然后就能看到数据【行政区域可视化】。可以选择省、市、县三个尺度。
以省级为例,下载后可得到 `中国_省.geojson` 这个文件。使用 R 读取。
```R
library(sf)
library(tmap)
China <- st_read("中国_省.geojson")
```
然后可以简单绘制一个地图,可以看到是有完整的九段线和南海诸岛。
```R
tm_shape(China) +
tm_polygons() +
tm_graticules()
```
根据图上所示的范围,我们大概确定一下南海诸岛的边界框(Bounding box),以及大陆和海南省、台湾省的边界框
```R
// 大陆、海南、台湾
mainland_hainan_taiwan <- st_bbox(c(xmin = 73.498962, xmax = 135.087387, ymin = 18, ymax=53.558498), crs = st_crs(China))
// 南海诸岛
south_china_sea <- st_bbox(c(xmin = 108, xmax = 122, ymin = 2, ymax=24), crs = st_crs(China))
```
注意中科院地理所网站上的描述
> 南海诸岛是中国南海上岛屿的总称。北自北卫滩(北纬21°08′),南至曾母暗沙(北纬3°5l′),南北跨纬度17°多,东西跨经度11°多。
然后我们先绘制出南海诸岛地区的地图
```R
south_china_sea_map <- tm_shape(China, bbox = south_china_sea) +
tm_polygons(fill = "white") +
// 显示九段线
tm_lines(col = "black") +
// 显示“南海诸岛”标题
tm_title(
"南海诸岛",
fontfamily = "song",
position = tm_pos_in("right", "bottom"),
frame = T,
frame.r = 0,
padding = c(0.2,0.1,0.2,0.1),
group_id = "nhzd",
// 调整文字显示大小,不要压南沙群岛和九段线
size = 0.7
) +
// 消除边距
tm_components("nhzd", offset = 0) +
tm_scalebar(position = tm_pos_in("left", "bottom","left","bottom","left", "bottom"), width = 5, margins = c(-0.5,0,0,0), group_id = "nhzdscale", allow_clipping = T) +
tm_components("nhzdscale", offset = 0) +
tm_layout(frame.r = 0, inner.margins = c(0,0,0,0), outer.margins = rep(0, 4), meta.margins = rep(0, 4), meta.auto_margins = F)
south_china_sea_map
```
注意 `tm_components` 的使用,通过 `offset` 去掉边距。
然后绘制大陆、海南、台湾的地图,并通过 `tm_inset` 函数将南海诸岛地区地图放进去。
```R
final_map <- tm_shape(China, bbox = mainland_hainan_taiwan) +
tm_polygons(fill = "white", col = "black") +
tm_lines(col = "black") +
# tm_components("south_china_sea_map", offset = 0) +
tm_compass(position = tm_pos_in("right", "top")) +
tm_components(offset = 0) +
tm_scalebar(position = tm_pos_in("left", "bottom"), text.size = 1.2, bg = F, group_id = "scale") +
tm_components(offset = 0) +
tm_layout(frame = FALSE, text.fontfamily = "song", outer.margins = rep(0, 4), inner.margins = rep(0, 4)) +
// 放入南海诸岛地图
tm_inset(x = south_china_sea_map, height = 10, width = 7.5, margins = rep(c(-1.2, -0.8), 2), position = c("right", "bottom"), box_frame = F)
final_map
```
函数 `tm_inset` 中 `height` `width` 参数会影响最终显示的区域的大小,注意调整,不要压到九段线。而且位置要通过 `margins` 参数消除边距,不要让这个图压倒钓鱼岛、九段线等。
具体地图我就不放了,大家自行尝试即可。
还有需要注意的是,R输出中文时会有点问题。所以需要用 `showtext` 包显示中文。
```R
library(showtext)
font_add("song", "FZXSSJW.TTF")
showtext_auto()
```
我这里使用的是方正新书宋简体,换成其他字体是一样的,第一个参数 `"song"` 就是字体族(family)的名称。然后只要在绘图前,调用 `showtext_auto()` 即可。
感谢您的阅读。本网站「地与码之间」对本文保留所有权利。