117 11 個(gè)案例掌握 Python 數(shù)據(jù)可視化--世衛(wèi)組織的錢從哪里來到哪里去

世衛(wèi)組織的錢從哪里來到哪里去

世界衛(wèi)生組織(WHO)是有影響力的全球性組織之一,本實(shí)驗(yàn)獲取了 WHO 官網(wǎng)發(fā)布的 2018 - 2019 年財(cái)政預(yù)算數(shù)據(jù),對(duì)其資金來源及使用情況做了分析,研究及可視化了其資金構(gòu)成、資助項(xiàng)目及資金流向等問題。
輸入并執(zhí)行魔法命令 %matplotlib inline 。

%matplotlib inline
import matplotlib.pyplot as plt
import warnings

warnings.filterwarnings("ignore") # 屏蔽報(bào)警

數(shù)據(jù)準(zhǔn)備

本數(shù)據(jù)集來自 WHO,WHO 在其官網(wǎng)向全球公開透明其資金來源情況以及援助項(xiàng)目情況。本數(shù)據(jù)集統(tǒng)計(jì)了在 2018 - 2019 年間指定自愿捐款(Specified voluntary contributions)向 WHO 捐助的資金及 WHO 使用其資金的情況。
導(dǎo)入數(shù)據(jù)進(jìn)行初步處理并查看前 5 行。

import pandas as pd

df=pd.read_excel('https://labfile.oss.aliyuncs.com/courses/3023/World_health_organization_clearning.xlsx')

# 添加各地區(qū)代碼對(duì)應(yīng)的地區(qū)全稱
cont_code_name={
    'AF':'Africa',
    'EM':'Eastern Mediterranean',
    'HQ':'Headquarters',
    'SE':'South East Asia',
    'EU':'Europe',
    'WP':'Western Pacific',
    'AM':'Americas',    
}

df['cont_name']=df['cont'].apply(lambda x:cont_code_name[x])

df.head()

從運(yùn)行結(jié)果可知,數(shù)據(jù)集由 5 個(gè)字段構(gòu)成,各字段解釋見下表:


image.png

世衛(wèi)組織的資金構(gòu)成

根據(jù) WHO 官方網(wǎng)站公開披露的 2018 - 2019 兩年預(yù)算顯示,WHO 的資金來源主要分為會(huì)費(fèi)分?jǐn)偅ˋssessed contributions)與接受捐贈(zèng)兩種形式,接受捐贈(zèng)又分為指定自愿捐款(Specified voluntary contributions),核心自愿捐助(Core voluntary contributions),PIP 捐款(PIP Contributions)。
運(yùn)行以下代碼,可視化 WHO 的資金來源結(jié)構(gòu)。

plt.rcParams['figure.figsize'] = (10, 6)

funding_structure = {
    'Assessed contributions': 956900000,
    'Specified voluntary contributions': 4328057662,
    'Core voluntary contributions': 160592410.5,
    'PIP Contributions': 178053223,
}

plt.pie(
    x=funding_structure.values(),
    labels=funding_structure.keys(),  # 標(biāo)簽值
    explode=[0.1, 0, 0, 0],  # 餅圖中每一塊相對(duì)中心的偏移
    textprops={'size': 20},  # 餅圖中文本格式的設(shè)置
    autopct='%.2f%%'  # 文本字符顯示格式
)

plt.title('The Contributor Funding Structure of World Health Organization', size=22)

從運(yùn)行結(jié)果可知,WHO 成員國會(huì)費(fèi)占其總預(yù)算比例相對(duì)較低,只有 17%,剩余部分全部來源于自愿捐款,而本實(shí)驗(yàn)數(shù)據(jù)集涉及的指定自愿捐款(Specified voluntary contributions)占到所有捐款的比例最高,為總預(yù)算的 76.96% 。

資助組織及被資助項(xiàng)目結(jié)構(gòu)

按資金流向分組聚合,并將聚合結(jié)果歸一化后拼接。

import numpy as np
# 篩選出流入 WHO 的資金,按資助組織進(jìn)行資助金額的求和并逆序排序
funding_from = df.loc[df['direction'] == 'from'].groupby(
    ['orgs'])['money'].sum().sort_values(ascending=False)
# 將資金歸一化處理
funding_from = funding_from/np.sum(funding_from)

# 同樣的方式處理被資助項(xiàng)目
funding_to = df.loc[df['direction'] == 'to'].groupby(
    ['orgs'])['money'].sum().sort_values(ascending=False)
funding_to = funding_to/np.sum(funding_to)

# 將兩個(gè)Series對(duì)象按列拼接
funding_from_to = pd.concat([funding_from, funding_to])
# 展示處理后的數(shù)據(jù)
funding_from_to

資助組織及被資助項(xiàng)目金額經(jīng)過歸一化后,其求和值均為 1 ,因此將其可視化到餅圖時(shí),每一部分的占比會(huì)被壓縮到一半(因?yàn)轱瀳D的總百分比是 100%,但是兩部分求和結(jié)果是 200%)。例如,美國(United States of America)在所有資助組織中資助的金額占比為 15.17%,但經(jīng)拼接后在 funding_from_to 數(shù)據(jù)并可視化到餅圖后,其占比將縮小至 7.585%,因此為了顯示 15.17% 數(shù)據(jù),需要在 plt.pie 接口參數(shù) autopct 傳入格式化函數(shù) autopct_fun,該函數(shù)將顯示的百分比數(shù)據(jù)擴(kuò)大為原值的 2 倍。

plt.rcParams['figure.figsize'] = (15, 15)


def autopct_fun(x):
    return '%.2f%%' % (2*x)


plt.pie(x=funding_from_to,
        labels=funding_from_to.index,
        textprops={'size': 17},
        autopct=autopct_fun)

plt.title(
    'Where Does the World Health Organization Contributor Funding From and Go ?', size=28)

上面的圖中因?yàn)轭悇e太多,導(dǎo)致 label 都擠在一起看不清。下面我們對(duì)上面的圖像進(jìn)行簡化。 具體的 index 的編號(hào)可以通過 np.where 來找到。

plt.rcParams['figure.figsize'] = (14, 7)


def autopct_fun(x):
    if 2*x < 8:
        return None
    else:
        return '%.2f%%' % (2*x)


plt.pie(x=funding_from_to.values,
        labels=list(funding_from_to.index[0:4]) + ['' for i in funding_from_to.index[4:301]] + list(
            funding_from_to.index[301:304]) + ['' for i in funding_from_to.index[304:]],
        textprops={'size': 13},
        autopct=autopct_fun)

plt.title(
    'Where Does the World Health Organization Contributor Funding From and Go ?', size=17)

從輸出結(jié)果可以看出:
WHO 最大的捐助國為美國( United States of America ),占比 15.18%,其次是蓋茨基金會(huì)( Bill & Melinda Gates Foundation ),占比 12.12%,排名第三的是全球疫苗和免疫聯(lián)盟( GAVI Alliance ),占比 8.19%;
WHO 最大的投資項(xiàng)目為根除脊髓灰質(zhì)炎( Polio eradication ),占比 26.55%,其次是提升獲得基本保健和營養(yǎng)服務(wù)( Increase access to essential healthand nutrition services ),占比 12.05%,排名第三的是可預(yù)防疾病疫苗( Vaccine-Preventable Diseases ),占比 8.96%。

不同地區(qū)的資助項(xiàng)目

本實(shí)驗(yàn)的目的是繪制兩個(gè)半圓形餅圖,內(nèi)半圓表示各個(gè)被資助地區(qū)的百分占比,外半圓表示各個(gè)地區(qū)對(duì)應(yīng)項(xiàng)目的百分占比,且須做到內(nèi)半圓地區(qū)塊與外半圓項(xiàng)目塊顏色的主色調(diào)完全對(duì)應(yīng)。由于本例相對(duì)復(fù)雜,因此分步驟進(jìn)行繪圖解釋:
生成內(nèi)半圓數(shù)據(jù)集
選擇資金流向?yàn)?to 的數(shù)據(jù),以地區(qū)進(jìn)行資金聚合、逆序排序并歸一化,查看前 5 行數(shù)據(jù)。

funding_cont_to = df.loc[df['direction'] == 'to'].groupby(
    ['cont'])['money'].sum().sort_values(ascending=False)
funding_cont_to = funding_cont_to/np.sum(funding_cont_to)
funding_cont_to.head()

內(nèi)半圓的顏色變化序列
Matplolib 默認(rèn)顏色序列為 TABLEAU_COLORS,可通過 cs.to_rgba 將其轉(zhuǎn)變?yōu)?rgba 顏色元組(plt.pie 接口需要的顏色參數(shù)類型為 rgba 或者 rgb 格式),內(nèi)半圓仍然采用默認(rèn)序列的顏色。

import matplotlib.colors as cs
start_colors=[cs.to_rgba(value) for value in cs.TABLEAU_COLORS.values()]
start_colors

外半圓的顏色變化序列
外圈的項(xiàng)目顏色塊由其對(duì)應(yīng)的內(nèi)圈的主題顏色確定,例如對(duì)于非洲 AF 地區(qū)的項(xiàng)目,如果 AF 的色塊顏色為藍(lán)色,則非洲區(qū)所有項(xiàng)目顏色均為藍(lán)色,但為了將項(xiàng)目進(jìn)行有效區(qū)分,需要將各項(xiàng)目顏色進(jìn)行漸變色設(shè)置,其原理是進(jìn)行主題色到白色的線性插值。

colors = []

for i, c in enumerate(funding_cont_to.index):
    # WHO向每個(gè)大區(qū)投入的項(xiàng)目,按降序排序
    funding_projection = df.loc[(df['direction'] == 'to') & (df['cont'] == c), [
        'orgs', 'money']].sort_values('money', ascending=False)

    # 獲取每個(gè)地區(qū)總項(xiàng)目數(shù)
    color_nums = len(funding_projection)
    # 每個(gè)地區(qū)對(duì)應(yīng)項(xiàng)目的主題顏色
    r, g, b, a = start_colors[i]
    # 根據(jù)主題顏色線性地生成由該主題顏色到白色的序列漸變色
    for r_new, g_new, b_new in zip(np.linspace(r, 1, color_nums), np.linspace(g, 1, color_nums), np.linspace(b, 1, color_nums)):
        colors.append((r_new, g_new, b_new, 1.0))
colors[:5]

外半圓的標(biāo)簽設(shè)置
由于外半圓項(xiàng)目數(shù)量較大,因此每個(gè)地區(qū)只顯示排名前 1 的項(xiàng)目,其余項(xiàng)目不作顯示。

labels = []

for i, c in enumerate(funding_cont_to.index):

    funding_projection = df.loc[(df['direction'] == 'to') & (df['cont'] == c), [
        'orgs', 'money']].sort_values('money', ascending=False)

    show_top = 1
    label = np.append(funding_projection['orgs'][:show_top],
                      ['']*(len(funding_projection)-show_top))
    labels = np.append(labels, label)

labels[:5]

生成外半圓數(shù)據(jù)集

funding_proj_to = pd.DataFrame()

for i, c in enumerate(funding_cont_to.index):

    funding_projection = df.loc[(df['direction'] == 'to') & (df['cont'] == c), [
        'orgs', 'money']].sort_values('money', ascending=False)

    # 合并所有地區(qū)的數(shù)據(jù)
    funding_proj_to = pd.concat([funding_proj_to, funding_projection])

funding_proj_to.set_index(['orgs'], inplace=True)
funding_proj_to = funding_proj_to/np.sum(funding_proj_to)
funding_proj_to.head()

繪圖
半圓圖的繪制原理:當(dāng)傳入 plt.pie 接口參數(shù) x 的求和值小于 1 時(shí),差額部分將形成餅圖的缺口,因此將歸一化的 x 數(shù)據(jù)乘以 0.5 即可獲得半圓,同理,此時(shí)的百分占比被壓縮成原比例的一半,需要通過 autopct_fun 函數(shù)將其顯示比例數(shù)據(jù)作修正。

plt.rcParams['figure.figsize'] = (15, 15)


def autopct_fun(x):
    return '%.2f%%' % (2*x)


# 外圈繪制項(xiàng)目
plt.pie(x=0.5*funding_proj_to,  # 當(dāng)x求和小于1時(shí),餅狀圖則按比例顯示,剩余部分為白色,此處將數(shù)據(jù)乘以 0.5,繪制結(jié)果為半圓
        labels=labels,
        radius=1,  # 餅圖半徑
        wedgeprops={'width': 0.4},  # 餅的徑向?qū)挾?        colors=colors,  # 每個(gè)色塊的顏色,此處顏色的格式是 rgba 元組
        textprops={'size': 17},
        autopct='')
# 內(nèi)圈繪制地區(qū)
plt.pie(x=0.5*funding_cont_to,
        labels=funding_cont_to.index,
        radius=0.45,
        pctdistance=0.8,  # 餅狀圖中表示 比例數(shù)據(jù)的文本 相對(duì)中心的位置
        wedgeprops={'width': 0.3},
        colors=cs.TABLEAU_COLORS,
        textprops={'size': 17},
        autopct=autopct_fun)

plt.ylim(0.5, 1.2)
plt.title('The Funded Zones and The Top 1 Important Funded Programs', size=30)

從輸出結(jié)果可以看出,已實(shí)現(xiàn)了地區(qū)與地區(qū)項(xiàng)目的顏色對(duì)應(yīng),且地區(qū)項(xiàng)目由主題色到白色進(jìn)行漸變顯示。下表列出了每個(gè)地區(qū)排名前 2 的被資助項(xiàng)目:


image.png

非洲被資助項(xiàng)目的相對(duì)比例

非洲毫無疑問是 WHO 項(xiàng)目重點(diǎn)投資地區(qū),以該地區(qū)最大的投資項(xiàng)目為對(duì)比對(duì)象,研究其他項(xiàng)目相對(duì)其所占比例。通過數(shù)據(jù)聚合并逆序排序的方式,獲取最大項(xiàng)目的值,以該值為分母進(jìn)行數(shù)據(jù)的歸一化,此處為美觀考慮,將最大項(xiàng)目的弧度設(shè)置為半圓。

funding_to = df.loc[(df['direction'] == 'to') & (df['cont'] == 'AF')].groupby(
    ['orgs'])['money'].sum().sort_values(ascending=False)
funding_to = funding_to/np.sum(funding_to)

first_large = funding_to[0]

# 計(jì)算各項(xiàng)目相對(duì)最大投資項(xiàng)目的百分比,最大投資項(xiàng)目比例設(shè)定為 0.5,目的是為了繪制半圓
funding_to_related = funding_to/first_large*0.5
funding_to_related.head(10).index[:10]

通過調(diào)節(jié)接口中圓圈的半徑 radius 及寬度 wedgeprops 兩個(gè)參數(shù),將非洲地區(qū)被投資項(xiàng)目逐環(huán)式地向內(nèi)繪制,最外徑為投資額最大的項(xiàng)目,依次向內(nèi),項(xiàng)目投資額逐漸遞減。

width = 0.03

fig, ax = plt.subplots(1, 1, figsize=(15, 15))

for i, projection_percent in enumerate(funding_to_related):
    ax.pie(x=projection_percent,
           startangle=90,
           radius=1.0-i*width,
           labels=['a'], # 輸入圖例文本占位符
           autopct='',
           textprops={'size': 0},
           wedgeprops={'width': width}
           )
# 修改圖例為各個(gè)項(xiàng)目的項(xiàng)目名稱
h, l = ax.get_legend_handles_labels()
plt.legend(handles=h,
           labels=list(funding_to_related.index),
           ncol=2,
           bbox_to_anchor=(0.55, 0.85),
           loc='upper left',
           frameon=False,
           fontsize=20)
plt.title('Funded Programs of Africa Weights Related to Polio Eradication',
          fontsize=30,
          ha='left')

運(yùn)行結(jié)果可以看到各個(gè)項(xiàng)目相對(duì)最大項(xiàng)目的比例,可以看出各項(xiàng)目相對(duì)根除骨髓灰質(zhì)炎項(xiàng)目的相對(duì)比例大小,整理后,相對(duì)比例如下表所示:


image.png

資助項(xiàng)目的資金規(guī)模分布

根據(jù)被投資項(xiàng)目的項(xiàng)目金額,將項(xiàng)目分成小于 1 千萬,1 千萬- 1 億,大于 1 億三個(gè)等級(jí)(單位:美金)。

funding_programs = df.loc[df['direction'] == 'to'].copy()

# 1M=100萬=1e6

bins = [funding_programs['money'].min(), 1e7, 1e8,
        funding_programs['money'].max()]
funding_programs['program_structure'] = pd.cut(funding_programs['money'],
                                               bins=bins,
                                               labels=[
                                                   '<10M', '10M-100M', '>100M']
                                               )
funding_programs['money'] = funding_programs['money'] / \
    np.sum(funding_programs['money'])
funding_programs.head()

按投資項(xiàng)目金額及所在地區(qū),研究各地區(qū)項(xiàng)目資金結(jié)構(gòu)。

# 設(shè)定隨機(jī)數(shù)種子
np.random.seed(121)
row_names = ['<10M', '10M-100M', '>100M']
col_names = ['AF', 'EM', 'HQ', 'EU', 'SE', 'WP', 'AM']

fig, axs = plt.subplots(
    nrows=len(row_names),
    ncols=len(col_names),
    figsize=(len(row_names)*7, len(col_names)*1))

for i, s in enumerate(row_names):
    for j, c in enumerate(col_names):
        ax = axs[i, j]

        x = funding_programs.loc[(funding_programs['cont'] == c) & (
            funding_programs['program_structure'] == s)]['money'].sum()

        # 繪制淺色背景
        ax.pie([1], radius=0.8, colors=[(0.97, 0.97, 0.97)])

        # 繪制深色主體
        ax.pie(x=[x],
               startangle=90,
               radius=1.0,
               labels=['%.2f%%' % round(x*100, 2)],
               autopct='%.2f%%',
               colors=np.random.random(size=(1, 3)),  # 隨機(jī)生成一個(gè)顏色元組(rgb元組)
               textprops={'size': 0},
               )
        ax.legend(frameon=False, fontsize=15)
        ax.set_title(label='%s : %s' % (c, s), size=15)

fig.suptitle('The Funded Programs Budget Structure of Different Zones', size=20)

從輸出結(jié)果可以看出:
超大金額(大于 1 億)的投資項(xiàng)目集中在 Africa,Eastern Mediterranean 兩個(gè)地區(qū),Europe 等 4 個(gè)地區(qū)沒有該規(guī)模項(xiàng)目;
中等規(guī)模項(xiàng)目集中在 Headquarters 地區(qū)。

被資助項(xiàng)目的資金規(guī)模分布-樹形地圖

!pip install pyecharts==1.7.1

另一種可視化結(jié)構(gòu)的繪圖對(duì)象為 pyecharts 包提供的 TreeMap 類,與傳統(tǒng)的餅圖不同,TreeMap 用一個(gè)個(gè)的方格表示各元素相對(duì)整體的比例。

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

funding_to = df.loc[df['direction'] == 'to'].groupby(
    ['orgs'])['money'].sum().sort_values(ascending=False)
funding_to = funding_to/np.sum(funding_to)

# 生成 TreeMap 數(shù)據(jù),該數(shù)據(jù)為 json 格式
funding_to_treemap = [{'value': value, 'name': name}
                      for name, value in zip(funding_to.index, funding_to)]


tree = TreeMap()
tree.add("Funded Budget",
         funding_to_treemap,
         label_opts=opts.LabelOpts(position="inside", font_size=12),
         drilldown_icon=" ",
         leaf_depth=1)
tree.set_global_opts(
    title_opts=opts.TitleOpts(
        title="The Funded Programs Budget Structure",),
    legend_opts=opts.LegendOpts(
        pos_top='5%', textstyle_opts=opts.TextStyleOpts(font_size=15))
)
tree.render_notebook()

從輸出結(jié)果可以看出前 5 類投資項(xiàng)目將近占到了總項(xiàng)目投資額的 60% 以上。

帶鉆取結(jié)構(gòu)的樹形圖

TreeMap 類還提供了數(shù)據(jù)鉆取功能,原理是傳入的數(shù)據(jù)文件增加一個(gè) children 字典項(xiàng),children 的值為需要被鉆取的 TreeMap 數(shù)據(jù),以下代碼生成了帶鉆取功能的數(shù)據(jù)。
數(shù)據(jù)準(zhǔn)備

funding_to = df.loc[df['direction'] == 'to'].groupby(
    ['cont_name', 'orgs'], as_index=False)['money'].sum()

funding_to['money'] = funding_to['money']/np.sum(funding_to['money'])

funding_to_treemap = [
    {'value': funding_to.loc[funding_to['cont_name'] == name]['money'].sum(),
     'name': name,
     'children':[
        {
            'value': funding_to.loc[(funding_to['cont_name'] == name) & (funding_to['orgs'] == org)]['money'].sum(),
            'name': org,
        }
        for org in list(set(funding_to.loc[funding_to['cont_name'] == name, 'orgs']))
    ]
    }
    for name in list(set(funding_to['cont_name']))
]

繪圖

tree = TreeMap()
tree.add("Funded Budget",
         funding_to_treemap,
         label_opts=opts.LabelOpts(position="inside", font_size=20),
         drilldown_icon=" ",
         leaf_depth=1  # 初始化圖形時(shí),顯示第一層(即最高級(jí))
         )
tree.set_global_opts(
    title_opts=opts.TitleOpts(
        title="The Funded Programs Budget Structure of Different Zones",),
    legend_opts=opts.LegendOpts(
        pos_top='5%', textstyle_opts=opts.TextStyleOpts(font_size=15))
)
tree.render_notebook()

運(yùn)行以上代碼,輸出的是地區(qū)級(jí)的結(jié)構(gòu)圖,當(dāng)鼠標(biāo)點(diǎn)擊其中一塊區(qū)域時(shí),樹形圖向下鉆取該區(qū)域子項(xiàng)目的結(jié)構(gòu)圖,可通過圖最下面的層級(jí)按鈕可以回到上一級(jí)。

被資助項(xiàng)目的資金規(guī)模分布-太陽花圖

同樣的數(shù)據(jù)結(jié)構(gòu)傳入 Sunburst 類,可以獲得帶有鉆取功能的太陽花圖,太陽花圖帶有兩個(gè)餅圖,內(nèi)部餅圖代表父級(jí)的結(jié)構(gòu)組成,點(diǎn)擊任一顏色塊,數(shù)據(jù)向下鉆取到該層級(jí)下子項(xiàng)的餅圖。

from pyecharts.charts import Sunburst

funding_to = df.loc[df['direction'] == 'to'].groupby(
    ['cont_name', 'orgs'], as_index=False)['money'].sum()

funding_to['money'] = funding_to['money']/np.sum(funding_to['money'])

# 數(shù)據(jù)結(jié)構(gòu)與樹形圖完全一致
funding_to_treemap = [
    {'value': funding_to.loc[funding_to['cont_name'] == name]['money'].sum(),
     'name': name,
     'children':[
        {
            'value': funding_to.loc[(funding_to['cont_name'] == name) & (funding_to['orgs'] == org)]['money'].sum(),
            'name': org,
        }
        for org in list(set(funding_to.loc[funding_to['cont_name'] == name, 'orgs']))
    ]
    }
    for name in list(set(funding_to['cont_name']))
]

sun = Sunburst()
sun.add(
    "",
    data_pair=funding_to_treemap,
    highlight_policy="ancestor",
    radius=[0, "95%"],
    sort_="null",
    label_opts=opts.LabelOpts(is_show=False, position='inside', font_size=5),
    levels=[
        {  # 外圈設(shè)置
            "r0": "65%",  # 內(nèi)圈半徑
            "r": "95%",  # 外圈半徑
            "itemStyle": {"borderWidth": 2},
            "label": {"rotate": "tangential"},
        },
        {  # 內(nèi)圈設(shè)置
            "r0": "25%",
            "r": "45%",
        },
    ],
)
sun.set_global_opts(title_opts=opts.TitleOpts(title="The Funded Programs Budget Structure of Different Zones"))
sun.set_series_opts(label_opts=opts.LabelOpts(formatter=""))
sun.render_notebook()

世衛(wèi)組織的資金流向

餅狀圖是表達(dá)組成關(guān)系或者總分關(guān)系的最佳繪圖對(duì)象,樹形圖和太陽花圖在餅圖的基礎(chǔ)上,增加了交互式地鉆取功能,實(shí)現(xiàn)了不同層級(jí)結(jié)構(gòu)的總分表達(dá)。在之前的實(shí)驗(yàn)中,我們借助這幾類對(duì)象研究了世衛(wèi)組織的資金來源、資助項(xiàng)目,以下我們進(jìn)一步研究其資金的流向。
描述流向的繪圖對(duì)象主要是 桑基圖,?;鶊D早期的應(yīng)用主要是能量分布,后期在金融領(lǐng)域大放異彩,再后來被廣泛應(yīng)用到經(jīng)管領(lǐng)域。?;鶊D將帶有流向特征的節(jié)點(diǎn)通過一定寬度的線連接起來,線的疏密代表任意兩節(jié)點(diǎn)的能量強(qiáng)弱。?;鶊D繪圖的主要難點(diǎn)在于數(shù)據(jù)準(zhǔn)備工作,以下分布展示其過程:
將資金量小于閾值的組織或者項(xiàng)目設(shè)置為其他類別
為減少?;鶊D可視化的節(jié)點(diǎn)數(shù)量,避免圖片過大反而帶來閱讀困難,將所有資助組織和被資助項(xiàng)目金額小于 1000 萬的均設(shè)置成其他資助者(other contributions)或其他項(xiàng)目(other programs)。

data = df.copy()

limit_money = 1e7   

data['orgs_adjust'] = data['orgs']

data.loc[(data['direction'] == 'from') &
         (data['money'] <= limit_money), 'orgs_adjust'] = 'other contributions'
data.loc[(data['direction'] == 'to') &
         (data['money'] <= limit_money), 'orgs_adjust'] = 'other programs'

data.head()

數(shù)據(jù)構(gòu)建
桑基圖接口主要傳入兩個(gè)數(shù)據(jù),一個(gè)為 nodes,一個(gè)為 links。nodes 表示需要可視化的節(jié)點(diǎn),此處 nodes 由各個(gè)組織名稱和各個(gè)地區(qū)名稱構(gòu)成,對(duì)其進(jìn)行去重和拼接;links 為一個(gè)列表,列表中每個(gè)元素為一個(gè)字典,由 source,target,value 三個(gè)鍵構(gòu)成,分別代表起始節(jié)點(diǎn)、結(jié)束節(jié)點(diǎn)和連接兩節(jié)點(diǎn)的能量值,source 和 target 須包含在 nodes 節(jié)點(diǎn)列表中。節(jié)點(diǎn)連接一共分成兩個(gè)部分,出資國家與被資助地區(qū)為資金流入關(guān)系,被資助地區(qū)與被資助項(xiàng)目為資金流出關(guān)系,因此在生成節(jié)點(diǎn)連接數(shù)據(jù)集時(shí)需要考慮 source 和 target 的方向,以下代碼生成了用于桑基圖接口的數(shù)據(jù)。

sankey_value='money'

# 去重后拼接
node_lists = np.append(np.unique(data['orgs_adjust']),(np.unique(data['cont'])))
nodes = [
    {
        'name': node
    }
    for node in node_lists
]
links = [
    {
        "source": s,
        "target": t,
        "value": v
    }
    for s, t, v in zip(data.loc[data['direction'] == 'from', 'orgs_adjust'],
                       data.loc[data['direction'] == 'from', 'cont'],
                       data.loc[data['direction'] == 'from', sankey_value],
                       )
]+[
    {
        "source": s,
        "target": t,
        "value": v
    }
    for t, s, v in zip(data.loc[data['direction'] == 'to', 'orgs_adjust'],
                       data.loc[data['direction'] == 'to', 'cont'],
                       data.loc[data['direction'] == 'to', sankey_value],
                       )
]

桑基圖的繪制
?;鶊D的接口調(diào)用方式和大多數(shù) pyecharts 接口類似。運(yùn)行以下代碼,可生成世衛(wèi)組織 2018 -2019 年指定自愿捐款的資金流向圖,該圖細(xì)致地展示了每一筆資金的使用,在 WHO 官網(wǎng)上,也有一張類似的圖,該圖生動(dòng)地公開了 WHO 經(jīng)費(fèi)使用情況,便于讀者了解 WHO 的資金預(yù)算流向情況。

from pyecharts.charts import Sankey

init_opts=opts.InitOpts(width='1000px',height='1000px')
sankey = Sankey(init_opts=init_opts)  # 初始化圖片的寬度和高度
sankey.add(
    series_name="",
    nodes=nodes,
    links=links,
    node_gap=7, # 節(jié)點(diǎn)間距
    label_opts=opts.LabelOpts(position='right',font_size=15), # 設(shè)置節(jié)點(diǎn)文本
    itemstyle_opts=opts.ItemStyleOpts(border_width=2), # 設(shè)置節(jié)點(diǎn)寬度
    linestyle_opt=opts.LineStyleOpts(color="source", width=2,curve=0.5, opacity=0.5), # 設(shè)置線型
    tooltip_opts=opts.TooltipOpts(trigger_on="click") # 設(shè)置交互方式
)
sankey.set_global_opts(
    title_opts=opts.TitleOpts(title="The Funding Budget Flows of Specified Voluntary Contributions of WHO in Year 2018 - 2019"),    
)
sankey.render_notebook()
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容