展示清楚库存结构只需一张图
黄成明老师的《数据化管理》一书中,介绍过一个库存切割图(P143),如下图所示,只需一张图表即可清楚展示库存全貌。

黄老师的公众号近日有介绍如何在Excel中实操,本文介绍怎么在Power BI中实现类似的功能。

有读者可能会想到使用Power BI内置的堆积条形图/柱形图实现,很遗憾,这种方法无法实现上图中的数据标签。因此,需要我们书写比较长的公式自造图表。示例仅对库存量进行实操,SKU层级雷同。
本文的方案有三个特色:互动性佳,数据可随切片器的变化而变化;灵活性好,数据维度可随时增加或减少;重点突出,渐变式配色,随着库存量增加颜色逐渐变深。以下进行详细说明。
准备好库存数据,导入Power BI,新建以下度量值,使用支持SVG的第三方图表(如Image by CloudScope)在画布中将该度量值展示出来,即可看到上图的效果。

库存结构图 = VAR Title_Width = 25//轴标签宽度VAR Height = 20 //单个维度高度VAR W =CALCULATE([库存量],ALLSELECTED('明细'))/240VAR T1=SELECTCOLUMNS(VALUES('明细'[上下装]),"分组","上下装","分组内容",[上下装],"库存",[库存量],"分组索引",1,"颜色","Crimson")VAR T2=SELECTCOLUMNS(VALUES('明细'[年份]),"分组","年份","分组内容",[年份],"库存",[库存量],"分组索引",2,"颜色","Orange")VAR T3=SELECTCOLUMNS(VALUES('明细'[季节]),"分组","季节","分组内容",[季节],"库存",[库存量],"分组索引",3,"颜色","Olive")VAR T4=SELECTCOLUMNS(VALUES('明细'[性别]),"分组","性别","分组内容",[性别],"库存",[库存量],"分组索引",4,"颜色"," Green")VAR T5=SELECTCOLUMNS(VALUES('明细'[类别]),"分组","类别","分组内容",[类别],"库存",[库存量],"分组索引",5,"颜色","DarkCyan")VAR T6=SELECTCOLUMNS(VALUES('明细'[货龄区间]),"分组","货龄区间","分组内容",[货龄区间],"库存",[库存量],"分组索引",6,"颜色","CadetBlue")VAR Big_T=UNION(T1,T2,T3,T4,T5,T6)VAR T_Plus=ADDCOLUMNS(Big_T,"滚动库存",SUMX(FILTER(Big_T,EARLIER([分组])=[分组]&&EARLIER([库存])<=[库存]),[库存])-[库存],"组内最大值",MAXX(FILTER(Big_T,EARLIER([分组])=[分组]),[库存]))VAR T_Plus_Plus=ADDCOLUMNS(T_Plus,"Rect","<rect x='" & Title_Width+[滚动库存]/W+Title_Width/W & "' y='"&Height*([分组索引]-1)&"' width='" & [库存] / W & "' height='" & Height-1 & " ' fill='"&[颜色]&"' opacity='"&[库存]/[组内最大值]*0.9&"'/>","Label",//数据标签位置IF(LEN([分组内容]&" ["&FORMAT ( ROUND ( [库存], 0 ), "#,###" ) &"]")*5+1>=[库存]/W,"<text x='" & Title_Width+[滚动库存]/W+1 & "' y='"&5+Height*([分组索引]-1)&"' fill='black' text-anchor='left' font-size='"&5*([库存]/W)/(LEN([分组内容]&" ["&FORMAT ( ROUND ( [库存], 0 ), "#,###" ) &"]")*5+2)&"' >"& [分组内容]&" ["&FORMAT ( ROUND ( [库存], 0 ), "#,###" ) &"]"& "</text>","<textx='"&Title_Width+[滚动库存]/W+1&"'y='"&5+Height*([分组索引]-1)&"'fill='black'text-anchor='left'font-size='5'>"&[分组内容]&"["&FORMAT(ROUND([库存],0),"#,###")&"]"&"</text>"))//加1为了向右挪动一个像素VAR SVG ="data:image/svg+xml;utf8,"&"<svg xmlns='http://www.w3.org/2000/svg' height='" & Height*6 & "' width='" & Title_Width + 240 & "'>" & "<text font-size='6'><tspan x='6' y='12'>上下装</tspan><tspan x='12' y='32'>年份</tspan><tspan x='12' y='52'>季节</tspan><tspan x='12' y='72'>性别</tspan><tspan x='12' y='92'>类别</tspan><tspan x='0' y='112'>货龄区间</tspan></text>"&//轴标签CONCATENATEX ( T_Plus_Plus, [Rect] & [Label]) & "</svg> "RETURNSVG
之前你可能需要很多图表展示库存结构,现在只需要一个,以下对原理进行解释。

1.构造纵向维度表
表中有6个维度,分别是上下装、年份、季节、性别、类别和货龄区间,需要合并成以下效果。

首先使用SELECTCOLUMNS对原始数据中需要的字段进行挑选和重命名,接着UNION合并六张子表。以下是此过程的单独列示,实际需要嵌入上方的很长的那个公式。
合并表 = VAR T1=SELECTCOLUMNS(VALUES('明细'[上下装]),"分组","上下装","分组内容",[上下装],"库存",[库存量],"分组索引",1)VAR T2=SELECTCOLUMNS(VALUES('明细'[年份]),"分组","年份","分组内容",[年份],"库存",[库存量],"分组索引",2)VAR T3=SELECTCOLUMNS(VALUES('明细'[季节]),"分组","季节","分组内容",[季节],"库存",[库存量],"分组索引",3)VAR T4=SELECTCOLUMNS(VALUES('明细'[性别]),"分组","性别","分组内容",[性别],"库存",[库存量],"分组索引",4)VAR T5=SELECTCOLUMNS(VALUES('明细'[类别]),"分组","类别","分组内容",[类别],"库存",[库存量],"分组索引",5)VAR T6=SELECTCOLUMNS(VALUES('明细'[货龄区间]),"分组","货龄区间","分组内容",[货龄区间],"库存",[库存量],"分组索引",6)ReturnUNION(T1,T2,T3,T4,T5,T6)
2.确定矩形位置
分析该图表的结构可以得知,图表的主体是一个个矩形的拼接。拼接的方式是纵向为每个维度,横向为每个维度中的子项。

对于纵向排列,上方SELECTCOLUMNS公式操作时为每个维度添加了索引,鉴于SVG的矢量性质,索引+每个矩形的高度即可生成自动下移的效果。
对于横向排列,后面的子项目在前一个子项目的尾巴处开始展示,已知矩形宽度和库存数量呈线性关系,所以需要为合并的维度表增加滚动库存:
VAR Big_T=UNION(T1,T2,T3,T4,T5,T6)VAR T_Plus=ADDCOLUMNS(Big_T,"滚动库存",SUMX(FILTER(Big_T,EARLIER([分组])=[分组]&&EARLIER([库存])<=[库存]),[库存])-[库存],"组内最大值",MAXX(FILTER(Big_T,EARLIER([分组])=[分组]),[库存]))
搞清楚了每个维度,每个子项的坐标系,即可实操,为每个子项增加一个矩形:
VAR T_Plus_Plus=ADDCOLUMNS(T_Plus,"Rect","<rect x='" & Title_Width+[滚动库存]/W+Title_Width/W & "' y='"&Height*([分组索引]-1)&"' width='" & [库存] / W & "' height='" & Height-1 & " ' fill='"&[颜色]&"' opacity='"&[库存]/[组内最大值]*0.9&"'/>","Label",
//数据标签位置
IF(LEN([分组内容]&" ["&FORMAT ( ROUND ( [库存], 0 ), "#,###" ) &"]")*5+1>=[库存]/W,"<text x='" & Title_Width+[滚动库存]/W+1 & "' y='"&5+Height*([分组索引]-1)&"' fill='black' text-anchor='left' font-size='"&5*([库存]/W)/(LEN([分组内容]&" ["&FORMAT ( ROUND ( [库存], 0 ), "#,###" ) &"]")*5+2)&"' >"& [分组内容]&" ["&FORMAT ( ROUND ( [库存], 0 ), "#,###" ) &"]"& "</text>","<text x='" & Title_Width+[滚动库存]/W+1 & "' y='"&5+Height*([分组索引]-1)&"' fill='black' text-anchor='left' font-size='5' >"& [分组内容]&" ["&FORMAT ( ROUND ( [库存], 0 ), "#,###" ) &"]"& "</text>"))
颜色的变化蕴含在上方代码中,突出显示如下,通过opacity标签控制透明度。控制的原则是与最大库存的项目比较,比方下装库存量是上装的50%,那么透明度就在上装的基础上打五折。

3.确定坐标轴位置
坐标轴使用SVG编码中的text标签设置,tspan达到换行的目的。
"<text font-size='6'><tspan x='6' y='12'>上下装</tspan><tspan x='12' y='32'>年份</tspan><tspan x='12' y='52'>季节</tspan><tspan x='12' y='72'>性别</tspan><tspan x='12' y='92'>类别</tspan><tspan x='0' y='112'>货龄区间</tspan></text>"
以上即完成了全部制作。该图表的设置为像素级别,所以可以调整的很精确。制作过程偏复杂,但好在只要做好即可复用。读者可以自行调整代码改变为自己喜欢的样式。如有更简便的实现方式,欢迎留言。
案例文件下载: