使用 Cartopy 绘制精美的地图

Hello 大家好,我是小骏。
从事气象绘图相关工作的朋友应该知道 Cartopy 这个 Python 库,它可以用来绘制各种投影的地图。

它默认采用 Natural Earth 提供的丰富的底图文件,其中包含了地球上的海洋、陆地、河流、湖泊、海岸线、国界等等,绘制地图时所需要的各种特征文件。


Cartopy 绘图部份依赖 Matplotlib 库,因此配合 Matplotlib 的各种绘图方法,基本上可以画出任何样式的图。当然,前提是要好好查文档,理解 API,并且花时间去折腾。😄

那么这篇专栏就简单介绍一下如何用 Cartopy 绘制我们想要的地图。 按照我们的惯例,我也录制了视频,大家可以点开来对照文章看。
我们可能见过很多种地图,它们显示的形状好像不太一样,这是因为地图有「投影」的区别。Cartopy 中常用的投影有圆柱投影、兰伯特投影、罗宾逊投影、墨卡托投影、正射投影等等,我工作中常用的也就圆柱投影和兰伯特投影这两种。
下图就是一张圆柱投影的图,横坐标是经度,纵坐标是纬度。这种投影好比把地球仪上的那层纸揭了下来,强行摊平成了一个长方形。所以越靠近 0 度纬线,也就是赤道的部分,越接近真实的大小;越靠近两极,相较于真实形状,拉伸程度越高。

下图是一张兰伯特投影的图,这种投影我觉得看起来更舒服一点。感觉上是只把局部的半球面做了拉平处理,所以看起来形变的程度不是很大。

运行下面的代码,就可以画出一幅圆柱投影的图。
简单读过代码可以知道,我们可以给指定的 feature 涂上任意颜色。比如把海洋掩盖掉涂成白色,就像代码中把参数 facecolor 设置成 white 就可以了。

那我如果想突出显示某个国家该怎么做?这就需要深入研究一下画图用到的 shapefile 文件的构成,以及代码调用它的方式。这里大家可以看一下这位大佬的博客,详细总结了 shapefile 是由各种 shape 和 attribute 来表示地图中的点、线、面等要素。
当然我们也可以直接问一下 ChatGPT,看看强大的人工智能能否言简意赅的解释清楚。

综合查阅资料后,我们知道可以这样读取 shapefile 中的内容:
遍历 shapefile 时,每个元素都标注了属性,里面就有我们想要的国家名称和所属大洲名称。我们可以通过比对属性字典中的 NAME_ZH 字段(国家名称简体中文)来筛选国家,或 CONTINENT 字段(大洲英文)来筛选大洲。这里要注意,Natural Earth 提供的文件有三个分辨率,我们选择 1:10m 的分辨率,才会完整的包含全部国家和地区。
下图就是把澳大利亚标红后的效果:

我们从 ERA 的官网上随便下载一个气温数据,可以绘制出这样的填色图。

使用相同的方法,我们可以将澳大利亚之外的部分涂成白色:
出图图下:

但是在气象绘图工作中,不仅需要灵活地画出指定区域,有时还需要对指定区域的数据做计算评估。我们使用上面的方法实质上仅仅是在处理图层,数据图层只是被遮起来了而已,并没有做实际的更改。
这个数据是全球的内容,如果我们想只绘制澳大利亚区域的数据,该怎么做呢?
这里就需要根据 shapefile 文件制作掩膜数据,然后将气温数据与掩膜数据不重合的部分抹去。这里使用前面博客作者开发的 frykit 这个库,来完成掩膜数据的制作。
为了能更方便地验证我们的数据确实被修改了,可以把数据导出成 NC 数据,使用 Panoply 这个软件来直观地看到数据形状。

我们用这个掩膜数据,使用 xarray.where() 方法,将上面填色图的数据掩盖掉,就可以达到只绘制澳大利亚区域的目的了。
可以再用 Panoply 查看一下处理后的数据:

使用这个数据,无需对图层做处理,直接绘制填色图,下图的效果就是我们想要的样子。

现在就可以对数据做统计计算,比如最大值、最小值、平均值等等。

总结
这篇文章想介绍的内容差不多就是这些了,但是说的都比较浅。代码中用到的许多库其实需要对照官方文档或其他资料去练习,比如读取网格数据时用到的 Xarray 库的使用;网格数据的 GRIB、NC 等各种数据格式规范、读取方式;Matplotlib 中的填色图(pcolormesh)、等值面图(contourf)、散点图(scatter)、色标的设置(cmap、norm);以及处理数据时用到的 Pandas、Numpy、Scipy 库的使用;更换正确的中国底图;以及各种气象数据统计相关的理论知识等等。说好听点就是这里的知识博大精深,说的粗糙一点就是坑非常多。
这些知识我也是一知半解,边用边查,所以没有讲的太深。
如果你觉得这篇文章有帮到你,可以点个赞,如果期待后续内容,可以点个关注。
那么我们下期再见,拜拜。👋

参考资料
Natural Earth 官方网站:https://www.naturalearthdata.com/
zhajiman 大佬博客:https://zhajiman.github.io/post/cartopy_shapefile/
cnmaps 官方文档:https://cnmaps-doc.readthedocs.io/zh_CN/latest/index.html
Matplotlib 官方文档:https://matplotlib.org/stable/index.html
Xarray 官方文档:https://docs.xarray.dev/en/stable/index.html
Cartopy 官方文档:https://scitools.org.uk/cartopy/docs/latest/
Panoply 下载页面:https://www.giss.nasa.gov/tools/panoply/download/
ERA 数据下载:https://cds.climate.copernicus.eu/#!/search?text=ERA5&type=dataset
frykit 库 GitHub 仓库:https://github.com/ZhaJiMan/frykit