DAX驱动图表设计
Synoptic Panel是Power BI中显示着色地图的良好载体,然而它的缺陷也不少,比方:
- 数据标签不能多个(例如同时显示业绩和业绩达成)
- 地图大小无法随着外部切片的变化而自适应
- 地图无法层级切换(比方全国切换到省市)
针对第二个缺陷,例如切片器选择青海,Synoptic Panel其实仍然显示的是全国,只是青海有数据。
在图表设置区,可以勾选不显示无数据区域,但是青海的地图会非常小,无法自动放大,和画布大小不匹配。
本文尝试解决多数据标签和地图自适应画布大小的问题,地理层级切换后续文章会讲到。以下动图是自适应的解决效果:
解决方案还是SVG地图(公众号后台回复SVG地图可以获取世界、全国、省市区县地图下载链接),但是放弃使用Synoptic Panel作为显示载体。
首先要对地图数据进行整理。记事本打开一份SVG地图,你看到的可能是密密麻麻不知所云的符号:
不要被长长的代码吓到,核心元素其实可以简写为如下:
代码语言:javascript复制<svg xmlns='http://www.w3.org/2000/svg' viewbox='0 0 649 640'>
<path 画的A地区地理形状 title='A地区' fill='灰色'></path>
<path 画的B地区地理形状 title='B地区' fill='灰色'></path>
<path 画的C地区地理形状 title='C地区' fill='灰色'></path>
</svg>
把每个path写入列,和Power BI数据中的地理位置名称对应,如下图中的省份地图列:
写入的方式有两种,一种是记事本打开地图,手动复制每个path,Switch函数切换写入。另外一种是将地图文件使用Power Query导入,按照</path>拆分列实现。
除了获取每个地区的path(也就是形状)之外,还需要精确获取每个地区在整个地图的位置以及占用的画布大小,这两个数据可以使用inkscape(免费软件)打开地图,选中每个地区,获得:
例如,内蒙古在地图文件的起始位置横向X在261.753,纵向Y在34.025,占用的画布宽度为252.572,高度为185.681。新建列,将每个地区的以上四个数据存入Power BI,如下图所示:
创建一个地图度量值:
代码语言:javascript复制自适应地图 =
VAR t =
SUMMARIZE ( '表', '表'[省份简称], '表'[省份地图], '表'[省份标签位置] )
VAR map =
ADDCOLUMNS (
t,
"着色地图",
IF (
[值] >= 5000,
SUBSTITUTE ( [省份地图], "#FFF", "DarkCyan" ),
SUBSTITUTE ( [省份地图], "#FFF", "Tomato" )
),
"省份标签",
"<text font-size='12' text-anchor='middle' " & [省份标签位置] & ">" & [省份简称] & "</text>"
)
RETURN
"<svg xmlns='http://www.w3.org/2000/svg' width='649' height='640' viewbox='"
& IF (
HASONEVALUE ( '表'[省份简称] ),
SELECTEDVALUE ( '表'[X_省份图形] ) & " "
& SELECTEDVALUE ( '表'[Y_省份图形] ) & " "
& SELECTEDVALUE ( '表'[Width_省份图形] ) & " "
& SELECTEDVALUE ( '表'[Height_省份图形] ),
"0 0 649 640"
) & "'>"
& CONCATENATEX ( map, [着色地图] )
& CONCATENATEX ( map, [省份标签] ) & "</svg>"
把以上度量值放入Html content,地图即可正常显示。
地区的默认颜色是白色,ADDCOLUMNS新增列使用IF语句使得颜色发生动态变化。
整个地图的大小是固定的(本例为649像素宽,640像素高),所以省份标签的位置固定,ADDCOLUMNS使用省份标签的位置为每个省份设立类别标签。这里也可以设置任意多个数据标签,将text包裹的[省份简称]替换即可,例如替换为[业绩]&[业绩达成率]。
难点在于Return后的内容,CONCATENATEX串联起了所有地区的图形以及数据标签。这里对viewbox进行了自定义,这是地图可以自适应画布的关键。
viewbox和width、height是什么关系?
viewbox有四个参数 例如 0 0 649 640表示X轴从0开始,Y轴从0开始,宽度649,高度640的图形。
width=649 height=640看上去和viewbox定义了相同大小的图形。但是本质有所不同。
前端专家张鑫旭老师有个精彩的比喻:
width、height就像整个计算机屏幕,viewBox就是截屏工具选中的那个框框,最终的呈现就是把框框中的截屏内容再次在显示器中全屏显示! 张鑫旭
比如对于内蒙古,它的宽度高度远远小于整个画布大小,把它的宽度高度用viewbox包裹起来,就能起到放大的效果。而[X_省份图形]和[Y_省份图形]替换viewbox的前两个参数,意味着这是”截屏“的起点。
以上是地图自适应画布的完整逻辑。前期比较辛苦的是每个地区的图形需要整理到报表中,但好在只需要整理一次。