159_模型_Power BI 地理分析之形狀地圖

  • 2022 年 7 月 12 日
  • 筆記

159_模型_Power BI 地理分析之形狀地圖

聲明以下地圖元素僅供學習交流所用,如需地圖公開使用請提前做好報審工作。

一、背景

當企業的體量達到一定體量的時候,保持穩定的增長是非常重要的事情。本案例展示如何用 Power BI 的形狀地圖來尋求業務的增長。

我們先來看結論:

  • 省級市場共計:34 個,已開拓:34 個;佔比:100.0%。

  • 地市級市場共計:370 個,已開拓:214 個;佔比:57.8%。

  • 區縣級市場共計:2875 個,已開拓:356 個;佔比:12.4%。

其實從這個三條結論來看,市場層級越下沉,其實我們的空白市場越多;當然要業務能支撐這樣的規模才行。

通過三張圖,就讓各大區領着各自團隊回去開會,制定一個空白市場開發的計劃及相應的配套預算。

Power BI 公共 web 效果://demo.jiaopengzi.com/pbi/159-full.html

159-1

159-2

159-3

二、模型設計

1、地圖數據

要分析從 省份>地市>區縣 三個層級的地理業務數據,首先要準備的是 省份、地市、區縣 三個層級的地理數據。

數據獲取可以從阿里雲的 DataV.GeoAtlas(//datav.aliyun.com/portal/school/atlas/area_selector) 獲取。

159-4

簡單的數據獲取直接從這裡獲取即可,但是我們需要的 省份、地市、區縣 三級的數據,那麼我們就是用 Python 獲取這部分數據。

數據拿到以後還要做相應的清洗,清洗不必要的字段信息;這裡獲取的數據是 GeoJSON 格式;但是 Power BI 的形狀地圖(//docs.microsoft.com/zh-cn/power-bi/visuals/desktop-shape-map)需要使用的是 TopoJSON 格式數據。

GeoJSON 轉換為 TopoJSON 我們使用開源的工具 mapshaper (//github.com/mbloch/mapshaper) 轉換即可。數量不是特別多的話可以使用可視化的方式轉換將 GeoJson 格式數據導入到 //mapshaper.org/ 導出即可。

159-5

如果無法打開網站還可以在本地搭建服務,依賴 Node.js ,命令行安裝即可。

npm install -g mapshaper

安裝好以後,通過命令啟動服務;在本地運行 mapshaper Web 界面

mapshaper-gui

也可以通過命令行的方式來進行 GeoJSON 轉換為 TopoJSON ; -i 是輸入 GeoJSON 路徑; -o 是輸出 TopoJSON 路徑。

mapshaper -i D:\Desktop\map\map_data\geo\country\L0_L1_country.json -o D:\Desktop\map\map_data\topo\country\L0_L1_country.json format=topojson

更多的信息可以參考://github.com/mbloch/mapshaper

Python 配合 mapshaper 可以批量地拆分和轉換 GeoJSON 數據。

以上工作筆者已經做好了,只需要在附件中獲取清洗好的現成數據即可。

159-6

topo中有三個文件 country、province、city 文件夾中的內容命令規則如下,其中 adcode 代表地區的編碼。

這樣可滿足合併和拆分的地圖數據的需求。

# L0-全國 L1-省份 L2-地市 L3-區縣 文件夾 文件命名規則
1 country L0_L1_country
2 country L0_L2_country
3 country L0_L3_country
4 province L1_L2_province_adcode
5 province L1_L3_province_adcode
6 city L2_L3_city_adcode

2、區域維度數據

如下圖,從大區>省份>城市>區縣 四個維度的數據分別都整理好了,同時兼容了直轄市、特區、縣級市以及灣灣的層級數據。

159-7

3、模型關係

數據基本介紹,請在之前的文章中查閱(//jiaopengzi.com/1435.html)。

159-8

三、度量值及可視化

1、度量值

159-9

Ⅰ、基礎的業務度量值:0001_銷售金額。

0001_銷售金額 = 
SUM ( 'T05_訂單子表'[F_06_產品銷售金額] ) / 10000 

Ⅱ、市場佔有結論語句度量值:Map_Area_Count ;L1-L3分別代表省份、地市、區縣。

Map_Area_Count_L1 = 
VAR Table_ID =
    VALUES ( 'D01_省份表'[F_02_省ID] )
VAR Table_All =
    ADDCOLUMNS ( Table_ID, "@value", [0001_銷售金額] )
VAR Table_Sale = FILTER( Table_All ,[@value] <> BLANK())
VAR FZ =
    COUNTROWS ( Table_Sale )
VAR FM =
    COUNTROWS ( 'D01_省份表' )
VAR Format_1 =
    FORMAT ( DIVIDE ( FZ, FM, BLANK () ), "#0,0.0%" )
RETURN
    "省級市場共計:" & FM & "個,已開拓:" & FZ & "個;佔比:" & Format_1

Ⅲ、數據向下鑽取後標題名稱:Map_Area_Title ;L1-L2分別代表省份、地市。

Map_Area_Title_L1 = SELECTEDVALUE('D01_省份表'[F_05_省簡稱2])

Ⅳ、數據向下鑽取後,形狀地圖的色彩飽和度度量值:Map_Drill ;L2-L3分別代表地市、區縣。這裡需要兼容一個形狀地圖不顯示沒有數據的區域,那麼我們需要構造下鑽後的所有區域的數據,沒有的數據就是 0 。

Map_Drill_L2 = 
VAR PARENT_ID =
    SELECTEDVALUE ( 'D02_城市表'[F_01_省ID] )
VAR TABLEY =
    ADDCOLUMNS (
        'D02_城市表',
        "@VALUE",
            VAR p = [F_01_省ID]
            RETURN
                IF ( p = PARENT_ID, '00_Measure'[0001_銷售金額] + 0, '00_Measure'[0001_銷售金額] )
    )
VAR TABLEZ =
    FILTER ( TABLEY, [F_01_省ID] = PARENT_ID )
RETURN
    SUMX ( TABLEZ, [@VALUE] )

Ⅴ、由於 Power BI 目前是圖例來顯示數據的多少的,我們用 SVG 構造一個圖例:SVG_Html_Legend ;L1-L3分別代表省份、地市、區縣。

SVG_Html_Legend_L1 = 
VAR table_all =
    CALCULATETABLE ( 'D01_省份表', ALL ( 'D01_省份表'[F_02_省ID] ) )
VAR table_add =
    ADDCOLUMNS ( table_all, "@value", [0001_銷售金額] )
VAR value_max =
    FORMAT ( MAXX ( table_add, [@value] ), "#,0" )
VAR value_min =
    FORMAT ( MINX ( table_add, [@value] ), "#,0" )
VAR value_ac =
    FORMAT ( [0001_銷售金額], "#,0" )
VAR FM =
    MAXX ( table_add, [@value] ) - MINX ( table_add, [@value] )
VAR FZ =
    MAXX ( table_add, [@value] ) - [0001_銷售金額]
VAR path_y = 160 * FZ / FM + 20
VAR TF0 =
    HASONEVALUE ( 'D01_省份表'[F_02_省ID] )
VAR TF1 =
    HASONEFILTER ( 'D01_省份表'[F_04_省簡稱1] ) 
VAR SVG_start_image = "data:image/svg+xml;utf8," //SVG 圖像類型頭部。
VAR SVG_start_html = "<svg id='jiaopengzi' width='100' height='200' viewBox='0 0 100 200' xmlns='//www.w3.org/2000/svg' version='1.1'>" //SVG html類型頭部。
VAR SVG_end = "</svg>"//SVG 結束標籤。
VAR SVG_defs = "
	<defs>
		<linearGradient id='jiaopengzi-linear' x1='0%' y1='100%' x2='0%' y2='0%'>
			<stop offset='0%' stop-color='#FFFFDD' />
			<stop offset='100%' stop-color='#C19220' />
		</linearGradient>
	</defs>
" 
VAR SVG_content_0 = "
	<rect x='0' y='20' width='32' height='160' fill='url(#jiaopengzi-linear)' />
	<g fill='#1E2F56' font-family='Microsoft Yahei' font-size='10' text-anchor='start' font-weight='bold'>
		<text x='32' y='20' dominant-baseline='text-after-edge'>" & value_max & "</text>
		<text x='32' y='180' dominant-baseline='text-before-edge'>" & value_min & "</text>
	</g>
"// 當沒有篩選的時候,path 中間的 text 不出現。
VAR SVG_content_1 = "
	<rect x='0' y='20' width='32' height='160' fill='url(#jiaopengzi-linear)' />
	<path fill='red' stroke='' d='M0 0 L-10 -5 L-10 5 Z' transform='translate(32," & path_y & ")' />
	<g fill='#1E2F56' font-family='Microsoft Yahei' font-size='10' text-anchor='start' font-weight='bold'>
		<text x='32' y='20' dominant-baseline='text-after-edge'>" & value_max & "</text>
		<text x='32' y='" & path_y & "' dominant-baseline='middle'>" & value_ac & "</text>
		<text x='32' y='180' dominant-baseline='text-before-edge'>" & value_min & "</text>
	</g>
"
VAR SVG_content1 =
    IF ( TF0 * TF1, SVG_content_1, SVG_content_0 )
VAR SVG_content =
    SWITCH ( TRUE (), TF0 && TF1, SVG_content_0, TF0, SVG_content_1, SVG_content_0 )
VAR SVG_html = SVG_start_html & SVG_defs & SVG_content & SVG_end
VAR SVG_image = SVG_start_image & SVG_html
RETURN
    SVG_html

Ⅵ、最後在形狀地圖工具提示中增加區域層級顯示。

Tips_Org_Map = 
VAR L0 =
    CALCULATE ( SELECTEDVALUE ( 'D00_大區表'[F_02_大區] ), 'D03_區縣表' )
VAR L1 =
    CALCULATE ( SELECTEDVALUE ( 'D01_省份表'[F_05_省簡稱2] ), 'D03_區縣表' )
VAR L2 =
    CALCULATE ( SELECTEDVALUE ( 'D02_城市表'[F_03_城市] ), 'D03_區縣表' )
VAR L3 =
    SELECTEDVALUE ( 'D03_區縣表'[F_03_區縣] )
VAR TF1 =
    HASONEVALUE ( 'D01_省份表'[F_05_省簡稱2] )
VAR TF2 =
    HASONEVALUE ( 'D02_城市表'[F_03_城市] )
VAR TF3 =
    HASONEVALUE ( 'D03_區縣表'[F_03_區縣] )
VAR ORG =
    SWITCH (
        TRUE (),
        TF3,
            L0 & "|" & L1 & "|" & L2 & "|" & L3,
        TF2,
            L0 & "|" & L1 & "|" & L2,
        TF1,
            L0 & "|" & L1,
        L0 & "|" & L1
    )
RETURN
    ORG

2、可視化

我們重點介紹案例中的形狀地圖,其它的內容可以在附件中查看。

159-10

在設置視覺對象格式下面,打開地圖設置,映射類型選擇:自定義地圖;添加上文提到的 TopoJSON 格式的地圖,投影根據自身需要選擇,一般選擇 Mercator 。

注意這裡的映射字段,形狀地圖 TopoJSON 數據清洗過後,只有兩個關鍵字段,一個 adcode 另外一個是 name ,我們使用 adcode 作為唯一表示,因為 name 可能會重複。

省市縣分別對應到我們的維度表裏面省市縣的 ID 。

159-11

圖例,根據條件創建度量值,使用三方視覺對象 HTML Content 製作最大值和最小值的顏色過渡圖例,當選中地圖元素可以顯示具體位置。

159-12

在形狀地圖中可以鑽取到下層數據。

159-13

下鑽後的頁面以及度量值關係,區縣的數據同理。

159-14

四、總結

1、形狀地圖目前還是預覽的狀態,必須在 Power BI Desktop 中啟用。 若要啟用「形狀地圖」,請選擇「文件」>「選項和設置」>「選項」>「預覽功能」,然後選中「形狀地圖視覺對象」複選框。

2、目前形狀地圖還有很多不靈活的地方,比如不能在地圖上顯示文本標籤,地圖填充顏色還是寫死的,不能通過 DAX 來動態驅動。

3、當前區縣一級的 TopoJson 比較大,使用的時候及時保存,避免不要的麻煩。

4、由於歷史原因,當前地圖數據對於灣灣的數據只有一個大致的,沒有更細粒度的數據。更細粒度的數據應該在不遠的將來可以使用了。

附件下載

//jiaopengzi.com/2816.html

視頻課

//jiaopengzi.com/all-course

by 焦棚子