用Pyecharts对疫情数据进行可视化分析

2020-06-12 17:03:34 浏览数 (1)

数据来源

本文使用的数据源来自https://lab.isaaclin.cn/nCoV/zh

数据可视化

代码语言:javascript复制
import requests
import pyecharts
from pyecharts.charts import *
from pyecharts import options as opts
from pyecharts.commons.utils import JsCode
from datetime import date, datetime
import datetime
代码语言:javascript复制
url = 'https://lab.isaaclin.cn/nCoV/api/area'
data = requests.get(url).json()

# 生成更新日期
update_date = date.today()

最新疫情数据

全球疫情地图

代码语言:javascript复制
oversea_confirm = []
for item in data['results']:
    if item['countryEnglishName']:
        oversea_confirm.append((item['countryEnglishName'].replace('United States of America', 'United States')
                                                          .replace('United Kiongdom', 'United Kingdom'), 
                                item['confirmedCount']))


_map = (
        Map(init_opts=opts.InitOpts(theme='dark', width='400'))
        .add("累计确诊人数", oversea_confirm, "world",is_map_symbol_show=False,  is_roam=False)
        .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
        .set_global_opts(
            title_opts=opts.TitleOpts(title="新型冠状病毒全球疫情地图",
                                     subtitle="更新日期:{}".format(update_date)),
            legend_opts=opts.LegendOpts(is_show=False),
            visualmap_opts=opts.VisualMapOpts(is_show=True, max_=50, 
                                              is_piecewise=False, 
                                              range_color=['#FFFFE0', '#FFFFE0', '#FFA07A', '#CD5C5C', '#8B0000']),
            graphic_opts=[
                    opts.GraphicGroup(
                        graphic_item=opts.GraphicItem(
                            bounding="raw",
                            right=150,
                            bottom=50,
                            z=100,
                        ),
                        children=[
                            opts.GraphicRect(
                                graphic_item=opts.GraphicItem(
                                    left="center", top="center", z=100
                                ),
                                graphic_shape_opts=opts.GraphicShapeOpts(
                                    width=200, height=50
                                ),
                                graphic_basicstyle_opts=opts.GraphicBasicStyleOpts(
                                    fill="rgba(0,0,0,0.3)"
                                ),
                            ),
                            opts.GraphicText(
                                graphic_item=opts.GraphicItem(
                                    left="center", top="center", z=100
                                ),
                                graphic_textstyle_opts=opts.GraphicTextStyleOpts(
                                    text=JsCode("['钻石号邮轮', '累计确诊人数:{}人'].join('\n')"
                                                .format(dict(oversea_confirm)['Diamond Princess Cruise Ship'])),
                                    font="bold 16px Microsoft YaHei",
                                    graphic_basicstyle_opts=opts.GraphicBasicStyleOpts(
                                        fill="#fff"
                                    ),
                                ),
                            ),
                        ],
                    )
                ],
        )
    )

_map.render_notebook()

全国疫情地图

代码语言:javascript复制
province_data = []
for item in data['results']:
    if item['countryName'] == '中国':
        province_data.append((item['provinceShortName'], item['confirmedCount']))

_map = (
        Map(init_opts=opts.InitOpts(theme='dark', width='400'))
        .add("累计确诊人数", province_data, "china",is_map_symbol_show=False,  is_roam=False)
        .set_series_opts(label_opts=opts.LabelOpts(is_show=True))
        .set_global_opts(
            title_opts=opts.TitleOpts(title="新型冠状病毒全国疫情地图",
                                     subtitle="更新日期:{}".format(update_date)),
            legend_opts=opts.LegendOpts(is_show=False),
            visualmap_opts=opts.VisualMapOpts(is_show=True, max_=1000, 
                                              is_piecewise=False, 
                                              range_color=['#FFFFE0', '#FFA07A', '#CD5C5C', '#8B0000'])
        )
)

_map.render_notebook()

湖北省内确诊情况¶

代码语言:javascript复制
for item in data['results']:
    if item['provinceShortName'] == '湖北':
        hubei_data = item['cities']

bar = (
        Bar(init_opts=opts.InitOpts(theme='dark', width='400'))
        .add_xaxis([x['cityName'] for x in hubei_data])
        .add_yaxis("累计确诊人数", [x['confirmedCount'] for x in hubei_data])
        .add_yaxis("当前确诊人数", [x['currentConfirmedCount'] for x in hubei_data])
        .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
        .set_global_opts(
            title_opts=opts.TitleOpts(title="新型冠状病毒湖北省内确诊情况",
                                     subtitle="更新日期:{}".format(update_date)),
            xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)),
            legend_opts=opts.LegendOpts(is_show=True),
            graphic_opts=[
                    opts.GraphicGroup(
                        graphic_item=opts.GraphicItem(
                            bounding="raw",
                            right=200,
                            top=120
                        ),
                        children=[
                            opts.GraphicRect(
                                graphic_item=opts.GraphicItem(
                                    left="center", top="center"
                                ),
                                graphic_shape_opts=opts.GraphicShapeOpts(
                                    width=200, height=60
                                ),
                                graphic_basicstyle_opts=opts.GraphicBasicStyleOpts(
                                    fill="rgba(0,0,0,0.3)"
                                ),
                            ),
                            opts.GraphicText(
                                graphic_item=opts.GraphicItem(
                                    left="center", top="center", z=1
                                ),
                                graphic_textstyle_opts=opts.GraphicTextStyleOpts(
                                    text=JsCode("['当前确诊人数:', '','累计确诊人数-死亡人数-治愈人数'].join('\n')"),
                                    font="bold 12px Microsoft YaHei",
                                    graphic_basicstyle_opts=opts.GraphicBasicStyleOpts(
                                        fill="#fff"
                                    ),
                                ),
                            ),
                        ],
                    )
                ],
                )
        )

bar.render_notebook()

全国疫情热力图

代码语言:javascript复制
cities_data = []
for item in data['results']:
    if item['countryName'] == '中国':
        cities_data.extend((item['cities']))

geo = (
        Geo(init_opts=opts.InitOpts(theme='dark', width='400'))
        .add_schema(maptype="china", zoom=3, center=[114.31,30.52])
        .add("累计确诊人数", 
             [(i['cityName'], i['currentConfirmedCount']) for i in cities_data 
              if i['cityName'] in pyecharts.datasets.COORDINATES.keys()], 
             type_='heatmap',
             symbol_size=3,
             progressive=50)
        .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
        .set_global_opts(
            title_opts=opts.TitleOpts(title="新型冠状病毒全国疫情热力图",
                                     subtitle="更新日期:{}".format(update_date),
                                     pos_left='right'),
            legend_opts=opts.LegendOpts(is_show=False),
            visualmap_opts=opts.VisualMapOpts(is_show=True, 
                                              is_piecewise=False, 
                                              range_color=['blue', 'green', 'yellow', 'yellow', 'red'])
        )
)

geo.render_notebook()

时间序列数据

数据处理

因为各地疫情数据更新时间不一致且存在缺失情况,需先对数据进行处理。

代码语言:javascript复制
# 获取时间序列数据
# 细分到城市
area_data_timeline = requests.get('https://lab.isaaclin.cn/nCoV/api/area?latest=0').json()

# 全国数据
all_data_timeline = requests.get('http://lab.isaaclin.cn/nCoV/api/overall?latest=0').json()
代码语言:javascript复制
def get_value(dic, key):
    try:
        return dic[key]
    except KeyError:
        return 0

def insert_data(to_update_date, to_update_area, dic, is_city):
    if to_update_date in format_data:
        if to_update_area in format_data[to_update_date]:
            pass
        else:
            format_data[to_update_date][to_update_area] = {}
    else:
        format_data[to_update_date] = {}
        format_data[to_update_date][to_update_area] = {}
    format_data[to_update_date][to_update_area]['currentConfirmedCount'] = get_value(dic, 'currentConfirmedCount')
    format_data[to_update_date][to_update_area]['confirmedCount'] = get_value(dic, 'confirmedCount')
    format_data[to_update_date][to_update_area]['deadCount'] = get_value(dic, 'deadCount')
    format_data[to_update_date][to_update_area]['suspectedCount'] = get_value(dic, 'suspectedCount')
    format_data[to_update_date][to_update_area]['curedCount'] = get_value(dic, 'curedCount')
    format_data[to_update_date][to_update_area]['countryName'] = get_value(dic, 'countryName')
    # 用于区分区域层级
    if is_city:
        format_data[to_update_date][to_update_area]['is_city'] = 1 
    else:
        format_data[to_update_date][to_update_area]['is_city'] = 0

format_data = {}
for item in area_data_timeline['results'][::-1]:
    to_update_date = date.fromtimestamp(item['updateTime']/1000)
    to_update_area = item['provinceShortName']
    insert_data(to_update_date, to_update_area, item, 0)
    if 'cities' in item:
        if item['cities']:
            for city_data in item['cities']:
                insert_data(to_update_date, city_data['cityName'], city_data, 1)

for item in all_data_timeline['results'][::-1]:
    to_update_date = date.fromtimestamp(item['updateTime']/1000)
    insert_data(to_update_date, '全国', item, 0)

time_range = list(format_data.keys())
代码语言:javascript复制
def area_data(area_name='湖北', type_='confirmedCount', get_total=True, date_list=time_range):
    # 用于pyecharts获取时间序列数据
    data_array = []
    for day in date_list:
        try:
            data_array.append(format_data[day][area_name][type_])
        except KeyError:
            if day   datetime.timedelta(days=-1) in format_data:
                if area_name in format_data[day   datetime.timedelta(days=-1)]:
                    # 当天未更新数据情况时,取前一天数据填充
                    data_array.append(format_data[day   datetime.timedelta(days=-1)][area_name][type_])
                else:
                    data_array.append(0)
            else:
                data_array.append(0)
    # 返回每日新增数据
    if not get_total:
        data_array = [data_array[i 1] - data_array[i] for i in range(len(data_array)-1)]
    return data_array

全国/湖北/武汉疫情趋势折线图¶

代码语言:javascript复制
data_type = {'累计确诊': 'confirmedCount', 
             '死亡病例': 'deadCount', 
             '治愈病例': 'curedCount'}

tl = Timeline(init_opts=opts.InitOpts(theme='dark', width='400'))
tl.add_schema(is_auto_play=True, play_interval=5000)

for key_, value_ in data_type.items():
    line = (Line(init_opts=opts.InitOpts())
            .add_xaxis(time_range)
            .add_yaxis("全国", area_data('全国', value_),is_smooth=True,
                       areastyle_opts=opts.AreaStyleOpts(opacity=1, 
                                                         color=JsCode("""new echarts.graphic.LinearGradient(0, 0, 0, 1, 
                                                                        [{
                                                                            offset: 0,
                                                                            color: 'rgb(255,99,71)'
                                                                        }, {
                                                                            offset: 1,
                                                                            color: 'rgb(32,178,170)'
                                                                        }])""")),
                       markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="max", name="最新数据")], symbol_size=70))
            .add_yaxis("湖北", area_data('湖北', value_),is_smooth=True,
                       areastyle_opts=opts.AreaStyleOpts(opacity=0))
            .add_yaxis("武汉", area_data('武汉', value_),is_smooth=True,
                       areastyle_opts=opts.AreaStyleOpts(opacity=0))
            .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
            .set_global_opts(
                title_opts=opts.TitleOpts(title="新型冠状病毒全国{}趋势图".format(key_),
                                         subtitle="更新日期:{}".format(update_date)),
                xaxis_opts=opts.AxisOpts(
                       type_="time", 
                       splitline_opts=opts.SplitLineOpts(is_show=False)),
           ))
    tl.add(line, key_)

tl.render_notebook()

全国疫情新增趋势

代码语言:javascript复制
line = (Line(init_opts=opts.InitOpts(theme='dark'))
        .add_xaxis(time_range[1:])
        .add_yaxis("全国", area_data('全国', get_total=False),is_smooth=True,
                   areastyle_opts=opts.AreaStyleOpts(opacity=1, 
                                                     color=JsCode("""new echarts.graphic.LinearGradient(0, 0, 0, 1, 
                                                                    [{
                                                                        offset: 0,
                                                                        color: 'rgb(255,99,71)'
                                                                    }, {
                                                                        offset: 1,
                                                                        color: 'rgb(32,178,170)'
                                                                    }])""")),)
        .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
        .set_global_opts(
            title_opts=opts.TitleOpts(title="新型冠状病毒全国每日新增确诊病例趋势图",
                                     subtitle="更新日期:{}".format(update_date)),
            xaxis_opts=opts.AxisOpts(
                   type_="time", 
                   splitline_opts=opts.SplitLineOpts(is_show=False)),
       ))

line.render_notebook()

全国疑似病例趋势¶

代码语言:javascript复制
line = (Line(init_opts=opts.InitOpts(theme='dark'))
        .add_xaxis(time_range[1:])
        .add_yaxis("全国", area_data('全国', 'suspectedCount', get_total=True),is_smooth=True,
                   areastyle_opts=opts.AreaStyleOpts(opacity=1, 
                                                     color=JsCode("""new echarts.graphic.LinearGradient(0, 0, 0, 1, 
                                                                    [{
                                                                        offset: 0,
                                                                        color: 'rgb(255,99,71)'
                                                                    }, {
                                                                        offset: 1,
                                                                        color: 'rgb(32,178,170)'
                                                                    }])""")),)
        .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
        .set_global_opts(
            title_opts=opts.TitleOpts(title="新型冠状病毒全国疑似病例趋势图",
                                     subtitle="更新日期:{}".format(update_date)),
            xaxis_opts=opts.AxisOpts(
                   type_="time", 
                   splitline_opts=opts.SplitLineOpts(is_show=False)),
       ))

line.render_notebook()

全国疫情蔓延趋势

代码语言:javascript复制
tl = Timeline(init_opts=opts.InitOpts(theme='dark', width='400'))
tl.add_schema(axis_type='time', is_auto_play=True, is_timeline_show=False)

for day in time_range:
    geo = (
            Geo(init_opts=opts.InitOpts(theme='dark'))
            .add_schema(maptype="china", zoom=1)
            .add("累计确诊人数", 
                 [(key_, value_['confirmedCount']) for key_, value_, in format_data[day].items() 
                  if key_ in pyecharts.datasets.COORDINATES.keys() and value_['is_city']==1], 
                 type_='heatmap',
                 symbol_size=3,
                 progressive=50)
            .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
            .set_global_opts(
                title_opts=opts.TitleOpts(title="新型冠状病毒全国疫情热力图【自动轮播】",
                                         subtitle="更新日期:{}".format(update_date)),
                legend_opts=opts.LegendOpts(is_show=False),
                visualmap_opts=opts.VisualMapOpts(max_=50000, is_show=False, 
                                                  is_piecewise=True,
                                                  pieces=[{"min": 50000}, 
                                                          {"min": 5000, "max": 50000},
                                                          {"min": 500, "max": 5000},
                                                          {"min": 10, "max": 500},
                                                          {"max": 10} ],
                                                  range_color=['blue', 'green', 'green', 'yellow', 'red']),
                graphic_opts=[opts.GraphicGroup(
                                                graphic_item=opts.GraphicItem(
                                                    rotation=JsCode("Math.PI / 4"),
                                                    bounding="raw",
                                                    right=110,
                                                    bottom=110,
                                                    z=100,
                                                ),
                                                children=[
                                                    opts.GraphicRect(
                                                        graphic_item=opts.GraphicItem(
                                                            left="center", top="center", z=100
                                                        ),
                                                        graphic_shape_opts=opts.GraphicShapeOpts(
                                                            width=400, height=50
                                                        ),
                                                        graphic_basicstyle_opts=opts.GraphicBasicStyleOpts(
                                                            fill="rgba(0,0,0,0.3)"
                                                        ),
                                                    ),
                                                    opts.GraphicText(
                                                        graphic_item=opts.GraphicItem(
                                                            left="center", top="center", z=100
                                                        ),
                                                        graphic_textstyle_opts=opts.GraphicTextStyleOpts(
                                                            text=day,
                                                            font="bold 26px Microsoft YaHei",
                                                            graphic_basicstyle_opts=opts.GraphicBasicStyleOpts(
                                                                fill="#fff"
                                                            ),
                                                        ),
                                                    ),
                                                ],
                                            )
                                ],
            )
    )

    tl.add(geo, day)

tl.render_notebook()

海外疫情

海外疫情趋势

在国内疫情得到有效控制的时候,海外地区却开始呈现爆发趋势。

代码语言:javascript复制
def oversea_top(day=date.today(), top=10, d_type='confirmedCount'):
    oversea_data = filter(lambda x: x[0]!='全国' and x[1]['is_city']==0 and x[1]['countryName']!='中国', 
                          format_data[day].items())
    oversea_data = sorted(oversea_data, key=lambda x: x[1]['confirmedCount'],  reverse=True)[:top]
    oversea_data = [(x[0], x[1][d_type]) for x in oversea_data]
    return oversea_data
代码语言:javascript复制
tl = Timeline(init_opts=opts.InitOpts(theme='dark', width='400'))
tl.add_schema(axis_type='time', is_timeline_show=True,is_rewind_play=True, is_inverse=True,
             label_opts=opts.LabelOpts(is_show=False))

for day in time_range[::-1]:
    oversea_data = oversea_top(day)[::-1]
    if oversea_data:
        bar = (
            Bar(init_opts=opts.InitOpts(theme='dark'))
            .add_xaxis([x[0] for x in oversea_data])
            .add_yaxis("", [x[1] for x in oversea_data])
            .set_series_opts(label_opts=opts.LabelOpts(is_show=True, 
                                                       position='insideRight',
                                                       font_style='italic'),
                            itemstyle_opts=opts.ItemStyleOpts(
                                color=JsCode("""new echarts.graphic.LinearGradient(1, 0, 0, 0, 
                                             [{
                                                 offset: 0,
                                                 color: 'rgb(255,99,71)'
                                             }, {
                                                 offset: 1,
                                                 color: 'rgb(32,178,170)'
                                             }])"""))
                            )
            .set_global_opts(
                title_opts=opts.TitleOpts(title="新型冠状病毒海外主要国家确诊情况",
                                         subtitle="更新日期:{}".format(update_date)),
                xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)),
                legend_opts=opts.LegendOpts(is_show=True),
                graphic_opts=[opts.GraphicGroup(graphic_item=opts.GraphicItem(
                                                   rotation=JsCode("Math.PI / 4"),
                                                   bounding="raw",
                                                   right=110,
                                                   bottom=110,
                                                   z=100),
                                               children=[
                                                   opts.GraphicRect(
                                                       graphic_item=opts.GraphicItem(
                                                           left="center", top="center", z=100
                                                       ),
                                                       graphic_shape_opts=opts.GraphicShapeOpts(
                                                           width=400, height=50
                                                       ),
                                                       graphic_basicstyle_opts=opts.GraphicBasicStyleOpts(
                                                           fill="rgba(0,0,0,0.3)"
                                                       ),
                                                   ),
                                                   opts.GraphicText(
                                                       graphic_item=opts.GraphicItem(
                                                           left="center", top="center", z=100
                                                       ),
                                                       graphic_textstyle_opts=opts.GraphicTextStyleOpts(
                                                           text=day,
                                                           font="bold 26px Microsoft YaHei",
                                                           graphic_basicstyle_opts=opts.GraphicBasicStyleOpts(
                                                               fill="#fff"
                                                           ),
                                                       ),
                                                   ),
                                               ],
                                            )
                                    ],)
            .reversal_axis()
        )
        tl.add(bar, day)

tl.render_notebook()

海外主要国家确诊/治愈率/死亡率趋势

代码语言:javascript复制
country_list = ['韩国', '日本', '伊朗', '新加坡', '意大利']
date_list = [date.today()   datetime.timedelta(days=-i) for i in range(14)][::-1]
tab = Tab()

for country in country_list:
    cofirm = area_data(area_name=country, type_='confirmedCount', date_list=date_list)
    dead = area_data(area_name=country, type_='deadCount', date_list=date_list)
    cured = area_data(area_name=country, type_='curedCount', date_list=date_list)
    dead_rate = [i/j if j != 0 else 0. for i, j in zip(dead, cofirm)]
    cure_rate = [i/j if j != 0 else 0. for i, j in zip(cured, cofirm)]


    line = (Line(init_opts=opts.InitOpts(theme='dark'))
            .add_xaxis(date_list)
            .add_yaxis("死亡率", dead_rate, yaxis_index=1, is_smooth=True, color='red')
            .add_yaxis("治愈率", cure_rate, yaxis_index=1, is_smooth=True, color='green')
            .extend_axis(yaxis=opts.AxisOpts(
                    name="",
                    type_="value",
                    min_=0,
                    max_=max([max(cure_rate),max(dead_rate)])*1.2,
                    position="right",
                    axislabel_opts=opts.LabelOpts(
                                    formatter=JsCode("""function (value) 
                                                    {return Number(value *100) '%';}""")),)
            )
            .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
            .set_global_opts(
                    title_opts=opts.TitleOpts(title="【{}】确诊/治愈率/死亡率 趋势".format(country),
                                             subtitle="更新日期:{}".format(update_date)),
                    tooltip_opts=opts.TooltipOpts(formatter=JsCode("""function (params) 
                                                    {return Number(params.value[1] *100).toFixed(3) '%';}""")),
                    xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)),
                    legend_opts=opts.LegendOpts(is_show=True)
                    )
        )

    bar = (Bar()
                .add_xaxis(date_list)
                .add_yaxis("确诊病例", cofirm, yaxis_index=0)
                .set_series_opts(label_opts=opts.LabelOpts(is_show=True, 
                                                           position='top',
                                                           font_style='italic'),
                                itemstyle_opts=opts.ItemStyleOpts(opacity=0.8,
                                    color=JsCode("""new echarts.graphic.LinearGradient
                                                (0, 0, 0, 1, 
                                                 [{
                                                     offset: 0,
                                                     color: 'rgb(255,99,71)'
                                                 }, {
                                                     offset: 1,
                                                     color: 'rgb(32,178,170)'
                                                 }])"""))
                                )
                )
    line.overlap(bar)

    tab.add(line, country)

tab.render_notebook()

0 人点赞