<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Python 繪制驚艷的桑基圖

          共 9676字,需瀏覽 20分鐘

           ·

          2022-02-21 18:59

          導(dǎo)讀:本文中,我們使用 Python 的 plotly 繪制桑基圖。


          作者:云朵君
          來源:數(shù)據(jù)STUDIO(ID:jim_learning)


          01 桑基圖簡(jiǎn)介

          很多時(shí)候,我們需要一種必須可視化數(shù)據(jù)如何在實(shí)體之間流動(dòng)的情況。例如,以居民如何從一個(gè)國(guó)家遷移到另一個(gè)國(guó)家為例。這里演示了有多少居民從英格蘭遷移到北愛爾蘭、蘇格蘭和威爾士。


          從這個(gè)桑基圖 (Sankey)可視化中可以明顯看出,從England遷移到Wales的居民多于從Scotland或Northern Ireland遷移的居民。

          什么是桑基圖?

          桑基圖通常描繪從一個(gè)實(shí)體(或節(jié)點(diǎn))到另一個(gè)實(shí)體(或節(jié)點(diǎn))的數(shù)據(jù)流。

          數(shù)據(jù)流向的實(shí)體被稱為節(jié)點(diǎn),數(shù)據(jù)流起源的節(jié)點(diǎn)是源節(jié)點(diǎn)(例如左側(cè)的England),流結(jié)束的節(jié)點(diǎn)是目標(biāo)節(jié)點(diǎn)(例如右側(cè)的Wales)。源節(jié)點(diǎn)和目標(biāo)節(jié)點(diǎn)通常表示為帶有標(biāo)簽的矩形。

          流動(dòng)本身由直線或曲線路徑表示,稱為鏈接流/鏈接的寬度與流的量/數(shù)量成正比。在上面的例子中,從英格蘭到威爾士的流動(dòng)(即居民遷移)比從英格蘭到蘇格蘭或北愛爾蘭的流動(dòng)(即居民遷移)更廣泛(更多),表明遷移到威爾士的居民數(shù)量多于其他國(guó)家。

          桑基圖可用于表示能量、金錢、成本的流動(dòng),以及任何具有流動(dòng)概念的事物。

          米納爾關(guān)于拿破侖入侵俄羅斯的經(jīng)典圖表可能是桑基圖表最著名的例子。這種使用桑基圖的可視化非常有效地顯示了法國(guó)軍隊(duì)在前往俄羅斯和返回的途中是如何進(jìn)步(或減少?)的。


          本文中,我們使用 Python 的 plotly 繪制桑基圖。


          02 如何繪制桑基圖?

          本文使用 2021 年奧運(yùn)會(huì)數(shù)據(jù)集繪制桑基圖。該數(shù)據(jù)集包含有關(guān)獎(jiǎng)牌總數(shù)的詳細(xì)信息——國(guó)家、獎(jiǎng)牌總數(shù)以及金牌、銀牌和銅牌的單項(xiàng)總數(shù)。我們通過繪制一個(gè)桑基圖來了解一個(gè)國(guó)家贏得的金牌、銀牌和銅牌數(shù)。

          df_medals?=?pd.read_excel("data/Medals.xlsx")
          print(df_medals.info())
          df_medals.rename(columns={'Team/NOC':'Country',?'Total':?'Total?Medals',?'Gold':'Gold?Medals',?'Silver':?'Silver?Medals',?'Bronze':?'Bronze?Medals'},?inplace=True)
          df_medals.drop(columns=['Unnamed:?7','Unnamed:?8','Rank?by?Total'],?inplace=True)

          df_medals

          <class?'pandas.core.frame.DataFrame'>
          RangeIndex:?93?entries,?0?to?92
          Data?columns?(total?9?columns):
          #???Column?????????Non-Null?Count??Dtype??
          ---??------?????????--------------??-----??
          0???Rank???????????93?non-null?????int64??
          1???Team/NOC???????93?non-null?????object
          2???Gold???????????93?non-null?????int64??
          3???Silver?????????93?non-null?????int64??
          4???Bronze?????????93?non-null?????int64??
          5???Total??????????93?non-null?????int64??
          6???Rank?by?Total??93?non-null?????int64??
          7???Unnamed:?7?????0?non-null??????float64
          8???Unnamed:?8?????1?non-null??????float64
          dtypes:?float64(2),?int64(6),?object(1)
          memory?usage:?6.7+?KB
          None


          1. 桑基圖繪圖基礎(chǔ)

          使用?plotly?的?go.Sankey,該方法帶有2 個(gè)參數(shù) ——?nodes??和?links?(節(jié)點(diǎn)和鏈接)。

          注意:所有節(jié)點(diǎn)——源和目標(biāo)都應(yīng)該有唯一的標(biāo)識(shí)符。

          在本文奧林匹克獎(jiǎng)牌數(shù)據(jù)集情況中:

          Source是國(guó)家。將前 3 個(gè)國(guó)家(美國(guó)、中國(guó)和日本)視為源節(jié)點(diǎn)。用以下(唯一的)標(biāo)識(shí)符、標(biāo)簽和顏色來標(biāo)記這些源節(jié)點(diǎn):

          • 0:美國(guó):綠色
          • 1:中國(guó):藍(lán)色
          • 2:日本:橙色

          Target是金牌、銀牌或銅牌。用以下(唯一的)標(biāo)識(shí)符、標(biāo)簽和顏色來標(biāo)記這些目標(biāo)節(jié)點(diǎn):

          • 3:金牌:金色
          • 4:銀牌:銀色
          • 5:銅牌:棕色

          Link(源節(jié)點(diǎn)和目標(biāo)節(jié)點(diǎn)之間)是每種類型獎(jiǎng)牌的數(shù)量。在每個(gè)源中有3個(gè)鏈接,每個(gè)鏈接都以目標(biāo)結(jié)尾——金牌、銀牌和銅牌。所以總共有9個(gè)鏈接。每個(gè)環(huán)節(jié)的寬度應(yīng)為金牌、銀牌和銅牌的數(shù)量。用以下源標(biāo)記這些鏈接到目標(biāo)、值和顏色:

          • 0 (美國(guó)) 至 3,4,5 : 39, 41, 33
          • 1 (中國(guó)) 至 3,4,5 : 38, 32, 18
          • 2 (日本) 至 3,4,5 : 27, 14, 17

          需要實(shí)例化 2 個(gè)?python dict?對(duì)象來表示

          • nodes?(源和目標(biāo)):標(biāo)簽和顏色作為單獨(dú)的列表和
          • links:源節(jié)點(diǎn)、目標(biāo)節(jié)點(diǎn)、值(寬度)和鏈接的顏色作為單獨(dú)的列表

          并將其傳遞給plotly的?go.Sankey

          列表的每個(gè)索引(標(biāo)簽、源、目標(biāo)、值和顏色)分別對(duì)應(yīng)一個(gè)節(jié)點(diǎn)或鏈接。

          NODES?=?dict(?
          #?????????0???????????????????????????1?????????????????????????????2????????3???????4?????????5?????????????????????????
          label?=?["United?States?of?America",?"People's?Republic?of?China",?"Japan",?"Gold",?"Silver",?"Bronze"],
          color?=?["seagreen",?????????????????"dodgerblue",?????????????????"orange",?"gold",?"silver",?"brown"?],)
          LINKS?=?dict(???
          ??source?=?[??0,??0,??0,??1,??1,??1,??2,??2,??2],?#?鏈接的起點(diǎn)或源節(jié)點(diǎn)
          ??target?=?[??3,??4,??5,??3,??4,??5,??3,??4,??5],?#?鏈接的目的地或目標(biāo)節(jié)點(diǎn)
          ??value?=??[?39,?41,?33,?38,?32,?18,?27,?14,?17],?#?鏈接的寬度(數(shù)量)
          #?鏈接的顏色
          #?目標(biāo)節(jié)點(diǎn):???????3-Gold??????????4-Silver????????5-Bronze
          ??color?=?[???
          ??"lightgreen",???"lightgreen",???"lightgreen",??????#?源節(jié)點(diǎn):0?-?美國(guó)?States?of?America
          ??"lightskyblue",?"lightskyblue",?"lightskyblue",????#?源節(jié)點(diǎn):1?-?中華人民共和國(guó)China
          ??"bisque",???????"bisque",???????"bisque"],)????????#?源節(jié)點(diǎn):2?-?日本
          data?=?go.Sankey(node?=?NODES,?link?=?LINKS)
          fig?=?go.Figure(data)
          fig.show()


          這是一個(gè)非常基本的桑基圖。但是否注意到圖表太寬并且銀牌出現(xiàn)在金牌之前?

          接下來介紹如何調(diào)整節(jié)點(diǎn)的位置和寬度。

          2. 調(diào)整節(jié)點(diǎn)位置和圖表寬度

          為節(jié)點(diǎn)添加 x 和 y 位置以明確指定節(jié)點(diǎn)的位置。值應(yīng)介于 0 和 1 之間。

          NODES?=?dict(?
          #?????????0???????????????????????????1?????????????????????????????2????????3???????4?????????5?????????????????????????
          label?=?["United?States?of?America",?"People's?Republic?of?China",?"Japan",?"Gold",?"Silver",?"Bronze"],
          color?=?["seagreen",?????????????????"dodgerblue",?????????????????"orange",?"gold",?"silver",?"brown"?],)
          x?=?[?????0,??????????????????????????0,????????????????????????????0,????????0.5,????0.5,??????0.5],
          y?=?[?????0,??????????????????????????0.5,??????????????????????????1,????????0.1,????0.5,????????1],)
          data?=?go.Sankey(node?=?NODES,?link?=?LINKS)
          fig?=?go.Figure(data)
          fig.update_layout(title="Olympics?-?2021:?Country?&??Medals",??font_size=16)
          fig.show()

          于是得到了一個(gè)緊湊的桑基圖:


          下面看看代碼中傳遞的各種參數(shù)如何映射到圖中的節(jié)點(diǎn)和鏈接。

          ▲代碼如何映射到桑基圖

          3. 添加有意義的懸停標(biāo)簽

          我們都知道plotly繪圖是交互的,我們可以將鼠標(biāo)懸停在節(jié)點(diǎn)和鏈接上以獲取更多信息。

          ▲帶有默認(rèn)懸停標(biāo)簽的桑基圖

          當(dāng)將鼠標(biāo)懸停在圖上,將會(huì)顯示詳細(xì)信息。懸停標(biāo)簽中顯示的信息是默認(rèn)文本:節(jié)點(diǎn)、節(jié)點(diǎn)名稱、傳入流數(shù)、傳出流數(shù)和總值。

          例如:

          • 節(jié)點(diǎn)美國(guó)共獲得11枚獎(jiǎng)牌(=39金+41銀+33銅)
          • 節(jié)點(diǎn)金牌共有104枚獎(jiǎng)牌(=美國(guó)39枚,中國(guó)38枚,日本27枚)

          如果我們覺得這些標(biāo)簽太冗長(zhǎng)了,我們可以對(duì)此進(jìn)程改進(jìn)。使用hovertemplate參數(shù)改進(jìn)懸停標(biāo)簽的格式

          • 對(duì)于節(jié)點(diǎn),由于hoverlabels 沒有提供新信息,通過傳遞一個(gè)空hovertemplate = ""來去掉hoverlabel
          • 對(duì)于鏈接,可以使標(biāo)簽簡(jiǎn)潔,格式為-
          • 對(duì)于節(jié)點(diǎn)和鏈接,讓我們使用后綴"Medals"顯示值。例如 113 枚獎(jiǎng)牌而不是 113 枚。這可以通過使用具有適當(dāng)valueformatvaluesuffixupdate_traces函數(shù)來實(shí)現(xiàn)。

          NODES?=?dict(?
          #?????????0???????????????????????????1???????????????????????????????2????????3???????4???????????5
          label?=?["United?States?of?America",?"People's?Republic?of?China",???"Japan",?"Gold",?"Silver",?"Bronze"],
          color?=?[????????????????"seagreen",?????????????????"dodgerblue",??"orange",?"gold",?"silver",?"brown"?],
          x?????=?[?????????????????????????0,????????????????????????????0,?????????0,????0.5,??????0.5,??????0.5],
          y?????=?[?????????????????????????0,??????????????????????????0.5,?????????1,????0.1,??????0.5,????????1],
          hovertemplate="?",)

          LINK_LABELS?=?[]
          for?country?in?["USA","China","Japan"]:
          ????for?medal?in?["Gold","Silver","Bronze"]:
          ????????LINK_LABELS.append(f"{country}-{medal}")
          LINKS?=?dict(source?=?[??0,??0,??0,??1,??1,??1,??2,??2,??2],?
          ???????#?鏈接的起點(diǎn)或源節(jié)點(diǎn)
          ???????target?=?[??3,??4,??5,??3,??4,??5,??3,??4,??5],?
          ???????#?鏈接的目的地或目標(biāo)節(jié)點(diǎn)
          ???????value?=??[?39,?41,?33,?38,?32,?18,?27,?14,?17],?
          ???????#?鏈接的寬度(數(shù)量)?
          ?????????????#?鏈接的顏色
          ?????????????#?目標(biāo)節(jié)點(diǎn):3-Gold??????????4?-Silver????????5-Bronze
          ?????????????color?=?["lightgreen",???"lightgreen",???"lightgreen",???#?源節(jié)點(diǎn):0?-?美國(guó)
          ??????????????????????"lightskyblue",?"lightskyblue",?"lightskyblue",?#?源節(jié)點(diǎn):1?-?中國(guó)
          ??????????????????????"bisque",???????"bisque",???????"bisque"],??????#?源節(jié)點(diǎn):2?-?日本
          ?????????????label?=?LINK_LABELS,?
          ?????????????hovertemplate="%{label}",)

          data?=?go.Sankey(node?=?NODES,?link?=?LINKS)
          fig?=?go.Figure(data)
          fig.update_layout(title="Olympics?-?2021:?Country?&??Medals",??
          ??????????????????font_size=16,?width=1200,?height=500,)
          fig.update_traces(valueformat='3d',?
          ??????????????????valuesuffix='Medals',?
          ??????????????????selector=dict(type='sankey'))
          fig.update_layout(hoverlabel=dict(bgcolor="lightgray",
          ??????????????????????????????????font_size=16,
          ??????????????????????????????????font_family="Rockwell"))
          fig.show("png")?#fig.show()

          ▲帶有改進(jìn)的懸停標(biāo)簽的桑基圖

          4. 對(duì)多個(gè)節(jié)點(diǎn)和級(jí)別進(jìn)行泛化

          相對(duì)于鏈接,節(jié)點(diǎn)被稱為源和目標(biāo)。作為一個(gè)鏈接目標(biāo)的節(jié)點(diǎn)可以是另一個(gè)鏈接的源。

          • 該代碼可以推廣到處理數(shù)據(jù)集中的所有國(guó)家。
          • 還可以將圖表擴(kuò)展到另一個(gè)層次,以可視化各國(guó)的獎(jiǎng)牌總數(shù)。

          NUM_COUNTRIES?=?5
          X_POS,?Y_POS?=?0.5,?1/(NUM_COUNTRIES-1)
          NODE_COLORS?=?["seagreen",?"dodgerblue",?"orange",?"palevioletred",?"darkcyan"]
          LINK_COLORS?=?["lightgreen",?"lightskyblue",?"bisque",?"pink",?"lightcyan"]

          source?=?[]
          node_x_pos,?node_y_pos?=?[],?[]
          node_labels,?node_colors?=?[],?NODE_COLORS[0:NUM_COUNTRIES]
          link_labels,?link_colors,?link_values?=?[],?[],?[]?

          #?第一組鏈接和節(jié)點(diǎn)
          for?i?in?range(NUM_COUNTRIES):
          ????source.extend([i]*3)
          ????node_x_pos.append(0.01)
          ????node_y_pos.append(round(i*Y_POS+0.01,2))
          ????country?=?df_medals['Country'][i]
          ????node_labels.append(country)?
          ????for?medal?in?["Gold",?"Silver",?"Bronze"]:
          ????????link_labels.append(f"{country}-{medal}")
          ????????link_values.append(df_medals[f"{medal}?Medals"][i])
          ????link_colors.extend([LINK_COLORS[i]]*3)

          source_last?=?max(source)+1
          target?=?[?source_last,?source_last+1,?source_last+2]?*?NUM_COUNTRIES
          target_last?=?max(target)+1

          node_labels.extend(["Gold",?"Silver",?"Bronze"])
          node_colors.extend(["gold",?"silver",?"brown"])
          node_x_pos.extend([X_POS,?X_POS,?X_POS])
          node_y_pos.extend([0.01,?0.5,?1])

          #?最后一組鏈接和節(jié)點(diǎn)
          source.extend([?source_last,?source_last+1,?source_last+2])
          target.extend([target_last]*3)
          node_labels.extend(["Total?Medals"])
          node_colors.extend(["grey"])
          node_x_pos.extend([X_POS+0.25])
          node_y_pos.extend([0.5])

          for?medal?in?["Gold","Silver","Bronze"]:
          ????link_labels.append(f"{medal}")
          ????link_values.append(df_medals[f"{medal}?Medals"][:i+1].sum())
          link_colors.extend(["gold",?"silver",?"brown"])

          print("node_labels",?node_labels)
          print("node_x_pos",?node_x_pos);?print("node_y_pos",?node_y_pos)

          node_labels?['United?States?of?America',?"People's?Republic?of?China",
          ????????????'Japan',?'Great?Britain',?'ROC',?'Gold',?'Silver',
          ????????????'Bronze',?'Total?Medals']
          node_x_pos?[0.01,?0.01,?0.01,?0.01,?0.01,?0.5,?0.5,?0.5,?0.75]
          node_y_pos?[0.01,?0.26,?0.51,?0.76,?1.01,?0.01,?0.5,?1,?0.5]
          #?顯示的圖
          NODES?=?dict(pad??=?20,?thickness?=?20,?
          ?????????????line?=?dict(color?=?"lightslategrey",
          ?????????????????????????width?=?0.5),
          ?????????????hovertemplate="?",
          ?????????????label?=?node_labels,?
          ?????????????color?=?node_colors,
          ?????????????x?=?node_x_pos,?
          ?????????????y?=?node_y_pos,?)
          LINKS?=?dict(source?=?source,?
          ?????????????target?=?target,?
          ?????????????value?=?link_values,?
          ?????????????label?=?link_labels,?
          ?????????????color?=?link_colors,
          ?????????????hovertemplate="%{label}",)
          data?=?go.Sankey(arrangement='snap',?
          ?????????????????node?=?NODES,?
          ?????????????????link?=?LINKS)
          fig?=?go.Figure(data)
          fig.update_traces(valueformat='3d',?
          ??????????????????valuesuffix='?Medals',?
          ??????????????????selector=dict(type='sankey'))
          fig.update_layout(title="Olympics?-?2021:?Country?&??Medals",??
          ??????????????????font_size=16,??
          ??????????????????width=1200,
          ??????????????????height=500,)
          fig.update_layout(hoverlabel=dict(bgcolor="grey",?
          ??????????????????????????????????font_size=14,?
          ??????????????????????????????????font_family="Rockwell"))
          fig.show("png")?



          延伸閱讀??

          延伸閱讀《利用Python進(jìn)行數(shù)據(jù)分析》


          干貨直達(dá)??



          更多精彩??

          在公眾號(hào)對(duì)話框輸入以下關(guān)鍵詞
          查看更多優(yōu)質(zhì)內(nèi)容!

          讀書?|?書單?|?干貨?|?講明白?|?神操作?|?手把手
          大數(shù)據(jù)?|?云計(jì)算?|?數(shù)據(jù)庫(kù)?|?Python?|?爬蟲?|?可視化
          AI?|?人工智能?|?機(jī)器學(xué)習(xí)?|?深度學(xué)習(xí)?|?NLP
          5G?|?中臺(tái)?|?用戶畫像?|?數(shù)學(xué)?|?算法?|?數(shù)字孿生

          據(jù)統(tǒng)計(jì),99%的大咖都關(guān)注了這個(gè)公眾號(hào)
          ??
          瀏覽 25
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄色免费网站在线 | 2025天天操夜夜操 | 17.c蜜桃视频红桃视频 | 又色又爽又黄18 网站 | www.激情 |