0
点赞
收藏
分享

微信扫一扫

122 11 个案例掌握 Python 数据可视化--疫情综合看板

尤克乔乔 2021-09-28 阅读 47

疫情综合看板

对于数据维度较多的大项目,绘制一张看板并动态查看各要素信息是非常有必要的。在此问题领域 Pyecharts 包是较好的解决方案,本实验以 1 -7 月份国内外新冠疫情数据为基础,详细地讲解了看板各要素设计的步骤和需要注意的问题。
屏蔽 Pyecharts 版本相关的报警。

import warnings
warnings.filterwarnings("ignore")

数据集介绍

本数据集来自 GitHub项目 ,本实验对项目中 xlsx 文件夹中国内数据和全球数据进行了相关字段数据的合并和清洗。导入数据并查看前 5 行。

import pandas as pd
df = pd.read_excel('https://labfile.oss.aliyuncs.com/courses/3023/China_world_cov.xlsx')
df['date']=df['date'].dt.date
df.head()

定义条形图函数

!pip install pyecharts==1.7.1

Pyecharts 看板的绘制是相对复杂的过程,如果各子图本身存在代码问题,则进行渲染时,将无法显示渲染结果,因此强烈建议在进行整体看板图设计时,先对各子图的代码逐一检查,看各子图是否能独立绘制完成。

以下定义了本实验中涉及条形图绘制的函数,需要注意的是:
当绘制单张条形图时,Bar 对象会自动分配各系列的 x 坐标轴索引号(xaxis_index),和 y 坐标轴索引号(yaxis_index);
xaxis_index 和 yaxis_index 索引号默认都是以 0 开始;
当条形图与其他带坐标轴的对象(折线图、条形图等)同时作为子图被加入画布时,需要注意索引号不能重复且不能断号;
定义函数时,对于全局变量(set_global_opts)相关参数,尽量不在函数中进行配置,以增加对象的灵活性。

from pyecharts import options as opts
from pyecharts.charts import Bar
def building_bar(data, xaxis_index=0, yaxis_index=0):
    bar = Bar()
    bar.add_xaxis(list(data.index))
    bar.add_yaxis(" ", list(data), xaxis_index=xaxis_index, yaxis_index=yaxis_index,
                  label_opts=opts.LabelOpts(is_show=False))
    return bar

绘制全国各省确诊人数趋势图

通过函数创建条形图并进行全局变量的配置,本实验可视化了 4 月全国各省新冠确诊人数并降序排列。

# 构建数据集
month = 4
data = df
china = data.loc[data['countryName'] == '中国']
china_p_confirm = china.loc[china['month'] == month].groupby(['provinceShortName'])[
    'confirmedIncr'].sum().sort_values(ascending=False)
# 构建条形图
china_p_bar = building_bar(china_p_confirm)
# 修饰条形图
china_p_bar.set_global_opts(
    # 标题的修饰
    title_opts=opts.TitleOpts(
        title='中国各省%d月确诊人数' % month),
    # 图例的修饰
    legend_opts=opts.LegendOpts(is_show=False),
    # x 坐标轴的修饰
    xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=18)),
    # y 坐标轴的修饰
    yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=18)),
    # 数据缩放的设置
    datazoom_opts=opts.DataZoomOpts(range_start=0, range_end=30),
)
china_p_bar.render_notebook()

绘制全球各国确诊人数趋势图

与实验「绘制全国各省确诊人数趋势图」相同的过程,可视化了全球各国家 4 月份确诊人数并降序排列。

month = 4
data = df
world = data.loc[data['countryName'] != '中国']
world

county_confirm = world.loc[world['month'] == month].groupby(['countryName'])[
    'confirmedIncr'].sum().sort_values(ascending=False)
county_bar = building_bar(county_confirm)
county_bar.set_global_opts(
    title_opts=opts.TitleOpts(title='全球各国%d月确诊人数' % month),
    legend_opts=opts.LegendOpts(is_show=False),
    xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=18)),
    yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(font_size=18)),
    datazoom_opts=opts.DataZoomOpts(range_start=0, range_end=10),
)

county_bar.render_notebook()

定义多系列折线图函数

Pyecharts 折线图对象可以实现多系列不同量纲数据的同时显示,在进行接口调用时需要注意以下几个方面:
若多系列是 y 轴方向上的数据,则每个系列对应的 x 数据必须是唯一的;
x 轴数据通过接口 .add_xaxis() 进行添加,y 轴数据通过 .add_yaxis() 接口添加;
当折线图作为子图与其他对象合并时,添加 x 轴数据时须明确索引(xaxis_index),添加 y 轴数据时须明确各系列的名称(series_name)及索引(yaxis_index);
通过 .add_yaxis() 接口添加的第 1 个序列为主序列,其 y 轴坐标轴通过 .set_global_opts() 接口进行设置;
剩下的序列为次坐标序列,y 轴坐标轴通过 .extend_axis() 接口进行设置。

from pyecharts.charts import Line
import matplotlib.colors as cs
def building_line(seriess, data):
    line = Line()
    # 设置多系列的颜色顺序
    colors = [value for value in cs.TABLEAU_COLORS.values()]
    # 添加X轴数据
    line.add_xaxis(xaxis_data=data.index)
    # 添加多系列Y轴数据
    for i, series in enumerate(seriess):
        line.add_yaxis(
            series_name=series,
            y_axis=data[series],
            symbol="emptyCircle",
            is_symbol_show=True,
            xaxis_index=0,  # 将所有折线图的X轴索引设置为0
            yaxis_index=i,  # 新增的Y轴数据逐次设置索引值
            label_opts=opts.LabelOpts(is_show=False),
            linestyle_opts=opts.LineStyleOpts(width=3, color=colors[i]),
        )

    # 次坐标Y轴的设置
    for j, series_y in enumerate(seriess[1:]):
        line.extend_axis(
            # x数据
            xaxis_data=data.index,
            # 次坐标轴,主要是y轴的设置
            yaxis=opts.AxisOpts(
                type_="value",
                name=series_y,
                offset=j*100-70,
                axisline_opts=opts.AxisLineOpts(
                    linestyle_opts=opts.LineStyleOpts(color=colors[j+1])
                ),
                name_textstyle_opts=opts.LabelOpts(),
                axislabel_opts=opts.LabelOpts(color=colors[j+1])
            )
        )
    # 主坐标Y轴的设置
    line.set_global_opts(
        xaxis_opts=opts.AxisOpts(type_="category",),
        yaxis_opts=opts.AxisOpts(
            type_="value",
            name=seriess[0],
            axistick_opts=opts.AxisTickOpts(is_show=True),
            splitline_opts=opts.SplitLineOpts(is_show=True),
            axisline_opts=opts.AxisLineOpts(   # 轴刻度线的设置
                linestyle_opts=opts.LineStyleOpts(color=colors[0])),
            axislabel_opts=opts.LabelOpts(
                is_show=True, color=colors[0]),  # 轴标签的设置
        )
    )
    return line

绘制全国某月死亡/确诊/治愈人数

调用折线图函数,进行某月死亡/确诊/治愈人数趋势图的绘制。

month = 3
data = df
china = data.loc[data['countryName'] == '中国']
line_china = china.loc[china['month'] == month].groupby(
    ['date'])['deadIncr', 'confirmedIncr', 'curedIncr'].sum()
line = building_line(seriess=['deadIncr', 'confirmedIncr',
                              'curedIncr'], data=line_china)
line.set_global_opts(
    legend_opts=opts.LegendOpts(pos_top="15%", pos_right="20%"),
    title_opts=opts.TitleOpts(
        title='中国各省%d月死亡/确诊/治愈人数' % month, pos_top="5%", pos_left="35%"),
)

line.render_notebook()

定义全国各省确诊人数地图

在前几次课程中,我们已经多次用到过 Map 对象,但都是单张图或简单拼接图,当需要多子图拼接时,Map 地图有 2 个参数尤其关键:
参数 zoom 。 用以调节地图的缩放比例,默认为1,当子图较多时,可通过调节 zoom 减小地图的尺寸;
参数 center 。用以调节地图中心的经纬度,默认情况下,中国地图的正中心(大约湖北省的某个位置)会出现在画布中心,但有时我们希望地图显示在左上角,可通过调节 center 经纬度至台湾省附近的某个经纬度实现。

from pyecharts.charts import Map

def building_map(data_pair, center=None, zoom=1):
    m = Map()
    m.add(
        series_name="",
        data_pair=data_pair,
        maptype='china',
        label_opts=opts.LabelOpts(is_show=False),
        is_map_symbol_show=False,
        center=center,
        zoom=zoom,

    )
    return m

绘制全国各省确诊人数地图

本实验采用默认参数绘制了全国 3 月份各省确诊人数热力地图,并进行了相关热力图参数的设置。

month = 3
data = df
china = data.loc[data['countryName'] == '中国']
china_p_confirm = china.loc[china['month'] == month].groupby(['provinceShortName'])[
    'confirmedIncr'].sum().sort_values(ascending=False)
data_pair = [[province, value]
             for province, value in zip(china_p_confirm.index, china_p_confirm)]

visualmap_opts = opts.VisualMapOpts(
    is_calculable=True,
    pos_top="20%",
    pos_left="5%",
    min_=china_p_confirm.min(),  # 最小数字
    max_=china_p_confirm[1]*1.1,   # 第二大数字+10%
    range_text=["High", "Low"],
    range_color=[cs.TABLEAU_COLORS['tab:blue'],   # 颜色渐变范围最小值为蓝色,依次为橘色,最大值为红色
                 cs.TABLEAU_COLORS['tab:orange'],
                 cs.TABLEAU_COLORS['tab:red']],
    textstyle_opts=opts.TextStyleOpts(color="black"),
)

m = building_map(data_pair=data_pair)

m.set_global_opts(
    title_opts=opts.TitleOpts(
        title='中国各省%d月确诊人数' % month, pos_top="5%", pos_left="35%"),
    visualmap_opts=visualmap_opts
)

m.render_notebook()

合并以上各子图

通过 Grid 对象将以上绘图对象进行合并,合并时需要注意以下方面问题:
通过 .add() 接口添加各子图时,需要注意各子图的 xaxis_index 和 yaxis_index(前序实验已做仔细介绍)的顺序号,需要从索引号为 0 的图依次添加;
第一个通过 .add() 接口添加的子图,该子图负责调用 .set_global_opts() 接口对影响全局的相关参数进行设置,例如 visualmap_opts、 datazoom_opts 等参数;
其余被添加的子图除以上参数无法设置(或设置无效)外,可自行设置 title_opts、legend_opts 等参数。

from pyecharts.charts import Grid

month = 3


# ------------  构建折线图  --xaxis_index=0,yaxis_index=0,1,2------------#
line_china = china.loc[china['month'] == month].groupby(
   ['date'])['deadIncr', 'confirmedIncr', 'curedIncr'].sum()
line = building_line(seriess=['deadIncr', 'confirmedIncr',
                             'curedIncr'], data=line_china)

# ------------  构建全球条形图  --x=1,y=3------------#
county_confirm = world.loc[world['month'] == month].groupby(['countryName'])[
   'confirmedIncr'].sum().sort_values(ascending=False)
county_bar = building_bar(county_confirm, xaxis_index=1, yaxis_index=3)

# ------------  构建中国条形图  --x=2,y=4------------#
china_p_confirm = china.loc[china['month'] == month].groupby(['provinceShortName'])[
   'confirmedIncr'].sum().sort_values(ascending=False)
china_p_bar = building_bar(china_p_confirm, xaxis_index=2, yaxis_index=4)

# ------------  构建地图------------#
data_pair = [[province, value]
            for province, value in zip(china_p_confirm.index, china_p_confirm)]
m = building_map(data_pair=data_pair, center=[140, 20], zoom=0.6)


# ----------------  全局属性  ------------------#
visualmap_opts = opts.VisualMapOpts(
   is_calculable=True,
   pos_top="20%",
   pos_left="45%",
   min_=china_p_confirm.min(),  # 最小数字
   max_=china_p_confirm[1]*1.1,   # 第二大数字+10%
   range_text=["High", "Low"],
   range_color=[cs.TABLEAU_COLORS['tab:blue'],   # 颜色渐变范围最小值为蓝色,依次为橘色,最大值为红色
                cs.TABLEAU_COLORS['tab:orange'],
                cs.TABLEAU_COLORS['tab:red']],
   textstyle_opts=opts.TextStyleOpts(color="black"),
)

## ------------  全局修饰,添加的第一个对象负责对所有对象的全局参数设置------------##
line.set_global_opts(
   legend_opts=opts.LegendOpts(pos_top="58%", pos_right="60%"),
   title_opts=opts.TitleOpts(
       title='中国各省%d月死亡/确诊/治愈人数' % month, pos_top="55%", pos_left="15%"),
   visualmap_opts=visualmap_opts,
   datazoom_opts=[
       opts.DataZoomOpts(   # 控制全球条形图
           pos_bottom="55%",
           range_start=0,
           range_end=15,
           xaxis_index=[1],
       ),
       opts.DataZoomOpts(   # 控制中国条形图
           pos_bottom="1%",
           range_start=0,
           range_end=40,
           xaxis_index=[2]
       ),
       opts.DataZoomOpts(    # 控制折线图的
           pos_bottom="1%",
           pos_left="10%",
           range_start=0,
           range_end=300,
           xaxis_index=[0]
       )
   ],
)

# --------------------- 其他子图设置影响其自身的全局变量 --------------------------#
county_bar.set_global_opts(
   title_opts=opts.TitleOpts(
       title='全球各国%d月确诊人数' % month, pos_top="0%", pos_right="20%"),
   legend_opts=opts.LegendOpts(is_show=False)
)
china_p_bar.set_global_opts(
   title_opts=opts.TitleOpts(
       title='中国各省%d月确诊人数' % month, pos_top="50%", pos_right="20%"),
   legend_opts=opts.LegendOpts(is_show=False)

)
m.set_global_opts(
   title_opts=opts.TitleOpts(
       title='中国各省%d月确诊人数' % month, pos_top="1%", pos_left="20%"),

)


# ---------------------合并-----------------------------#
grid = Grid(init_opts=opts.InitOpts(width="1200px", height="800px"))

# 添加各绘图对象并调节位置
grid.add(line, is_control_axis_index=True, grid_opts=opts.GridOpts(
   pos_right="60%", pos_top="65%", pos_bottom="8%"))
grid.add(county_bar, is_control_axis_index=True, grid_opts=opts.GridOpts(
   pos_left="60%", pos_top="5%", pos_bottom="65%"))
grid.add(china_p_bar, is_control_axis_index=True, grid_opts=opts.GridOpts(
   pos_left="60%", pos_top="55%", pos_bottom="8%"))
grid.add(m, grid_opts=opts.GridOpts(
   pos_left="60%", pos_top="55%", pos_bottom="10%"))

grid.render_notebook()

鼠标按住并拖动运行结果图中热力图条的三角形按钮,可以发现,全局相关色块的对象均可被同步调节。

定义子图的看板函数

将合并的画布进一步封装成函数,函数的参数为月份 month 。

def get_month_grid(month):
    # ------------  构建折线图  --x=0,y=0,1,2------------#
    line_china = china.loc[china['month'] == month].groupby(
        ['date'])['deadIncr', 'confirmedIncr', 'curedIncr'].sum()
    line = building_line(seriess=['deadIncr', 'confirmedIncr',
                                  'curedIncr'], data=line_china)

    # ------------  构建全球条形图  --x=1,y=3------------#
    county_confirm = world.loc[world['month'] == month].groupby(['countryName'])[
        'confirmedIncr'].sum().sort_values(ascending=False)
    county_bar = building_bar(county_confirm, xaxis_index=1, yaxis_index=3)

    # ------------  构建中国条形图  --x=2,y=4------------#
    china_p_confirm = china.loc[china['month'] == month].groupby(['provinceShortName'])[
        'confirmedIncr'].sum().sort_values(ascending=False)
    china_p_bar = building_bar(
        china_p_confirm, xaxis_index=2, yaxis_index=4)

    # ------------  构建地图------------#
    data_pair = [[province, value]
                 for province, value in zip(china_p_confirm.index, china_p_confirm)]
    m = building_map(data_pair=data_pair, center=[140, 20], zoom=0.6)

    # ----------------  全局属性  ------------------#
    visualmap_opts = opts.VisualMapOpts(
        is_calculable=True,
        pos_top="20%",
        pos_left="45%",
        min_=china_p_confirm.min(),  # 最小数字
        max_=china_p_confirm[1]*1.1,   # 第二大数字+10%
        range_text=["High", "Low"],
        range_color=[cs.TABLEAU_COLORS['tab:blue'],   # 颜色渐变范围最小值为蓝色,依次为橘色,最大值为红色
                     cs.TABLEAU_COLORS['tab:orange'],
                     cs.TABLEAU_COLORS['tab:red']],
        textstyle_opts=opts.TextStyleOpts(color="black"),
    )

    ## ------------  全局修饰  ------------##
    line.set_global_opts(
        legend_opts=opts.LegendOpts(pos_top="58%", pos_right="60%"),
        title_opts=opts.TitleOpts(
            title='中国各省%d月死亡/确诊/治愈人数' % month, pos_top="55%", pos_left="15%"),
        visualmap_opts=visualmap_opts,  # 设置全局的色块-数据映射
        datazoom_opts=[
            opts.DataZoomOpts(   # 控制全球条形图
                pos_bottom="55%",
                range_start=0,
                range_end=20,
                xaxis_index=[1],
            ),
            opts.DataZoomOpts(   # 控制中国条形图
                pos_bottom="1%",
                range_start=0,
                range_end=60,
                xaxis_index=[2]
            ),
            opts.DataZoomOpts(    # 控制折线图
                pos_bottom="1%",
                pos_left="10%",
                range_start=0,
                range_end=300,
                xaxis_index=[0]
            )
        ],
    )

    county_bar.set_global_opts(
        title_opts=opts.TitleOpts(
            title='全球各国%d月确诊人数' % month, pos_top="0%", pos_right="20%"),
        legend_opts=opts.LegendOpts(is_show=False)
    )
    china_p_bar.set_global_opts(
        title_opts=opts.TitleOpts(
            title='中国各省%d月确诊人数' % month, pos_top="50%", pos_right="20%"),
        legend_opts=opts.LegendOpts(is_show=False)
    )
    m.set_global_opts(
        title_opts=opts.TitleOpts(
            title='中国各省%d月确诊人数' % month, pos_top="1%", pos_left="20%"),
    )

    # ---------------------合并-----------------------------#
    grid = Grid(init_opts=opts.InitOpts(width="1200px", height="800px"))

    grid.add(line, is_control_axis_index=True, grid_opts=opts.GridOpts(
        pos_right="60%", pos_top="65%", pos_bottom="8%"))   
    grid.add(county_bar, is_control_axis_index=True, grid_opts=opts.GridOpts(
        pos_left="60%", pos_top="5%", pos_bottom="65%"))   
    grid.add(china_p_bar, is_control_axis_index=True, grid_opts=opts.GridOpts(
        pos_left="60%", pos_top="55%", pos_bottom="8%"))  
    grid.add(m, grid_opts=opts.GridOpts(
        pos_left="60%", pos_top="55%", pos_bottom="10%"))

    return grid

添加月度时间线

通过调用 Timeline 对象,实现了带动画的看板绘制,可点击左上角三角形播放按钮播放各月疫情数据变化情况。

from pyecharts.charts import Timeline
import numpy as np
from pyecharts.globals import ThemeType

timeline = Timeline(
    init_opts=opts.InitOpts(
        width='1200px',
        height='750px',
        theme=ThemeType.ESSOS,  # 设置看板背景主题颜色
    )
)

# 调节时间刻度对象的位置
timeline.add_schema(play_interval=1200,
                    pos_top="5%",
                    pos_left="1%",
                    pos_right="65%",
                    pos_bottom="90%",                  
                   )  

for month in np.arange(1,8,1):
    grid=get_month_grid(month)
    timeline.add(grid, "{}月".format(month))


timeline.render_notebook()

文件保存

Pyecharts 中的所有绘图对象可以通过 .render() 接口保存,默认保存格式为 html 网页格式,当保存成网页格式时,可在打开网页后,右键,选择”图片另存为“进行图片的保存。

当我们需要保存图片格式(png,gif,jpeg)时,需要确保以下配置已正确安装( Windwos 环境 ):
phantomjs 的安装。下载地址 ,下载后直接解压到任一目录,并将 bin 所在目录添加到环境变量中;
node.js 的安装。一般能运行 Pyecharts 则说明已完成安装;
python 环境需安装 snapshot-phantomjs 库,运行 pip install snapshot-phantomjs 。 当速度较慢时,可以切换到豆瓣或者清华镜像安装此库。

并通过 pyecharts.render 的 make_snapshot 接口调用 snapshot_phantomjs 的 snapshot 引擎进行图片的生成与保存。

# 本地安装 snapshot_phantomjs
#pip install snapshot_phantomjs
from snapshot_phantomjs import snapshot
from pyecharts.render import make_snapshot

timeline = Timeline(
    init_opts=opts.InitOpts(
        width='1200px',
        height='750px',
        theme=ThemeType.ESSOS,  # 设置看板背景主题颜色
    )
)

# 调节时间刻度对象的位置
timeline.add_schema(play_interval=500,
                    pos_top="5%",
                    pos_left="1%",
                    pos_right="65%",
                    pos_bottom="90%",
                    )

for month in np.arange(1, 8, 1):
    grid = get_month_grid(month)
    timeline.add(grid, "%d月" % month)

# 生成网页并保存各种格式图片
make_snapshot(snapshot, timeline.render("a.html"), "./a.png")

# --------------- 以下文件格式请自行尝试 ------------------------#
# make_snapshot(snapshot, timeline.render(), "./a.jpeg")
# make_snapshot(snapshot, timeline.render(), "./a.pdf")
# make_snapshot(snapshot, timeline.render(), "./a.gif")
# make_snapshot(snapshot, timeline.render(), "./a.eps")
# make_snapshot(snapshot, timeline.render(), "./a.base64")

# 渲染到notebook
timeline.render_notebook()
举报

相关推荐

0 条评论