原文地址: https://geekplux.com/2018/08/28/how-to-implement-sankey-diagram.html
Google 搜索桑基圖,能夠搜到一大堆定義。簡而言之,桑基圖是一種數據流圖,展現了數據是如何從左到右流向最後的節點,每條邊表明一條數據流,寬度表明數據流的大小。桑基圖經常使用於流量分析,能夠很清楚的看出數據是如何漸漸分流的。本文着重講解如何實現,理論方面的東西各位能夠自行了解。html
關鍵點有兩個:node
桑基圖要展示的數據流,算是圖(拓撲類、網絡型或關係型)數據的一種。實現一個數據可視化圖,最重要的就是拆解元素。而實現一個圖數據可視化,則最重要的是分清「節點」和「邊」。git
拆解元素以後,最重要的即是座標的計算,這裏包括點和邊的座標。而圖形中,任何的元素均可以看做是點連線而成,因此元素座標的計算實際上就成了點座標的計算。好比桑基圖中,節點是一個矩形,那麼只需計算兩個點(左上和右下)的座標(x0, y0),(x1, y1)
即可肯定;邊是一個帶形,須要計算四個端點才能肯定,帶形的弧度則可由簡單的三次貝塞爾曲線計算得來。github
由此觀之,實現桑基圖的核心在於計算出以上的這些點座標。其實實現任意一種可視化都是計算點的座標。算法
當數據量到必定程度的時候, 桑基圖中的邊會出現重疊現象,形成必定的視覺混亂。如何減小能夠閱讀本文第二節。後端
經典的圖數據結構通常是鄰接矩陣和鄰接表,咱們也能夠本身設計。我在作拓撲數據可視化的時候,會先和後端或數據同窗商定好我須要拿到的數據結構,一般是這個樣子:網絡
{ nodes: [ { foo: bar }, { foo: baz }, ... ], links: [ { source: 0, target: 1, value: 100 }, { source: 1, target: 2, value: 10 }, ... ] }
而我拿到以後要作的第一步就是先把 nodes 和 links 串聯起來,這裏每一個 link 的 source 和 target 分別是 nodes 的下標,固然你也能夠設置其餘的引用(指針),總之經過引用講二者串聯起來,變成:數據結構
{ nodes: [ { foo: bar, column: 0, // 節點所在第幾列 row: 0, // 節點所在第幾行 value: 100, // 節點數據流大小 sourceLinks: [ { source: 0, target: 1, ... } ], targetLinks: [ ... ] }, ... ], links: [ { source: 0, target: 1, value: 100, sourceNode: { foo: bar, column: 0, row: 0, ... }, targetNode: { ... } }, ... ] }
這樣,對於某個節點來講,能夠直接用 O(1) 的時間複雜度訪問到它的任意相鄰節點。ide
這裏的計算方法可本身定,一般是取該節點入邊和出邊的數據流大小之和的最小值。函數
在桑基圖的計算中,咱們還須要進行一個關鍵的計算——計算節點在桑基圖中的第幾行第幾列。
第幾列的計算,即爲節點在圖中的深度計算:
第幾行的計算,涉及到排序的問題,一般某一列中的節點都是按節點數據流大小,從大到小排序。
剛纔咱們說過,座標計算能夠分爲兩部分:節點和邊。其中,邊的座標位置依賴於節點的座標,因此應該先計算節點座標。
但在計算座標以前,首先要明確一個問題:是否限定視圖的寬高。這個問題引伸出兩種節點座標的計算方式。
若是不限定寬高,那麼節點座標的計算步驟很簡單:
大體是這個思路,橫座標的計算取決於兩個值,節點寬度和 節點水平間距;縱座標的計算取決於 節點的數據流大小 和 節點垂直間距。
具體的計算代碼,可根據你本身的數據結構來調整。
若是限定寬高,那麼計算步驟須要換個思路:
這個思路是 d3-sankey 的實現思路。若是你有限定視圖寬高的需求,那麼能夠直接使用 d3-sankey。
只要肯定了節點座標,邊的座標能夠根據它源節點和目標節點的座標來算出:
以上操做能夠經過遍歷每一個 node 的 sourceLinks 和 targetLinks 來計算。獲得邊的四個端點之後,就能夠算出三次貝塞爾曲線的控制點了:
一般要減小邊的交叉,能夠採用下面兩種方法:
均值排序這個名字是我本身起的。。不過這個方法很實用有效。
對於每一個源節點來講,都有相連的目標節點。這裏的「均值」指的是全部相連目標節點所在行數的平均值(全部目標節點的行數相加,除以目標節點個數),這個平均值能夠大體描述該節點每一個出邊的位置。每條出邊都有這樣一個值,這個值越小,則說明該出邊要鏈接的目標節點的位置越靠上,反之越靠下。因此可根據這個值,從小到大排出出邊在該節點上從上到下的位置。
我參與的 UBA (User Behavior Analytics 內部項目) 項目中,正好用到了桑基圖。除了上述的圖形繪製以外,主要複雜的是交互。
如圖所示,除了基本的 hover 交互以外,項目中主要還有
整個桑基圖實現下來發現繪製只是一些計算,交互纔是更難抽象和處理的部分。
綜上,桑基圖是一個 展示數據流很是好用的視圖,感興趣的同窗能夠本身實現一個試試。除了我文章中這些基本的桑基圖佈局,你還能夠試試其餘變種,另外交互方面也能夠突破剛纔我提到的那些,好比我以前實現過點擊節點進行摺疊/展開的交互。整體來講可視化仍是一個比較有意思的方向。
本做品採用知識共享 署名-非商業性使用-禁止演繹 4.0 國際 許可協議進行許可。