【Python 】绘制惊艳的桑基图
很多時候,我們需要一種必須可視化數據如何在實體之間流動的情況。例如,以居民如何從一個國家遷移到另一個國家為例。這里演示了有多少居民從英格蘭遷移到北愛爾蘭、蘇格蘭和威爾士。
從這個 桑基圖 (Sankey)可視化中可以明顯看出,從England遷移到Wales的居民多于從Scotland或Northern Ireland遷移的居民。
什么是桑基圖?
桑基圖通常描繪 從一個實體(或節點)到另一個實體(或節點)的數據流。
數據流向的實體被稱為節點,數據流起源的節點是源節點(例如左側的England),流結束的節點是 目標節點(例如右側的Wales)。源節點和目標節點通常表示為帶有標簽的矩形。
流動本身由直線或曲線路徑表示,稱為鏈接。流/鏈接的寬度與流的量/數量成正比。在上面的例子中,從英格蘭到威爾士的流動(即居民遷移)比從英格蘭到蘇格蘭或北愛爾蘭的流動(即居民遷移)更廣泛(更多),表明遷移到威爾士的居民數量多于其他國家。
桑基圖可用于表示能量、金錢、成本的流動,以及任何具有流動概念的事物。
米納爾關于拿破侖入侵俄羅斯的經典圖表可能是桑基圖表最著名的例子。這種使用桑基圖的可視化非常有效地顯示了法國軍隊在前往俄羅斯和返回的途中是如何進步(或減少?)的。
本文中,我們使用 python 的 plotly 繪制桑基圖。
如何繪制桑基圖?
本文使用 2021 年奧運會數據集繪制桑基圖。該數據集包含有關獎牌總數的詳細信息——國家、獎牌總數以及金牌、銀牌和銅牌的單項總數。我們通過繪制一個桑基圖來了解一個國家贏得的金牌、銀牌和銅牌數。
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 float648 Unnamed: 8 1 non-null float64 dtypes: float64(2), int64(6), object(1) memory usage: 6.7+ KB None桑基圖繪圖基礎
使用 plotly 的 go.Sankey,該方法帶有2 個參數 —— nodes ?和 links (節點和鏈接)。
注意:所有節點——源和目標都應該有唯一的標識符。
在本文奧林匹克獎牌數據集情況中:
Source是國家。將前 3 個國家(美國、中國和日本)視為源節點。用以下(唯一的)標識符、標簽和顏色來標記這些源節點:
0:美國:綠色
1:中國:藍色
2:日本:橙色
Target是金牌、銀牌或銅牌。用以下(唯一的)標識符、標簽和顏色來標記這些目標節點:
3:金牌:金色
4:銀牌:銀色
5:銅牌:棕色
Link(源節點和目標節點之間)是每種類型獎牌的數量。在每個源中有3個鏈接,每個鏈接都以目標結尾——金牌、銀牌和銅牌。所以總共有9個鏈接。每個環節的寬度應為金牌、銀牌和銅牌的數量。用以下源標記這些鏈接到目標、值和顏色:
0 (美國) 至 3,4,5 : 39, 41, 33
1 (中國) 至 3,4,5 : 38, 32, 18
2 (日本) 至 3,4,5 : 27, 14, 17
需要實例化 2 個 python dict 對象來表示
nodes (源和目標):標簽和顏色作為單獨的列表和
links:源節點、目標節點、值(寬度)和鏈接的顏色作為單獨的列表
并將其傳遞給plotly的 go.Sankey。
列表的每個索引(標簽、源、目標、值和顏色)分別對應一個節點或鏈接。
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],?#?鏈接的起點或源節點target?=?[??3,??4,??5,??3,??4,??5,??3,??4,??5],?#?鏈接的目的地或目標節點value?=??[?39,?41,?33,?38,?32,?18,?27,?14,?17],?#?鏈接的寬度(數量) #?鏈接的顏色 #?目標節點:?????? 3-Gold ???????? 4-Silver ?????? 5-Bronzecolor?=?[???"lightgreen",???"lightgreen",???"lightgreen",??????#?源節點:0?-?美國 States of America"lightskyblue",?"lightskyblue",?"lightskyblue",????#?源節點:1 -?中華人民共和國China"bisque",???????"bisque",???????"bisque"],)????????#?源節點:2 -?日本 data?=?go.Sankey(node?=?NODES,?link?=?LINKS) fig?=?go.Figure(data) fig.show()這是一個非常基本的桑基圖。但是否注意到圖表太寬并且銀牌出現在金牌之前?
接下來介紹如何調整節點的位置和寬度。
調整節點位置和圖表寬度
為節點添加 x 和 y 位置以明確指定節點的位置。值應介于 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()于是得到了一個緊湊的桑基圖:
下面看看代碼中傳遞的各種參數如何映射到圖中的節點和鏈接。
代碼如何映射到桑基圖添加有意義的懸停標簽
我們都知道plotly繪圖是交互的,我們可以將鼠標懸停在節點和鏈接上以獲取更多信息。
帶有默認懸停標簽的桑基圖當將鼠標懸停在圖上,將會顯示詳細信息。懸停標簽中顯示的信息是默認文本:節點、節點名稱、傳入流數、傳出流數和總值。
例如:
節點美國共獲得11枚獎牌(=39金+41銀+33銅)
節點金牌共有104枚獎牌(=美國39枚,中國38枚,日本27枚)
如果我們覺得這些標簽太冗長了,我們可以對此進程改進。使用hovertemplate參數改進懸停標簽的格式
對于節點,由于hoverlabels 沒有提供新信息,通過傳遞一個空hovertemplate = ""來去掉hoverlabel
對于鏈接,可以使標簽簡潔,格式為<country>-<medal type>
對于節點和鏈接,讓我們使用后綴"Medals"顯示值。例如 113 枚獎牌而不是 113 枚。這可以通過使用具有適當valueformat和valuesuffix的update_traces函數來實現。
對多個節點和級別進行泛化
相對于鏈接,節點被稱為源和目標。作為一個鏈接目標的節點可以是另一個鏈接的源。
該代碼可以推廣到處理數據集中的所有國家。
還可以將圖表擴展到另一個層次,以可視化各國的獎牌總數。
總結
以上是生活随笔為你收集整理的【Python 】绘制惊艳的桑基图的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (视频+图文)机器学习入门系列-第1章
- 下一篇: 分布式服务框架Dubbo使用小结