查看本案例完整的数据, 代码和报告请登录数据酷客 (cookdata.cn) 案例板块.
视频内容
1. 世界各国家现存确诊人数地图
将国家或地区的数值信息映射到地图上, 通过颜色变化来表示数值的大小或范围. 颜色地图适合带有地理位置信息的数据的展现, 将颜色和地图相结合, 直观显示数据的地理分布, 通过颜色深浅容易判断数值的大小. 下图显示的是截止到 4 月 6 日, 中国各省市现有确诊人数地图, 每个省市区域被赋予一种颜色, 通过查看左下角的图例可以明确每种颜色对应的数值范围. 我们可以看到图例中的颜色由下至上依次从浅到深, 数值范围也相应地由小到大. 通过地图可以非常直观地看到各省市现存确诊人数的多少, 比如湖北的现存确诊还有几百人, 北京, 上海, 广东等地由于境外输入病例的增加, 还存在不少的现有确诊病例, 安徽, 广西, 青海等地现有确诊病例已经清零.
在了解了颜色地图的一些基本情况后, 我们利用 pyecharts 绘制截止到 4 月 4 日, 世界现存确诊人数地图, 首先我们导入 4 月 4 日当天的全球疫情数据:
- # 读取数据
- import pandas as pd
- world_data = pd.read_csv('./input/today_world_2020_04_04.csv')
接下来我们导入 pyecharts 库以及绘图需要的相关类:
- import pyecharts
- # 调整配置项
- import pyecharts.options as opts
- # Map 类用于绘制地图
- from pyecharts.charts import Map
首先我们利用各国家的累计确诊人数减去累计治愈和累计死亡人数得到现存确诊人数, 作为新的一列特征添加到数据中:
world_data['today_storeConfirm'] = world_data['total_confirm'] - world_data['total_heal'] - world_data['total_dead']
利用 Map 类绘制世界地图时, 需要输入各国家的英文名称和对应的数值, 但我们的数据中国家的名称是中文, 所以我们首先要将中文名称转换为英文名称:
world_data.head()
我们载入国家中英文对照表, 使用 Series 类的 replace 方法将各国家对应的中文名称替换成英文名称:
- contry_name = pd.read_csv('./input/county_china_english.csv', encoding='GB2312')
- contry_name.head()
- world_data['eg_name'] = world_data['name'].replace(contry_name['中文'].values ,contry_name['英文'].values)
- world_data['eg_name'].head()
提取出我们需要的数据, 保存成一个嵌套列表的形式:
- heatmap_data = world_data[['eg_name','today_storeConfirm']].values.tolist()
- heatmap_data[:10]
接下来我们开始绘图, 首先初始化类对象 Map, 并调用 add 方法添加绘图基本配置:
- map_ = Map().add(series_name = "现存确诊人数", # 设置提示框标签
- data_pair = heatmap_data, # 输入数据
- maptype = "world", # 设置地图类型为世界地图
- is_map_symbol_show = False # 不显示标记点
- )
为保证图形更美观并且更易于观察, 继续添加系列和全局配置项:
- # 设置系列配置项
- map_.set_series_opts(label_opts=opts.LabelOpts(is_show=False)) # 不显示国家 (标签) 名称
- # 设置全局配置项
- map_.set_global_opts(title_opts = opts.TitleOpts(title="世界各国家现存确诊人数地图"), # 设置图标题
- # 设置视觉映射配置项
- visualmap_opts = opts.VisualMapOpts(pieces=[ # 自定义分组的分点和颜色
- {"min": 10000,"color":"#800000"}, # 栗色
- {"min": 5000, "max": 9999, "color":"#B22222"}, # 耐火砖
- {"min": 999, "max": 4999,"color":"#CD5C5C"}, # 印度红
- {"min": 100, "max": 999, "color":"#BC8F8F"}, # 玫瑰棕色
- {"max": 99, "color":"#FFE4E1"}, # 薄雾玫瑰
- ],
- is_piecewise = True)) # 显示分段式图例
调用 render_notebook 方法可以直接在 jupyter notebook 中渲染图形:
由上图可以看到, 新冠肺炎疫情已经造成了全球大流行, 世界上只有几个国家还没有受到新冠肺炎疫情的侵袭. 在亚洲, 伊朗现存确诊人数最多, 中国由于发生疫情较早, 防控措施到位以及对患者积极的治疗, 现存确诊人数已大幅减少; 在美洲, 美国目前是世界上疫情最为严重的国家, 现存确诊人数最多, 这个数字还在随着每日新增确诊人数的增加而不断上升; 欧洲是目前世界上疫情最为严重的大洲, 以意大利和西班牙为首的几个主要国家都有大量的现存确诊病例, 各个国家的医疗系统正面临巨大的压力.
2. 世界国家累计死亡人数玫瑰图
玫瑰图是一种二维极坐标统计图. 玫瑰图与饼状图类似, 饼状图各个扇形的半径相同, 角度不同, 角度表示每一部分占比的大小; 玫瑰图各个扇形的半径和角度都不同, 角度依然表示每一部分的占比大小, 半径表示每一部分的数值大小. 下图是一个特殊的玫瑰图, 扇形角度一致, 半径不同, 可以很清楚观察到海外每个国家累计确诊人数的大小对比关系. 下面我们通过绘制截止到 4 月 4 日, 世界国家累计死亡人数玫瑰图, 从另一角度分析世界国家的疫情严重程度.
首先筛选出累计死亡人数超过 500 人的世界国家, 并按人数进行降序排序:
- need_data = world_data[['name','total_dead']][world_data['total_dead'] >500]
- rank = need_data[['name','total_dead']].sort_values(by='total_dead',ascending=False).values
接着导入 Pie 类并添加绘图的基本配置:
- from pyecharts.charts import Pie
- pie = Pie().add("累计死亡人数", # 添加提示框标签
- rank, # 输入数据
- radius = ["20%", "80%"], # 设置内半径和外半径
- center = ["60%", "60%"], # 设置圆心位置
- rosetype = "radius") # 玫瑰图模式, 通过半径区分数值大小, 角度大小表示占比
最后设置全局和系列配置项并绘制玫瑰图:
- pie.set_global_opts(title_opts = opts.TitleOpts(title="世界国家累计死亡人数玫瑰图", # 设置图标题
- pos_right = '40%'), # 图标题的位置
- legend_opts = opts.LegendOpts( # 设置图例
- orient='vertical', # 垂直放置图例
- pos_right="85%", # 设置图例位置
- pos_top="15%"))
- pie.set_series_opts(label_opts = opts.LabelOpts(formatter="{b} : {d}%")) # 设置标签文字形式为(国家: 占比(%))
- # 在 notebook 中进行渲染
- pie.render_notebook()
从图上可以看到前 11 名国家中欧洲占到了 8 席, 意大利和西班牙的累计死亡人数排在前两位, 已经破万, 美国由于疫情的快速发展, 累计死亡人数快速上升, 来到第三位. 目前意大利和西班牙的医疗系统不堪重负, 医疗物资严重不足, 并且有大量医务人员感染. 相对而言美国的医疗救护能力更强, 美国每 10 万人的 ICU 病床数达为 34.7 个, 而意大利的数据是 12.5 个 ICU 床位 / 10 万人, 西班牙则更少, 只有 9.7 个 ICU 床位 / 10 万人, 不到美国的三分之一, 很多重症病人住不了院, 没有呼吸机.
3. 3 月美国单日新增确诊人数与股票指数涨跌幅折线图
3 月, 全球投资人经历了美股历史上最为动荡的一个月, 10 天经历了 4 次熔断. 所谓熔断机制(Circuit Breaker), 也叫自动停盘机制, 是指当股指波幅达到规定的熔断点时, 交易所为控制风险采取的暂停交易措施. 折线图可以显示随时间而变化的连续数据, 因此非常适合显示在相等时间间隔下数据的趋势, 下图所示的是截止到 4 月 6 日, 海外多国累计确诊人数折线图, 可以直观地观察到海外国家的累计确诊人数在 3 月中旬后快速增长, 特别是美国, 几乎呈指数级增长上升.
我们从 akshare 上获取了 3 月份三只股票指数的涨跌幅数据, 分别是纳斯达克综合指数 (美国), 上证指数(中国) 和日经 225 指数(日本), 通过折线图可以观察美国疫情对美国股票乃至世界其它股票的影响.
首先我们读取从 API 上获取的股票指数数据, 由于周末股市不开盘, 所以只有 22 天的数据:
- stock = pd.read_csv('./input/stockindex.csv',encoding='GB2312')
- stock
接着读取全球疫情历史数据:
alltime_data = pd.read_csv('./input/alltime_world_2020_04_04.csv')
筛选出与股票开盘日期对应的美国单日新增确诊人数:
- import warnings
- warnings.filterwarnings('ignore')
- alltime_us = alltime_data[alltime_data['name'] == '美国']
- use_data = alltime_us[alltime_data['date'].isin(stock['日期'].values)][['date','today_confirm']]
然后导入绘制折线图的 Line 类和绘制组合图形的 Grid 类:
from pyecharts.charts import Line, Grid
定义美国单日新增确诊人数折线图的相关设置:
- l1 = Line().add_xaxis(# 配置 x 轴
- xaxis_data = use_data['date'].values # 输入 x 轴数据
- )
- l1.add_yaxis(# 配置 y 轴
- series_name = "单日新增人数", # 设置图例名称
- y_axis = use_data['today_confirm'].values.tolist(), # 输入 y 轴数据
- symbol_size = 10, # 设置点的大小
- label_opts = opts.LabelOpts(is_show=False), # 标签设置项: 显示标签
- linestyle_opts = opts.LineStyleOpts(width=1.5, type_='dotted'), # 线条宽度和样式
- is_smooth = True, # 绘制平滑曲线
- )
- # 设置全局配置项
- l1.set_global_opts(title_opts = opts.TitleOpts(title = "3 月美国单日新增人数与股票指数涨幅对比折线图",
- pos_left = "center"), # 设置图标题和位置
- axispointer_opts = opts.AxisPointerOpts(is_show = True,
- link = [{"xAxisIndex": "all"}]), # 坐标轴指示器配置
- # x 轴配置项
- xaxis_opts = opts.AxisOpts(type_ = "category",
- boundary_gap = True), # 坐标轴两边是否留白
- # y 轴配置项
- yaxis_opts = opts.AxisOpts(name = "单日新增人数"), # 轴标题
- # 图例配置项
- legend_opts = opts.LegendOpts(pos_left ='7%') # 图例的位置
- )
定义三支股票指数变化的折线图设置:
l2 = Line().add_xaxis(xaxis_data = use_data['date'].values) l2.add_yaxis(series_name = "上证指数", y_axis = stock['SSEC'].values, # 添加上证指数数据 symbol_size = 10, label_opts = opts.LabelOpts(is_show = False), linestyle_opts = opts.LineStyleOpts(width = 1.5), # 设置线宽 is_smooth = True) l2.add_yaxis(series_name = "日经 225 指数", y_axis = stock['N225'].values, # 添加日经 225 指数数据 symbol_size = 10, label_opts = opts.LabelOpts(is_show = False), linestyle_opts = opts.LineStyleOpts(width = 1.5), is_smooth = True) l2.add_yaxis(series_name = "纳斯达克综合指数", y_axis = stock['NASDAQ'].values, # 添加纳斯达克综合指数数据 symbol_size = 10, label_opts = opts.LabelOpts(is_show = False), linestyle_opts = opts.LineStyleOpts(width = 1.5), is_smooth = True) l2.set_global_opts(axispointer_opts = opts.AxisPointerOpts( # 设置坐标轴指示器 is_show = True, link = [{"xAxisIndex": "all"}]), # 对 x 轴所有索引进行联动 xaxis_opts = opts.AxisOpts(grid_index = 1, # x 轴开始的索引 type_ = "category", # 类型 boundary_gap = True, position = "top", # 坐标轴位置 axisline_opts = opts.AxisLineOpts(is_on_zero=True)), # x 轴或 y 轴的轴线是否在另一个轴的 0 刻度上 yaxis_opts = opts.AxisOpts(is_inverse = False, name = "涨跌幅(%)",name_gap = 25), # 轴线设置 legend_opts = opts.LegendOpts(pos_bottom = '50%',pos_right = '70') # 图例设置 )
将两幅图按照上下位置进行组合:
# 绘制组合图形 grid = Grid(init_opts = opts.InitOpts(width = "1024px", height = "768px")) # 设置图形的长和宽 grid.add(chart=l1, # 添加第一个图表 grid_opts = opts.GridOpts(pos_left = 50, pos_right = 50, height = "35%")) # 直角坐标系网格配置项 grid.add(chart = l2, # 添加第二个图表 grid_opts = opts.GridOpts(pos_left = 50, pos_right = 50, pos_top = "55%", height = "35%")) # 利用 notebook 进行渲染 grid.render_notebook()
美国特朗普政府为了防止股市下跌, 让美联储降息, 极力的淡化疫情的危害, 以至于在 3 月初每日新增的确诊人数没有大量增加. 特朗普释放的利好消息根本没有解决股民对新冠疫情感到未知恐惧的问题, 而错过防疫时间, 让疫情在美国快速蔓延. 因此美国股市一跌再跌, 在 3 月 9 号, 12 号, 16 号和 18 号触发了四次熔断, 而后又在熔断的第二天暴涨, 美国股市的熔断同时也影响了另外的两只股票指数, 上证指数和日经 225 指数也有不同幅度的下跌.
4. 3 月世界国家累计确诊人数动态条形图
条形图由一些长度不等的横向长方形组成, 以长方形的长度来表示数据, 易于比较各组数据之间的差别. 比如下图显示的是截止到 4 月 6 日, 海外主要疫情国家 - 每百万人确诊数条形图, 可以明显看出不同国家确诊人数的差距.
动态图表是目前非常流行的一种可视化方法, 可以按照时间序列动态展示条形图数据的变化. 接下来我们利用 Matplotlib 绘制 3 月世界国家累计确诊人数的动态条形图, 来分析最近这一个月来疫情较为严重的国家累计确诊人数的变化.
我们首先挑选出疫情最为严重的 10 个国家, 并筛选出这些国家的历史疫情数据:
country_list = ['美国', '意大利', '中国', '西班牙', '德国', '伊朗', '法国', '英国', '瑞士','比利时'] need_data = alltime_data[alltime_data['name'].isin(country_list)]
接下来使用 datetime 模块生成时间数据, 构造时间列表:
from datetime import datetime,timedelta time_list = [(datetime(2020, 3, 1) + timedelta(i)).strftime('%Y-%m-%d') for i in range(31)]
载入 Matplotlib 库, 并设置正常显示中文字体:
import matplotlib.pyplot as plt %matplotlib inline plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['figure.dpi'] = 100
为每个国家设置一种颜色:
color_list = ['brown','peru','orange','blue','green', 'red','yellow','teal','pink','orchid'] country_color = pd.DataFrame() country_color['country'] = country_list country_color['color'] = color_list
定义绘图函数:
import matplotlib.ticker as ticker def barh_draw(day): # 提取每一天的数据 draw_data = need_data[need_data['date']==day][['name','total_confirm']].sort_values(by='total_confirm',ascending=True) # 清空当前的绘图 ax.clear() # 绘制条形图 ax.barh(draw_data['name'],draw_data['total_confirm'], color=[country_color[country_color['country']==i]['color'].values[0] for i in draw_data['name']]) # 数值标签的间距 dx = draw_data['total_confirm'].max()/200 # 添加数值标签 for j, (name, value) in enumerate(zip(draw_data['name'], draw_data['total_confirm'])): ax.text(value+dx, j, f'{value:,.0f}', size=10, ha='left', va='center') # 添加日期标签 ax.text(draw_data['total_confirm'].max()*0.75, 0.4, day, color='#777777',size=40, ha='left') # 设置刻度标签的格式 ax.xaxis.set_major_formatter(ticker.StrMethodFormatter('{x:,.0f}')) # 设置刻度的位置 ax.xaxis.set_ticks_position('top') # 设置刻度标签的颜色和大小 ax.tick_params(axis='x',colors='#777777', labelsize=15) # 添加网格线 ax.grid(which='major',axis='x',linestyle='-') # 添加图标题 ax.text(0, 11, '3 月世界各国家累计确诊人数动态条形图',size=20, ha='left') # 去除图边框 plt.box(False) # 关闭绘图框 plt.close() # 动态绘图 fig, ax = plt.subplots(figsize=(12, 8)) import matplotlib.animation as animation from IPython.display import html animator = animation.FuncAnimation(fig, barh_draw, frames=time_list, interval=200) HTML(animator.to_jshtml())
从动态条形图中可以看到, 3 月初, 中国的累计确诊人数排在第一位, 由于疫情发生较早且防控措施到位, 每日新增人数逐渐减少, 疫情基本结束, 其它国家的确诊人数还处在萌芽阶段; 3 月初至 3 月中旬, 意大利, 伊朗, 西班牙三个国家累计确诊人数突然快速增长, 其它几个国家的累计确诊人数也在以较快的速度增长; 3 月中旬到 3 月下旬, 美国的累计确诊人数飞速增长, 迅速超越几个欧洲国家, 最终超越中国来到第一位, 成为世界上累计确诊人数最多的国家, 意大利和西班牙继续快速增长, 最终超越中国来到第二位和第三位.
5, 总结
本案例使用基于网易实时疫情播报平台爬取的数据, 进行新冠肺炎疫情数据的可视化分析. 利用 pyecharts 和 Matplotlib 绘制了世界地图, 玫瑰图, 折线图和动态条形图, 从现存确诊人数, 累计死亡人数, 每日新增确诊人数和累计确诊人数四个角度分析全球和部分国家当前的疫情情况. 通过本案例, 大家可以举一反三, 绘制更多的可视化图形, 从更多的角度对疫情数据进行分析, 希望大家学有所成!
来源: https://www.qcloud.com/developer/article/1621588