如何 PowerBI 中構建任意復雜?;鶊D

有小伙伴問如何在 PowerBI 中實現(xiàn)復雜的?;鶊D (Sankey diagram),本文來做介紹。
桑基圖,可以相當復雜,例如:

?;鶊D,可以非常直觀地反應出:
流向
流量
節(jié)點
這可以應用到很多場景。
本文先來介紹如何在 PowerBI 中實現(xiàn)復雜?;鶊D的通用原理,后續(xù)再做復雜案例的介紹。
二階段?;鶊D
先看一個案例,用 PowerBI 實現(xiàn)如下:

這可以清楚地看到我們如何將分組匯總的數(shù)據(jù)逐步轉化到可視化,它的過程是:
縱向分組匯總(俗稱:一維透視表)
桑基圖
這個過程實現(xiàn)起來非常簡單。
首先,從 PowerBI 視覺對象庫(AppSource)導入?;鶊D,如下:

找到?;鶊D,如下:

如果您無法找到?;鶊D,請嚴格按照上述操作順序進行即可。
?;鶊D只需要三個字段就可以構建完成,如下:

例如,可以將產(chǎn)品[類別]作為源,將地理位置[地區(qū)]作為目標以及度量值[銷售額]作為權重來進行設置,如下:

構建完畢。
稱?A->B?類型的桑基圖為?二階?;鶊D。
在很多應用中,我們需要多階?;鶊D,例如三階?;鶊D如下:

甚至四階桑基圖如下:

這些案例都是用同一個?;鶊D視覺對象在 PowerBI 中實現(xiàn),不難推而廣之,這可以實現(xiàn)任意階段桑基圖(如果不構成性能問題的話)。這里是否存在通用的構建邏輯呢,答案是肯定的。
?;鶊D通用構建原理
從多階(三階或四階)?;鶊D可以觀察到這樣的規(guī)律:
?;鶊D只能設置來源,去向以及權重大?。?/p>
同一元素序列可能同時作為來源和去向;
權重只發(fā)生在有意義的連接上。
在清楚了這三條?;鶊D鐵律后,就可以構建復雜的?;鶊D了。我們的思考如下:
有且僅有一個字段作為來源,涵蓋所有來源
有且僅有一個字段作為去向,涵蓋所有去向
有且僅有一個度量值計算權重,且僅僅發(fā)生在有意義的連接上
有了這樣的思考,我們就可以用 PowerBI DAX 來做實現(xiàn)了。
構建三階?;鶊D
為了構建如下的桑基圖,如下:

根據(jù)已經(jīng)分析得到的規(guī)律,會引導我們做進一步思考:
產(chǎn)品[類別]和地理位置[地區(qū)]都需要被納入某個字段作為桑基圖的來源字段使用;地理位置[地區(qū)]和客戶[行業(yè)]都需要被納入某個字段作為?;鶊D的目標字段使用。
于是用 PowerBI DAX 構建,如下:
// 第一步,新建一個計算表,用來構建三階?;鶊D的來源字段
SanKey_Source_3 =
UNION(
SELECTCOLUMNS( VALUES( Geo[Region] ) , "SourceName" , [Region] ),
SELECTCOLUMNS( VALUES( 'Product'[Category] ) , "SourceName" , [Category] )
)
// 第二步,新建一個計算表,用來構建三階?;鶊D的去向字段
SanKey_Dest_3 =
UNION(
SELECTCOLUMNS( VALUES( Geo[Region] ) , "DestName" , [Region] ),
SELECTCOLUMNS( VALUES( Customer[Industry]) , "DestName" , [Industry] )
)
// 第三步,構建僅僅在有意義的連接上的權重度量值,新建一個度量值
Sankey3.KPI =
VAR _source = SELECTEDVALUE( SanKey_Source_3[SourceName] )
VAR _dest = SELECTEDVALUE( SanKey_Dest_3[DestName] )
VAR _source_as_product = TREATAS( { _source } , 'Product'[Category] )
VAR _source_as_geo = TREATAS( { _source } , 'Geo'[Region] )
VAR _dest_as_geo = TREATAS( { _dest } , 'Geo'[Region] )
VAR _dest_as_customer = TREATAS( { _dest } , 'Customer'[Industry] )
RETURN SWITCH( TRUE(),
_source IN VALUES( 'Product'[Category] ) && _dest IN VALUES( Geo[Region] ) ,
CALCULATE( [KPI] , _source_as_product , _dest_as_geo ) ,
_source IN VALUES( 'Geo'[Region] ) && _dest IN VALUES( Customer[Industry] ) ,
CALCULATE( [KPI] , _source_as_geo , _dest_as_customer ) ,
BLANK()
)這里的核心就在度量值的邏輯,它具有如下特點:
用?
_source獲取來源用?
_dest獲取去向再用?
TREATAS?構建可能的動態(tài)掛載器再用?
SWITCH?TRUE?的結構來判斷連接是否有意義如果有意義,則用事先準備好的動態(tài)掛載器去計算度量值
如果沒有意義,則返回空,圖表則不會在無意義的連接上形成計算
動態(tài)掛載器,并不出現(xiàn)在 PowerBI 的官方說明文檔中,由于這里的邏輯是一種動態(tài)掛載的非侵入式設計(可參考BI佐羅此前的文章),這樣的結構在編寫中通常被名詞化后形象地稱為:動態(tài)掛載器或鉤子。
如果這里的 DAX 公式?jīng)]有特別理解,再來看四階?;鶊D的構建過程,再次體會下。
構建四階?;鶊D
與構建三階?;鶊D的思考過程完全一樣,這里構建如下的桑基圖:

這需要在來源字段和去向字段裝入更多的可能,并在度量值的構建中做更多的判斷,用 PowerBI DAX 實現(xiàn)如下:
// 第一步,構建來源
SanKey_Source_4 =
UNION(
SELECTCOLUMNS( VALUES( Geo[Region] ) , "SourceName" , [Region] ),
SELECTCOLUMNS( VALUES( 'Product'[Category] ) , "SourceName" , [Category] ),
SELECTCOLUMNS( VALUES( 'Customer'[Industry] ) , "SourceName" , [Industry] )
)
// 第二步,構建去向
SanKey_Dest_4 =
UNION(
SELECTCOLUMNS( VALUES( Geo[Region] ) , "DestName" , [Region] ),
SELECTCOLUMNS( VALUES( Customer[Industry]) , "DestName" , [Industry] ),
SELECTCOLUMNS( VALUES( Customer[Occupation]) , "DestName" , [Occupation] )
)
// 第三步,構建度量值
Sankey4.KPI =
VAR _source = SELECTEDVALUE( SanKey_Source_4[SourceName] )
VAR _dest = SELECTEDVALUE( SanKey_Dest_4[DestName] )
VAR _source_as_product = TREATAS( { _source } , 'Product'[Category] )
VAR _source_as_geo = TREATAS( { _source } , 'Geo'[Region] )
VAR _source_as_customer_industry = TREATAS( { _source } , 'Customer'[Industry] )
VAR _dest_as_geo = TREATAS( { _dest } , 'Geo'[Region] )
VAR _dest_as_customer_industry = TREATAS( { _dest } , 'Customer'[Industry] )
VAR _dest_as_customer_occupation = TREATAS( { _dest } , 'Customer'[Occupation] )
RETURN SWITCH( TRUE(),
_source IN VALUES( 'Product'[Category] ) && _dest IN VALUES( Geo[Region] ) ,
CALCULATE( [KPI] , _source_as_product , _dest_as_geo ) ,
_source IN VALUES( 'Geo'[Region] ) && _dest IN VALUES( Customer[Industry] ) ,
CALCULATE( [KPI] , _source_as_geo , _dest_as_customer_industry ) ,
_source IN VALUES( 'Customer'[Industry] ) && _dest IN VALUES( Customer[Occupation] ) ,
CALCULATE( [KPI] , _source_as_customer_industry , _dest_as_customer_occupation ) ,
BLANK()
)構建完成。類似地,可以用完全一樣的套路構建多階段?;鶊D。
桑基圖的意義
如果用透視表來表達三階?;鶊D,會是這樣:

上面的透視表和下面的?;鶊D是完全等價的,但?;鶊D給出的可視化效果可以讓人立刻直覺式思考得到想要的信息。
總結
本文給出了構建?;鶊D的一般方法和套路,結合 PowerBI DAX 可以構建任意階桑基圖。
在本文給出的案例中,還有以下特點需要注意:
?;鶊D的每層節(jié)點的總流量是相等的
不存在跨層流動
不存在回流
后續(xù),我們將做更一般化的討論,將本文原理擴展到:
流量不一定相當?shù)膱鼍?/p>
存在跨層流動的場景
存在回流的場景
那就更具有一般化了。
?;鶊D,可以用來構建很多業(yè)務場景的可視化,我們也將在后續(xù)文章給出案例。
在訂閱了BI佐羅講授的《BI進行時》課程區(qū),除了可以下載本文案例,還可以觀看視頻講解。

讓數(shù)據(jù)真正成為你的力量
Create value?through?simple and?easy?with fun?by PowerBI
Excel BI?|?DAX Pro?|?DAX?權威指南?|?線下VIP學習
掃碼與PBI精英一起學習,驗證碼:data2020
PowerBI MVP 帶你正確而高效地學習 PowerBI
點擊“閱讀原文”,即刻開始
↙
