最近有个小伙伴遇到了一个这样的问题,他想使用一篇文献中的数据,不过这篇文献并没有提供具体数据,而仅仅是提供了一张地图图片,例如这样的(这个是我随便从一篇论文中找到的):
![]()
那么遇到这种情况,我们该如何从图片中提取数据并重新绘制这幅图呢(毕竟论文是不允许使用截图的)。对于这个地图显然数据已经不太可能提取出来了(因为作者是对数据进行了分段),所以只能说看看能不能提取颜色,然后重新绘制。
在开始内容前,我们先设置下字体和绘图主题:
# 设置字体 |
通常我们可以使用识色软件识别每个城市的颜色(这里的地图是城市地图),然后列个表。但是这很难实现,毕竟很难一一准确的识别 300 多个城市的颜色。这里我提供一种思路供大家参考。
这种方法仅限于我们能猜到这幅地图的坐标参考系的情况,例如上面的地图的坐标参考系是:“+proj=aea +lat_0=0 +lon_0=105 +lat_1=25 +lat_2=47 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs”(这个很常用,自然资源部的很多地图都是用的这个)。
我的思路是先把这个图片作为栅格数据读取,然后再使用城市地理矢量数据提取每个区域的平均颜色,最后再把这些颜色绘制到地图上。
首先我们通过恰当的裁剪把中国地图的部分裁剪出来:
![]()
然后就可以把这个图片作为栅格数据读取了:
library(terra) |
这里我们虽然设定了 crs(坐标参考系),但是还没有设定范围,下面我们需要找到这个栅格数据的范围(extent)。
cnrange.geojson 文件是我使用 https://tidyfriday.cn/geojson 网站绘制的一个中国地图大致范围(不含南海):
![]()
这里的主要目的就是剔出南海部分,避免对等下范围的提取产生影响:
library(sf) |
然后就可以用这个 citybbox 给 rst 设定范围了:
ext(rst) <- c(citybbox[1], citybbox[3], citybbox[2], citybbox[4]) |
然后我们绘制一幅图看看效果:
terra::plot(vect(rangesf), col = "red") |
![]()
这样我们就可以分城市提取各个城市的平均颜色:
terra::extract(rst$pic1_1, vect(city), fun = "mean") -> citydf1 |
rst 实际上总共是 4 个 layer,其中前三个分别是 RGB 颜色的 R 值、G 值 和 B 值,然后我们再把提取得到的三个数据框合并起来组合成颜色:
library(tidyverse) |
然后我可以绘制一副简单的地图看看效果:
citydf %>% |
![]()
这样我们就把这幅图复现出来了,不过还差了图例。
图例可以通过提取颜色绘制出来。
大家可以使用这个图片识色软件:(讲义文档里面有)。
然后提取对应的颜色即可。
如果上面的应用过期了,可以试试这个:https://tidyfriday.cn/colorpicker/
# 图例 |
![]()
然后我们就可以再次绘图了。这里我们仿照样图绘制带小地图版本的中国市级地图:
# 再次绘制主图 |
![]()
这样我们就解决了这个问题。
点击这里跳转到 RStata 短书平台获取附件:R 语言:如何从地图图片上提取数据并重新绘图?
评论