159_模型_Power BI 地理分析之形状地图
159_模型_Power BI 地理分析之形状地图
声明以下地图元素仅供学习交流所用,如需地图公开使用请提前做好报审工作。
一、背景
当企业的体量达到一定体量的时候,保持稳定的增长是非常重要的事情。本案例展示如何用 Power BI 的形状地图来寻求业务的增长。
我们先来看结论:
省级市场共计:34 个,已开拓:34 个;占比:100.0%。
地市级市场共计:370 个,已开拓:214 个;占比:57.8%。
区县级市场共计:2875 个,已开拓:356 个;占比:12.4%。
其实从这个三条结论来看,市场层级越下沉,其实我们的空白市场越多;当然要业务能支撑这样的规模才行。
通过三张图,就让各大区领着各自团队回去开会,制定一个空白市场开发的计划及相应的配套预算。
Power BI 公共 web 效果:https://demo.jiaopengzi.com/pbi/159-full.html
二、模型设计
1、地图数据
要分析从 省份>地市>区县 三个层级的地理业务数据,首先要准备的是 省份、地市、区县 三个层级的地理数据。
数据获取可以从阿里云的 DataV.GeoAtlas(https://datav.aliyun.com/portal/school/atlas/area_selector) 获取。
简单的数据获取直接从这里获取即可,但是我们需要的 省份、地市、区县 三级的数据,那么我们就是用 Python 获取这部分数据。
数据拿到以后还要做相应的清洗,清洗不必要的字段信息;这里获取的数据是 GeoJSON 格式;但是 Power BI 的形状地图(https://docs.microsoft.com/zh-cn/power-bi/visuals/desktop-shape-map)需要使用的是 TopoJSON 格式数据。
GeoJSON 转换为 TopoJSON 我们使用开源的工具 mapshaper (https://github.com/mbloch/mapshaper) 转换即可。数量不是特别多的话可以使用可视化的方式转换将 GeoJson 格式数据导入到 https://mapshaper.org/ 导出即可。
如果无法打开网站还可以在本地搭建服务,依赖 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
更多的信息可以参考:https://github.com/mbloch/mapshaper
Python 配合 mapshaper 可以批量地拆分和转换 GeoJSON 数据。
以上工作笔者已经做好了,只需要在附件中获取清洗好的现成数据即可。
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、区域维度数据
如下图,从大区>省份>城市>区县 四个维度的数据分别都整理好了,同时兼容了直辖市、特区、县级市以及湾湾的层级数据。
3、模型关系
数据基本介绍,请在之前的文章中查阅(https://jiaopengzi.com/1435.html)。
三、度量值及可视化
1、度量值
Ⅰ、基础的业务度量值: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='http://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、可视化
我们重点介绍案例中的形状地图,其它的内容可以在附件中查看。
在设置视觉对象格式下面,打开地图设置,映射类型选择:自定义地图;添加上文提到的 TopoJSON 格式的地图,投影根据自身需要选择,一般选择 Mercator 。
注意这里的映射字段,形状地图 TopoJSON 数据清洗过后,只有两个关键字段,一个 adcode 另外一个是 name ,我们使用 adcode 作为唯一表示,因为 name 可能会重复。
省市县分别对应到我们的维度表里面省市县的 ID 。
图例,根据条件创建度量值,使用三方视觉对象 HTML Content 制作最大值和最小值的颜色过渡图例,当选中地图元素可以显示具体位置。
在形状地图中可以钻取到下层数据。
下钻后的页面以及度量值关系,区县的数据同理。
四、总结
1、形状地图目前还是预览的状态,必须在 Power BI Desktop 中启用。 若要启用“形状地图”,请选择“文件”>“选项和设置”>“选项”>“预览功能”,然后选中“形状地图视觉对象”复选框。
2、目前形状地图还有很多不灵活的地方,比如不能在地图上显示文本标签,地图填充颜色还是写死的,不能通过 DAX 来动态驱动。
3、当前区县一级的 TopoJson 比较大,使用的时候及时保存,避免不要的麻烦。
4、由于历史原因,当前地图数据对于湾湾的数据只有一个大致的,没有更细粒度的数据。更细粒度的数据应该在不远的将来可以使用了。
附件下载
https://jiaopengzi.com/2816.html
视频课
https://jiaopengzi.com/all-course
by 焦棚子
159_模型_Power BI 地理分析之形状地图的更多相关文章
- 155_模型_Power BI & Power Pivot 进销存之安全库存
155_模型_Power BI & Power Pivot 进销存之安全库存 一.背景 谈进销存的概念时,我们也需要提及另外一个概念:安全库存. 库存周转在理想的状态下是做到零库存,但是在内部 ...
- 158_模型_Power BI 使用 DAX + SVG 打通制作商业图表几乎所有可能
158_模型_Power BI 使用 DAX + SVG 打通制作商业图表几乎所有可能 一.背景 最近对 Power BI 中使用 SVG 比较感兴趣,今天我们使用 DAX + SVG 复刻一下 Ze ...
- 151-模型-Power BI&Power Pivot模型DAX函数使用量分析
151-模型-Power BI&Power Pivot模型DAX函数使用量分析 1.背景 我们在 Power BI 或者 Power Pivot 项目中会写很多的 DAX 表达式.在最后项目交 ...
- 163_技巧_Power BI 一键批量建立自定义字段参数
163_技巧_Power BI 一键批量建立自定义字段参数 一.背景 在 2022 年 5 月开始,Power BI 新增了一个非常有用的功能字段参数.再也不用写一串的 SWITCH 了.字段参数的效 ...
- [阿里DIN]从模型源码梳理TensorFlow的形状相关操作
[阿里DIN]从模型源码梳理TensorFlow的形状相关操作 目录 [阿里DIN]从模型源码梳理TensorFlow的形状相关操作 0x00 摘要 0x01 reduce_sum 1.1 reduc ...
- 160_技巧_Power BI 新函数-计算工作日天数
160_技巧_Power BI 新函数-计算工作日天数 一.背景 Power BI 2022 年 7 月 14 日更新了最新版本的,版本号为:2.107.683.0 . 更多更新内容可以查看官方博客: ...
- 161_可视化_Power BI 复刻 GitHub 贡献热力图
161_可视化_Power BI 复刻 GitHub 贡献热力图 一.背景 在 GitHub 上,有用户的贡献度的热力图如下: Power BI 公共 web 效果:https://demo.jiao ...
- 跨平台移动开发_PhoneGap 使用Geolocation基于所在地理位置坐标调用百度地图API
使用Geolocation基于所在地理位置坐标调用百度地图API 效果图 示例代码 <!DOCTYPE html> <html> <head> <title& ...
- GIS规划应用——基于哈夫模型的GIS服务区分析
1. GIS服务区分析 区位因素是商业分析中一个至关重要的因素,因此在商店选址时,例行的服务区分析十分重要.服务区是指顾客分布的主要区域,在其范围内该店的商品销售量或服务营业额超过其竞争对手.对于现 ...
随机推荐
- 记一次 PHP 省市县三级联动 数据库取值
/** * Notes:省市县三级联动 * Created by depressiom * Date: 2022年4月14日 */ public function getCityData(){ //获 ...
- Linux 环境变量配置的 6 种方法,建议收藏
关注「开源Linux」,选择"设为星标" 回复「学习」,有我为您特别筛选的学习资料~ Linux环境变量配置 在自定义安装软件的时候,经常需要配置环境变量,下面列举出各种对环境变量 ...
- input 相关
1.label 标签 for 属性同 input 标签 id 属性联系之一
- selenium模块 phantomJs 谷歌无可视界面
参考微博: 什么是selenium 一款基于浏览器自动化的模块 什么是浏览器自动化 通过脚本程序或者python代码,这组程序或者代码表示一些行为动作,selenium可以让这些行为动作映射到浏览器中 ...
- 一款高速的NET版的离线免费OCR
PaddleOCR.Onnx 一款基于Paddle的OCR,项目使用ONNX模型,速度更快.本项目同时支持X64和X86的CPU上使用.本项目是一个基于PaddleOCR的C++代码修改并封装的.NE ...
- c++动态内存分配需要注意的地方,可以不用尽量不用
在实际开发中,需要动态分配内存的场景极少,string和vector已经足够方便,如果不是非用不可的情况,采用动态分配内存就是给自己挖坑. 如果应用开发中一定要用动态内存分配技术,建议把它封装在类中, ...
- SUSE系统---keepalived的搭建
作为博客第一篇,先小尝初试一下搭建keepalived,因为项目需要搭建集群,为了满足需要,需要服务器对外暴露个虚拟IP,进行集群部署. 第一步:先把keepalived.tra.gz压缩包放到相应目 ...
- git rename branch
git 不能直接重命名远程分支,如果需要重命名则执行以下步骤操作: 重命名本地分支 删除远程分支 推送本地分支(重命名后的)到远程 额外说明: 1. 重命名后的分支也会保留历史 commit(应该是本 ...
- 基于Python的渗透测试信息收集系统的设计和实现
信息收集系统的设计和实现 渗透测试是保卫网络安全的一种有效且必要的技术手段,而渗透测试的本质就是信息收集,信息搜集整理可为后续的情报跟进提供强大的保证,目标资产信息搜集的广度,决定渗透过程的复杂程度, ...
- 贝塞尔曲线在Unity中的应用
前言:国庆放假后基本整个人的散掉了.加之种种原因,没时间没心情写博客.最近研究了一下3d的一些效果.其中有类似翻书撕纸的操作,可是一个panel怎么由平整的变成弯曲的呢? 两点可以确定一条直线,三点可 ...