查看原文
其他

用 matplotlib 画出中国疫情地图(附源码)

Mort Python中文社区 2022-12-04


作者简介:Mort,数据分析爱好者,擅长数据可视化,比较关注机器学习领域,希望能和业内朋友多学习交流。

最近一段时间,全国的疫情情况一直都是大众所密切关注的,而笔者刚好在网上看到了这个疫情地图,又是就萌生了用Python来绘制疫情地图的写法,下面就简单介绍一下如何用Python中最常用的matplotlib库来绘制疫情地图的方法。

这次用到的是matplotlib中的Basemap,这是一个基于matplotlib的绘图库,需要单独安装,在这里提醒各位一下,安装Basemap最好用conda install basemap命令,如果用pip install basemap命令可能会失败,笔者用的是Anaconda,使用pip安装basemap多次失败,最后只能用conda才安装成功。笔者系统是Win10,Anaconda是官方最新版。

因为绘制地图肯定要用到地图数据,而这个数据的下载方法众多,笔者选择了去权威网站gadm下载,网址为https://www.gadm.org/,在这里我们仅用到中国地图,所以只要下载中国地区的数据就行了,在这里有两种格式的文件,一种是Shapefile文件,一种是Geopackage文件,我们下载前者,文件名是gadm36_CHN_shp.zip,下载后解压,解压完内容如下图。

图1. 中国地图数据文件

有了地图数据之后我们就可以绘制地图了。

首先是数据准备和数据处理。代码如下,其中provinces是一个全国各省名称的list,而nums是各省对应确诊感染人数的list,colors同样是一个list,其中包含我们作图用到的颜色,而info_dic是一个dictionary,其每条数据包含省份名称、感染人数和对应绘图时的颜色。

provinces和nums这两个数据可以到各个疫情数据网站获取,笔者在这里用到的是百度疫情网站,网址是https://voice.baidu.com/act/newpneumonia/newpneumonia,在这里笔者还遇到了一个小插曲,在查看该网址的源代码时,发现百度的程序猿把“治愈”的英文cured拼成了crued(如下图),这可是高中单词……

图2. 百度网页源码
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
from matplotlib.collections import PatchCollection
from matplotlib.patches import PathPatch
import numpy as np

info_dic = {}
provinces = ['湖北','广东','浙江','河南','湖南','安徽','江西','江苏','重庆','山东','四川','北京','黑龙江','上海','福建','河北','陕西','广西','云南','海南','山西','贵州','辽宁','天津','甘肃','吉林','内蒙古','新疆','宁夏','香港','青海','台湾','澳门','西藏']
nums =[29631,1151,1092,1073,879,830,771,492,468,466,405,337,331,299,261,218,213,210,141,136,119,109,107,94,83,80,58,49,49,36,18,18,10,1]
colors = ['darkred','firebrick','indianred','lightcoral','lightsalmon']
for i in range(len(provinces)):
    info_dic[provinces[i]] = {'num':nums[i]}


for name in info_dic.keys():
    if info_dic[name]['num']>=10000:
        info_dic[name]['color']= 'darkred'
    elif 1000<info_dic[name]['num']<9999:
        info_dic[name]['color']= 'firebrick'
    elif 100<info_dic[name]['num']<999:
        info_dic[name]['color']= 'indianred'
    elif 10<info_dic[name]['num']<99:
        info_dic[name]['color']= 'lightcoral'
    else:
        info_dic[name]['color']= 'lightsalmon'

接下来是绘制地图的代码,这里有几点需要注意。一是中国台湾的地图数据要单独下载,因为某些众所周知的原因,之前下载的中国地图数据是不包含中国台湾地图的,笔者作为一位爱国人士,对此表示强烈谴责。二是Basemap官方文档中有把变量名map当作普通变量使用的情况,而Python中map是一个保留(关键)字,这样使用可能会出现一些错误,所以最好不要用map作变量名,笔者用map1作为变量名。三是下面代码中map1.readshapefile读取文件这两行,不需要指定文件的具体扩展名,比如map1.readshapefile(r'f:\data\gadm36_CHN_shp\gadm36_CHN_1', 'prov')这个,其中的gadm36_CHN_1指以“gadm36_CHN_1”开头的那一系列文件,basemap会逐个读取,所以大家不需要指定。

if __name__ == '__main__':
    map1 =  Basemap(projection='lcc', width=7000000,height=5000000,
                       lat_0=35, lon_0=105)
    plt.figure(figsize=(12,9))
    map1.drawmapboundary(fill_color='aqua')
    map1.fillcontinents(color='#ddaa66',lake_color='aqua')
    map1.drawcoastlines()
    map1.readshapefile(r'f:\data\gadm36_CHN_shp\gadm36_CHN_1''prov')
    map1.readshapefile(r'f:\data\gadm36_TWN_shp\gadm36_TWN_0''taiwan'# 台湾地图要单独添加

    ax = plt.gca()
    for name in provinces:
        patch = []
        if name != '台湾':
            for info, shape in zip(map1.prov_info, map1.prov):
                if name in info['NL_NAME_1']:
                    patch.append( Polygon(np.array(shape), closed=True))
            ax.add_collection(PatchCollection(patch, facecolor=info_dic[name]['color'],edgecolor='k', linewidths=1., zorder=2))
        else:
            for info, shape in zip(map1.taiwan_info, map1.taiwan):
                if info['NAME_0'] == "Taiwan":
                    patch.append( Polygon(np.array(shape), closed=True) )
            ax.add_collection(PatchCollection(patch, facecolor=info_dic['台湾']['color'], edgecolor='k', linewidths=1., zorder=2))

绘制好的中国疫情地图如下,再放一张百度原图对比一下。这次用matplotlib绘制的地图是静态图,而且比较简单,如果要做复杂一点的交互式图片,大家可以考虑plotly,笔者目前也在研究,以后会写一些plotly的教程分享给大家。

图3. basemap所绘制地图

图4. 百度官方原图

赞 赏 作 者



Python中文社区作为一个去中心化的全球技术社区,以成为全球20万Python中文开发者的精神部落为愿景,目前覆盖各大主流媒体和协作平台,与阿里、腾讯、百度、微软、亚马逊、开源中国、CSDN等业界知名公司和技术社区建立了广泛的联系,拥有来自十多个国家和地区数万名登记会员,会员来自以工信部、清华大学、北京大学、北京邮电大学、中国人民银行、中科院、中金、华为、BAT、谷歌、微软等为代表的政府机关、科研单位、金融机构以及海内外知名公司,全平台近20万开发者关注。


扫码关注下方公众号后回复“疫情”即可获取本文源码

▼ 点击成为社区注册会员      喜欢文章,点个在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存