[可视化]2020年奥运会数据可视化

「这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战

本文基于所获取的2020年奥运会相关数据,利用pandas和pyecharts制作静态可视化大屏

设计大屏布局

地图

地图绘制比较较简单,直接将数据中的英文名称奖牌总数作为map数据就可直接实现地图绘制

图例相比于热力值显示,采用了三等分的方式,获奖数量体现更直观

后续大部分图表都采用light这个主题

import pandas as pd
from pyecharts import options as opts
from pyecharts.charts import Map

df = pd.read_excel("奖牌榜单数据集.xlsx")
data = [[i,j] for i,j in zip(df['英文名称'], df['奖牌总数'])]

charts =  Map(init_opts=opts.InitOpts(theme='light'))
charts.add("奖章总数", data, "world",is_map_symbol_show=False)
charts.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
charts.set_global_opts(title_opts=opts.TitleOpts(title="2020东京奥运会各国金牌分布图"),
                       visualmap_opts=opts.VisualMapOpts(max_=120,is_piecewise=True,split_number=3))
charts.render_notebook()
复制代码

横向堆叠图

展现TOP10的奖牌榜单采用了横向堆叠图的形式,jpyecharts将绘图横向图片的时候会调用reversal_axis()函数,这时候要注意此时数据也需要reverse,所以在处理数据的时候采用[::-1]将数据reverse一下。

色彩搭配笔者弱鸡一枚,对应金牌,银牌,铜牌找三个能看的颜色匹配了一下。

from pyecharts.charts import Bar
from pyecharts import options as opts

df = pd.read_excel("奖牌榜单数据集.xlsx")
df = df.sort_values(by="奖牌总数",axis=0,ascending=False)
nation = df['名称'].values[:10][::-1].tolist()
gold = df['金牌'].values[:10][::-1].tolist()
silver = df['银牌'].values[:10][::-1].tolist()
copper = df['铜牌'].values[:10][::-1].tolist()

bar = Bar(init_opts=opts.InitOpts(width='1000px',height='600px'))
bar.add_xaxis(nation)
# stack值一样的系列会堆叠在一起
bar.add_yaxis('金牌', gold, stack='stack1',category_gap="50%",color="#e5b751")
bar.add_yaxis('银牌', silver, stack='stack1',category_gap="50%",color="#f1f0ed")
bar.add_yaxis('铜牌', copper, stack='stack1',category_gap="50%",color="#fed71a")
bar.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
bar.set_global_opts(title_opts=opts.TitleOpts(title="东京奥运会奖牌榜TOP10"))
bar.reversal_axis()
bar.render_notebook()
复制代码

饼图

饼图展示中国各比赛项目的获奖情况,

数据部分定位到中国后,采用groupby取统计项目名称做一个降序排列就好。

利用枚举的序列i对每个饼图设置XY的位置

import pandas as pd
from pyecharts import options as opts
from pyecharts.charts import Pie

df = pd.read_excel("参赛运动员数据集.xlsx")
region_list = ["中国", "中国香港", "中国台北"]
titles = []
pie = Pie(
    init_opts=opts.InitOpts(
        theme='light',
        width='1000px',
        height='800px',
    )
)
for i,r in enumerate(region_list):
    
    sortdata = df[df["国家"]== r].groupby('项目名')['项目名'].count().sort_values(0, ascending=False)
    names = sortdata.index.tolist()
    values = sortdata.values.tolist()
    dataItem = [list(z) for z in zip(names,  values)]
    
    pos_x = '{}%'.format(int(i / 3) * 33 + 18)
    pos_y = '{}%'.format(i % 3 * 28 + 33)
    
    titles.append(dict(text=r+' ',
                       left=pos_x,
                       top=pos_y,
                       textAlign='center',
                       textVerticalAlign='middle',
                       textStyle=dict(color='#603d30',fontSize=12))
                 )
    
    pie.add(
        r,
        dataItem,
        center=[pos_x, pos_y],
        radius=['8%', '12%'],
        label_opts=opts.LabelOpts(is_show=True,formatter='{b}:{d}%')
    )
    


pie.set_global_opts(
    legend_opts=opts.LegendOpts(is_show=False),
    title_opts=titles)
pie.render_notebook()
复制代码

时间轴

学习自AwesomeTang大佬的制作方法

df = pd.read_excel("参赛运动员数据集.xlsx")
y_data = []
counter = 0
position = ['left', 'right']
for idx, row in df[(df['英文缩写']=='CHN') & (df['金牌类型']==1)].iterrows():
    msg = '{bbb|%s}\n{aaa|%s}\n{bbb|%s/%s}' % (row['获奖时间'][:10], row['运动员'], row['项目名'], row['子项目名称'])
    # 单个数据项配置
    l_item = opts.LineItem(
        name=10,
        value=counter,
        symbol='emptyCircle',
        symbol_size=10,
        label_opts=opts.LabelOpts(
            is_show=True, 
            font_size=16,
            position=position[counter%2], 
            formatter=msg,
            rich = {
                'aaa': {
                    'fontSize': 18, 
                    'color': 'red', 
                    'fontWeight':'bold', 
                    'align':position[(counter+1)%2],
                    },
                'bbb': {
                    'fontSize': 15, 
                    'color': '#000', 
                    'align':position[(counter+1)%2]}}
            )
    )
    y_data.append(l_item)
    counter+=1
    
line = Line(
    init_opts=opts.InitOpts(
        theme='light',
        width='1000px',
        height='2000px',
        bg_color='white'
    )
)
line.add_xaxis(
    ['CHN']
)
line.add_yaxis(
    '',
    y_data,
    linestyle_opts={
        'normal': {
            'width': 4,  # 设置线宽
            'color':'red',
            'shadowColor': 'rgba(155, 18, 184, .3)',  # 阴影颜色
            'shadowBlur': 10,  # 阴影大小
            'shadowOffsetY': 10,  # Y轴方向阴影偏移
            'shadowOffsetX': 10,  # x轴方向阴影偏移
        }
    },
    itemstyle_opts={
        'normal': {
            'color':'red',
            'shadowColor': 'rgba(155, 18, 184, .3)',  # 阴影颜色
            'shadowBlur': 10,  # 阴影大小
            'shadowOffsetY': 10,  # Y轴方向阴影偏移
            'shadowOffsetX': 10,  # x轴方向阴影偏移
        }
    },
    tooltip_opts=opts.TooltipOpts(is_show=False)
)

line.set_global_opts(
    xaxis_opts=opts.AxisOpts(is_show=False, type_='category'),
    yaxis_opts=opts.AxisOpts(is_show=False, type_='value', max_=len(y_data)),
    title_opts=opts.TitleOpts(
        title="夺金时刻", pos_left='center', pos_top='2%',
        title_textstyle_opts=opts.TextStyleOpts(color='red', font_size=20)
    ),
    graphic_opts=[
                opts.GraphicGroup(
                            graphic_item=opts.GraphicItem(id_='1',left="center", top="center", z=-1),
                            children=[# tokyo 
                                    opts.GraphicImage(graphic_item=opts.GraphicItem(id_="logo",
                                                                                    left='center',
                                                                                    z=-1),
                                                      graphic_imagestyle_opts=opts.GraphicImageStyleOpts(
                                        image="https://olympics.com/tokyo-2020/en/d3images/emblem/olympics/emblem-tokyo2020.svg",
                                        width=800,
                                        height=1000,
                                        opacity=0.1,)
                                    )
                                ]
                                )
                                ]
)
line.render_notebook()
复制代码

数据大屏布局

将上面四个张图表修改为函数,使用Page进行组合图表

完整代码

# https://www.233tw.com/python/59145
import pandas as pd
from pyecharts import options as opts
from pyecharts.charts import *


def map_world()-> Map:
    df = pd.read_excel("奖牌榜单数据集.xlsx")
    data = [[i,j] for i,j in zip(df['英文名称'], df['奖牌总数'])]

    charts =  Map()
    charts.add("奖章总数", data, "world",is_map_symbol_show=False)
    charts.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    charts.set_global_opts(title_opts=opts.TitleOpts(title="2020东京奥运会各国金牌分布图"),
                           visualmap_opts=opts.VisualMapOpts(max_=120,is_piecewise=True,split_number=3))
    return charts

def bar_medals()->Bar:
    df = pd.read_excel("奖牌榜单数据集.xlsx")
    df = df.sort_values(by="奖牌总数",axis=0,ascending=False)
    nation = df['名称'].values[:10][::-1].tolist()
    gold = df['金牌'].values[:10][::-1].tolist()
    silver = df['银牌'].values[:10][::-1].tolist()
    copper = df['铜牌'].values[:10][::-1].tolist()

    bar = Bar(init_opts=opts.InitOpts(width='1000px',height='600px'))
    bar.add_xaxis(nation)
    # stack值一样的系列会堆叠在一起
    bar.add_yaxis('金牌', gold, stack='stack1',category_gap="50%",color="#e5b751")
    bar.add_yaxis('银牌', silver, stack='stack1',category_gap="50%",color="#f1f0ed")
    bar.add_yaxis('铜牌', copper, stack='stack1',category_gap="50%",color="#fed71a")
    bar.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    bar.set_global_opts(title_opts=opts.TitleOpts(title="东京奥运会奖牌榜TOP10"))
    bar.reversal_axis()
    return bar

def pie_china()->Pie:
    df = pd.read_excel("参赛运动员数据集.xlsx")
    region_list = ["中国", "中国香港", "中国台北"]
    titles = []
    pie = Pie(
        init_opts=opts.InitOpts(
            theme='light',
            width='1000px',
            height='800px',
        )
    )
    for i,r in enumerate(region_list):

        sortdata = df[df["国家"]== r].groupby('项目名')['项目名'].count().sort_values(0, ascending=False)
        names = sortdata.index.tolist()
        values = sortdata.values.tolist()
        dataItem = [list(z) for z in zip(names,  values)]
        pos_x = '{}%'.format(int(i / 3) * 33 + 18)
        pos_y = '{}%'.format(i % 3 * 28 + 33)
        titles.append(dict(text=r+' ',
                           left=pos_x,
                           top=pos_y,
                           textAlign='center',
                           textVerticalAlign='middle',
                           textStyle=dict(color='#603d30',fontSize=12)))
        pie.add(r,dataItem,center=[pos_x, pos_y],radius=['8%', '12%'],label_opts=opts.LabelOpts(is_show=True,formatter='{b}:{d}%'))
    pie.set_global_opts(legend_opts=opts.LegendOpts(is_show=False),title_opts=titles)
    return pie

def timeline()->Line:
    df = pd.read_excel("参赛运动员数据集.xlsx")
    y_data = []
    counter = 0
    position = ['left', 'right']
    for idx, row in df[(df['英文缩写']=='CHN') & (df['金牌类型']==1)].iterrows():
        msg = '{bbb|%s}\n{aaa|%s}\n{bbb|%s/%s}' % (row['获奖时间'][:10], row['运动员'], row['项目名'], row['子项目名称'])
        # 单个数据项配置
        l_item = opts.LineItem(
            name=10,
            value=counter,
            symbol='emptyCircle',
            symbol_size=10,
            label_opts=opts.LabelOpts(
                is_show=True, 
                font_size=16,
                position=position[counter%2], 
                formatter=msg,
                rich = {
                    'aaa': {
                        'fontSize': 18, 
                        'color': 'red', 
                        'fontWeight':'bold', 
                        'align':position[(counter+1)%2],
                        },
                    'bbb': {
                        'fontSize': 15, 
                        'color': '#000', 
                        'align':position[(counter+1)%2]}}
                )
        )
        y_data.append(l_item)
        counter+=1

    line = Line(
        init_opts=opts.InitOpts(
            theme='light',
            width='1000px',
            height='2000px',
            bg_color='white'
        )
    )
    line.add_xaxis(
        ['CHN']
    )
    line.add_yaxis(
        '',
        y_data,
        linestyle_opts={
            'normal': {
                'width': 4,  # 设置线宽
                'color':'red',
                'shadowColor': 'rgba(155, 18, 184, .3)',  # 阴影颜色
                'shadowBlur': 10,  # 阴影大小
                'shadowOffsetY': 10,  # Y轴方向阴影偏移
                'shadowOffsetX': 10,  # x轴方向阴影偏移
            }
        },
        itemstyle_opts={
            'normal': {
                'color':'red',
                'shadowColor': 'rgba(155, 18, 184, .3)',  # 阴影颜色
                'shadowBlur': 10,  # 阴影大小
                'shadowOffsetY': 10,  # Y轴方向阴影偏移
                'shadowOffsetX': 10,  # x轴方向阴影偏移
            }
        },
        tooltip_opts=opts.TooltipOpts(is_show=False)
    )

    line.set_global_opts(
        xaxis_opts=opts.AxisOpts(is_show=False, type_='category'),
        yaxis_opts=opts.AxisOpts(is_show=False, type_='value', max_=len(y_data)),
        title_opts=opts.TitleOpts(
            title="夺金时刻", pos_left='center', pos_top='2%',
            title_textstyle_opts=opts.TextStyleOpts(color='red', font_size=20)
        ),
        graphic_opts=[
                    opts.GraphicGroup(
                                graphic_item=opts.GraphicItem(id_='1',left="center", top="center", z=-1),
                                children=[# tokyo 
                                        opts.GraphicImage(graphic_item=opts.GraphicItem(id_="logo",
                                                                                        left='center',
                                                                                        z=-1),
                                                          graphic_imagestyle_opts=opts.GraphicImageStyleOpts(
                                            image="https://olympics.com/tokyo-2020/en/d3images/emblem/olympics/emblem-tokyo2020.svg",
                                            width=800,
                                            height=1000,
                                            opacity=0.1,)
                                        )
                                    ]
                                    )
                                    ]
    )
    return line

page = Page(layout=Page.DraggablePageLayout, page_title="2020东京奥运会数据可视化")

# 在页面中添加图表
page.add(
    timeline(),
    map_world(),
    bar_medals(),
    pie_china(),

)
page.load_javascript()
page.render("draghtmlpage.html")
复制代码

将布局设置为Page.DraggablePageLayout可以拖拽其中的图片自定义布局。

打开保存的html自定义布局,布局完成后点击save config对布局参数保存其json文件。

最后,运行下面一行代码,调用保存好的布局文件,重新生成html

a = page.save_resize_html('draghtmlpage.html', cfg_file='chart_config.json', dest='奥运.html')
复制代码

效果:

初步实现数据可视化大屏展示,还是有很多不足,才疏学浅,有错误或者不完善的地方,请批评指正!!

参考资料:

[1] 【2020东京奥运会】数据可视化~

[2] 手把手教你用 pandas 分析可视化东京奥运会数据

[3] Python制作可视化大屏(东京奥运会)

猜你喜欢

转载自juejin.im/post/7033028728628510727