ggplot2 绘制地图时如何使用纹理填充?

ggplot2 绘制地图时如何使用纹理填充?

之前群里有小伙伴问如何在使用 R 语言绘制地图的时候使用纹理填充。经过两天的折腾终于研究出来了。首先我先介绍两个东西,第一个是使用 ggtextures 包绘制有纹理填充的柱状图,第二个是使用 devoutsvg 包绘制有纹理填充的地图(这种方法只能输出 svg 格式的图形)。

安装包

下面的教程用到了一些 GitHub 上的包,可以先运行下面的命令安装:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

如果你无法从 GitHub 上安装这些包,可以在附件中找到安装包进行本地安装。

从哪里找到纹理图片

使用纹理填充的第一步当然是找一些纹理图片啦,svgpatternusgs 包提供了大约 200 多种纹理图案。使用下面的代码我们可以把这些纹理图片保存下来(运行之前记得在工作目录下创建两个名称分别为 svg 和 png 的文件夹):

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

svg 图片无法直接作为栅格数据读取,所以我们可以先把这些 svg 数据转换为 png 数据:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

下面的绘图中我使用了其中的五张图片,但是直接在图例中使用这些图片(800x800的)会过于细密,所以我单独生成了 5 张更低分辨率的图片用于制作图例(也记得创建一个名为 legend 的空文件夹):

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

这样我们就准备好了下面用于填充的纹理图片。

使用 ggtextures 绘制有纹理填充的柱状图

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

为什么要讲这个呢,因为等下想用这个包制作图例哈哈。

使用 devoutsvg 绘制填充纹理的地图

这个方法很容易使用,就是对字体设置等操作不是很友好:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

结果我就不展示了,绘制出的效果感人。

对 ggplot2 绘制出的地图使用纹理填充

首先我们通过一个流程展示这种方法的基本原理,第一步,加载下面的操作中需要的一些 R 包:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

读取我之前介绍的带九段线小地图的中国地图数据:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

然后我筛选出 新疆安徽 两个省等下进行纹理填充:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

下面我们处理纹理图片:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

如果大家有留意的话,刚刚生成这个图片的程序里面也有 800 这个数,也就是说 image 对象是个 800x800 的数据框,然后这个数据框中的每个元素都是该像素点对应的 HEX 颜色值。下面我们生成这些像素点的坐标点(由于这里不是使用大家常见的经纬度坐标系,所以这些左边并不是普通的经纬度):

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

接下来我们要做的事情是对这个数据框进行裁剪,大家可以想象下,上面的操作我是把这个纹理图片覆盖整个中国地图,而下面我们要做的事情就是筛选出这些点中位于新疆和安徽界内的:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

再把这个 sf 对象退化为含XY坐标的数据框:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

接下来就可以画图啦:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

可以看到,安徽和新疆已经被填充上纹理了!

问题到这一步还没有完全解决,我们需要一个图例呀!这就是我刚刚讲 ggtextures 包的目的,我们可以自己做个图例贴上去,这就分三步了:

  1. 使用 ggtextures 造个具有类似图例的图表;
  2. 提取图例;
  3. 贴到地图上。

第一步,我们画个具有类似图例的图表:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

第二步,提取图例。可以使用 cowplot 包:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

第三步,拼图:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

在实际中使用

下面我使用 3 月 22 号我国新冠肺炎现存确诊人数省份分布的案例来演示如何制作一幅带纹理填充的地图。首先我们下载疫情数据并计算现存确诊数据:

$$现存确诊 = 累计确诊 - 累计治愈 - 累计死亡$$

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

读取地图数据:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

本文的开头我使用代码生成了两百多个纹理图片,这里我选择了五种(因为我的数据是分成了 5 组):

  • png/usgs-416.png
  • png/usgs-412.png
  • png/usgs-233.png
  • png/usgs-427.png
  • png/usgs-625.png

下面我们处理一下纹理图片:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

接下来我们依次计算每组(一共五组)包含的省份的纹理(这一段代码运行非常费时,请准备好运行下面代码的时候要做的其他事情):

为了便于大家复现本教程,我把我此时此刻的工作空间保存下:

1
save.image("ggplot2-texture")

大家可以使用下面的命令直接打开我的工作空间:

1
load("ggplot2-texture")

这样大家可以跳过下面这段运行最为耗时的代码,直接绘制下面的图(但是这样的时候大家要注意我的工作空间里面的 cnfont、enfont 这些变量可能会覆盖你的工作空间里面的,所以 load 之后可以运行下你自己 Profile 里面的代码重新生成这些预置变量),打开 Profile 文件的方法是:

1
usethis::edit_r_profile()

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

绘制地图:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

本来我是用 geom_raster 图层的,但是警告信息中提醒我用 geom_tile 图层更好,于是我就听它的了:

最后就是添加图例啦!方法和刚刚的一样:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

这样就完成纹理填充啦!

思考

上面也说到了,对纹理进行填充是个非常耗时的事情,所以我想是不是可以提前生成好每个省的 5 种纹理,然后使用的时候直接从生成好的纹理中进行选择?我觉得这个值得尝试!

知识星球附件链接:https://t.zsxq.com/yJyfmaE

#

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×