社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

实时追踪,如何用Python画新冠状病毒疫情地图?

程序人生 • 4 年前 • 331 次点击  


作者 | 天元浪子
来源 | CSDN博客


文章目录


1. 前言

2. 数据下载

3. 数据处理

4. 数据可视化


前言


今天,本文作者所在的群里白垩老师问如何用python画武汉肺炎疫情地图。白垩老师是研究海洋生态与地球生物的学者,国家重点实验室成员,于不惑之年学习python,实为我等学习楷模。先前我并没有关注武汉肺炎的具体数据,也没有画过类似的数据分布图。于是就拿了两个小时,专门研究了一下,遂成此文。


数据下载


网上一搜,首先搜到的是腾讯的疫情实时追踪,那就用这个数据源吧。



有了网址怎么抓数据呢?这里,我送大家一双火眼金睛,可以从纷乱中找到最靠谱的下载方式。我习惯用FireFox浏览器,下面的讲解就以FireFox为例(其他浏览器基本类似)。


  • 打开菜单,点击“Web开发者”,在递进菜单中选择"网络":




刷新页面,我们很快就能发现,应答类型为json格式的这个请求,最有可能包含我们需要的数据了:



  • 深入分析,我们就得到了url地址、请求方法、参数、应答格式等信息。查询参数中,callback是回调函数名,我们可以尝试置空,_应该是以毫秒为单位的当前时间戳。有了这些信息,分分钟就可以抓到数据了。我们先在IDLE中以交互方式抓一下看看效果:




    
>>> import time, json, requests>>> url = 'https://view.inews.qq.com/g2/getOnsInfo?name=wuwei_ww_area_counts&callback=&_=%d'%int(time.time()*1000)>>> data = json.loads(requests.get(url=url).json()['data'])>>> print(len(data))301>>> print(data[0]){'country': '中国', 'area': '湖北', 'city': '武汉', 'confirm': 698, 'suspect': 0, 'dead': 63, 'heal': 42}>>> print(data[-1]){'country''中国''area''山东''city''枣庄''confirm'2'suspect'0'dead'0'heal'0}

只要两行代码,就可以抓到数据了。怎么样,是不是超级简单?


数据处理


以省为单位画疫情图,我们只需要统计同属一个省的所有地市的确诊数据即可。最终的数据抓取代码如下:


import time, json, requests
def catch_distribution(): """抓取行政区域确诊分布数据""" data = dict() url = 'https://view.inews.qq.com/g2/getOnsInfo?name=wuwei_ww_area_counts&callback=&_=%d'%int(time.time()*1000) for item in json.loads(requests.get(url=url).json()['data']): if item['area'] not in data: data.update({item['area']:0}) data[item['area']] += int(item['confirm'])     return data

数据可视化


数据可视化,我习惯使用matplotlib模块。matplotlib有很多扩展工具包(toolkits),比如,画3D需要mplot3d工具包,画地图的话,则需要basemap工具包,以及处理地图投影的pyproj模块。另外画海陆分界线、国界线、行政分界线等还需要shape数据。所需模块请自行安装,shape文件可以从这里下载,绘图用到的矢量字库可以从自己的电脑上随便找一个(我用的是simsun.ttf)。我的主程序是2019nCoV.py,shape文件下载下来之后,是这样保存的:



以下为全部代码,除了疫情地图,还包括了全国每日武汉肺炎确诊数据的下载和可视化。


# -*- coding: utf-8 -*-
import timeimport jsonimport requestsfrom datetime import datetimeimport numpy as npimport matplotlibimport matplotlib.figurefrom matplotlib.font_manager import FontPropertiesfrom matplotlib.backends.backend_agg import FigureCanvasAggfrom matplotlib.patches import Polygonfrom matplotlib.collections import PatchCollectionfrom mpl_toolkits.basemap import Basemapimport matplotlib.pyplot as pltimport matplotlib.dates as mdates
plt.rcParams['font.sans-serif'] = ['FangSong'] # 设置默认字体plt.rcParams['axes.unicode_minus'] = False # 解决保存图像时'-'显示为方块的问题
def catch_daily(): """抓取每日确诊和死亡数据""" url = 'https://view.inews.qq.com/g2/getOnsInfo?name=wuwei_ww_cn_day_counts&callback=&_=%d'%int(time.time()*1000) data = json.loads(requests.get(url=url).json()['data']) data.sort(key=lambda x:x['date']) date_list = list() # 日期 confirm_list = list() # 确诊 suspect_list = list() # 疑似 dead_list = list() # 死亡 heal_list = list() # 治愈 for item in data: month, day = item['date'].split('.') date_list.append(datetime.strptime('2020-%s-%s'%(month, day), '%Y-%m-%d')) confirm_list.append(int(item['confirm'])) suspect_list.append(int(item['suspect'])) dead_list.append(int(item['dead'])) heal_list.append(int(item['heal'])) return date_list, confirm_list, suspect_list, dead_list, heal_list
def catch_distribution(): """抓取行政区域确诊分布数据""" data = {'西藏':0} url = 'https://view.inews.qq.com/g2/getOnsInfo?name=wuwei_ww_area_counts&callback=&_=%d'%int(time.time()*1000) for item in json.loads(requests.get(url=url).json()['data']): if item['area'] not in data: data.update({item['area']:0}) data[item['area']] += int(item['confirm']) return data
def plot_daily(): """绘制每日确诊和死亡数据""" date_list, confirm_list, suspect_list, dead_list, heal_list = catch_daily() # 获取数据 plt.figure('2019-nCoV疫情统计图表', facecolor='#f4f4f4', figsize=(10, 8)) plt.title('2019-nCoV疫情曲线', fontsize=20) plt.plot(date_list, confirm_list, label='确诊') plt.plot(date_list, suspect_list, label='疑似') plt.plot(date_list, dead_list, label='死亡') plt.plot(date_list, heal_list, label='治愈') plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m-%d')) # 格式化时间轴标注 plt.gcf().autofmt_xdate() # 优化标注(自动倾斜) plt.grid(linestyle=':') # 显示网格 plt.legend(loc='best') # 显示图例 plt.savefig('2019-nCoV疫情曲线.png') # 保存为文件 #plt.show()
def plot_distribution(): """绘制行政区域确诊分布数据""" data = catch_distribution() font = FontProperties(fname='res/simsun.ttf', size=14) lat_min = 0 lat_max = 60 lon_min = 70 lon_max = 140 handles = [ matplotlib.patches.Patch(color='#ffaa85', alpha=1, linewidth=0), matplotlib.patches.Patch(color='#ff7b69', alpha=1, linewidth=0), matplotlib.patches.Patch(color='#bf2121', alpha=1, linewidth=0), matplotlib.patches.Patch(color='#7f1818', alpha=1, linewidth=0),] labels = [ '1-9人', '10-99人', '100-999人', '>1000人'] fig = matplotlib.figure.Figure() fig.set_size_inches(10, 8) # 设置绘图板尺寸 axes = fig.add_axes((0.1, 0.12, 0.8, 0.8)) # rect = l,b,w,h m = Basemap(llcrnrlon=lon_min, urcrnrlon=lon_max, llcrnrlat=lat_min, urcrnrlat=lat_max, resolution='l', ax=axes) m.readshapefile('res/china-shapefiles-master/china', 'province', drawbounds=True) m.readshapefile('res/china-shapefiles-master/china_nine_dotted_line', 'section', drawbounds=True) m.drawcoastlines(color='black') # 洲际线 m.drawcountries(color='black') # 国界线 m.drawparallels(np.arange(lat_min,lat_max,10), labels=[1,0,0,0]) #画经度线 m.drawmeridians(np.arange(lon_min,lon_max,10), labels=[0,0,0,1]) #画纬度线 for info, shape in zip(m.province_info, m.province): pname = info['OWNER'].strip('\x00') fcname = info['FCNAME'].strip('\x00') if pname != fcname: # 不绘制海岛 continue for key in data.keys(): if key in pname: if data[key] == 0: color = '#f0f0f0' elif data[key] < 10: color = '#ffaa85' elif data[key] <100: color = '#ff7b69' elif data[key] < 1000: color = '#bf2121' else: color = '#7f1818' break poly = Polygon(shape, facecolor=color, edgecolor=color) axes.add_patch(poly) axes.legend(handles, labels, bbox_to_anchor=(0.5, -0.11), loc='lower center', ncol=4, prop=font) axes.set_title("2019-nCoV疫情地图", fontproperties=font) FigureCanvasAgg(fig) fig.savefig('2019-nCoV疫情地图.png')
if __name__ == '__main__': plot_daily()     plot_distribution()

2019-nCoV疫情曲线:


2019-nCoV疫情地图:


上图为圆柱投影,这也是basemap默认的投影模式,我们还可以换用其他投影模式,比如兰勃托等角投影,只需要将97行代码改为:


m = Basemap(projection='lcc', width=5000000, height=5000000, lat_0=36, lon_0=102, resolution='l', ax=axes)

兰勃托投影效果如下:


还可以使用正射投影:

m = Basemap(projection='ortho', lat_0=30, lon_0=105, resolution='l', ax=axes)


正射投影效果如下:


原文链接:
https://blog.csdn.net/xufive/article/details/104093197



热 文 推 荐 


@开发者,带上装备,开源项目wuhan2020等你一起组建“技术武装队伍”

硬核!C语言八大排序算法,附动图和详细代码解释!

疫情严重,潜伏期也有传染性?科技公司在行动

奥利给!前端程序媛妹妹 9 点总结入职半年的成长史


2019女性开发者报告:3成16岁就会编程、JS/Python成女性掌握最多语言


为了让自己快乐,我在36岁辞职了

十步,教你把Python运行速度提升 30%


你点的每个“在看”,我都认真当成了喜欢


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/53931
 
331 次点击