美文网首页Power BI干货PowerBI专栏
Power BI技巧:时间维度动态折叠显示

Power BI技巧:时间维度动态折叠显示

作者: PowerBI星球 | 来源:发表于2020-05-19 20:03 被阅读0次

    文/Beau

    数据分析爱好者,擅长PBI数据分析

    本文灵感来自于星球球友的一个求助帖,他的诉求是可以在矩阵中对于日期类型的列标题进行动态折叠显示。

    何为折叠呢?

    简单的说就是当切片器选择日期长度超过一周时,则折叠为周维度显示,以此类推,可由日折叠为周,周折叠为月,月折叠为季,季折叠为年,换句话说就是日期由低纬度向高维度的汇总。

    还是不明白?那就直接看效果图。

    特别提醒:

    为了便于大家理解,核心度量值代码已在源文件中做了详细注释哦。

    闲话不多说,切入正题。

    制作步骤

    1、模型概览

    模型是不是很简单?原生的三个表以及一个自建维度表,这里只建了三个度量值,所以就没有建专门的度量值表。

    关键点:

    1.这里的日期表包含列的颗粒度应尽可能的细,如下图所示,原因在于这样处理会便于后期日期维度表的创建。 

    2.对于日期表中的日名称和周名称的建立是有技巧的,日名称要包含年月,周名称要包含年,如下图所示。这样处理的目的在于我们能够方便的锁定目标数据。

    2、构造辅助表

    使用DAX新建表,如下

    日期维度表 =

    VAR y =

        ADDCOLUMNS (

            SELECTCOLUMNS(

                SUMMARIZE( '日期', '日期'[年份名称], '日期'[年份序号], '日期'[日期] ),

                "年份", '日期'[年份名称],

                "维度明细", '日期'[年份名称],

                "日期", '日期'[日期],

                "orderby",0

            ),

            "类别名称", "年"

        )

    VAR q =

        ADDCOLUMNS (

            SELECTCOLUMNS(

                SUMMARIZE( '日期', '日期'[年份名称], '日期'[季度名称], '日期'[季度序号], '日期'[日期] ),

                "年份", '日期'[年份名称],

                "维度明细", '日期'[季度名称],

                "日期", '日期'[日期],

                "orderby",1

            ),

            "类别名称", "季"

        )

    VAR m =

        ADDCOLUMNS (

            SELECTCOLUMNS(

                SUMMARIZE( '日期', '日期'[年份名称], '日期'[月份名称], '日期'[月份序号], '日期'[日期] ),

                "年份", '日期'[年份名称],

                "维度明细", '日期'[月份名称],

                "日期", '日期'[日期],

                "orderby",2

            ),

            "类别名称", "月"

        )

    VAR w =

        ADDCOLUMNS (

            SELECTCOLUMNS(

                SUMMARIZE( '日期', '日期'[年份名称], '日期'[周名称], '日期'[周序号], '日期'[日期] ),

                "年份", '日期'[年份名称],

                "维度明细", '日期'[周名称],

                "日期", '日期'[日期],

                "orderby",3

            ),

            "类别名称", "周"

        )

    VAR d =

        ADDCOLUMNS (

            SELECTCOLUMNS(

                SUMMARIZE( '日期', '日期'[年份名称], '日期'[日名称], '日期'[日值], '日期'[日期] ),

                "年份", '日期'[年份名称],

                "维度明细", '日期'[日名称],

                "日期", '日期'[日期],

                "orderby",4

            ),

            "类别名称", "日"

        )

    RETURN

        UNION ( y, q, m, w, d )

    核心思想在于利用原生日期表日期数据进行汇总合并。

    这里要注意"orderby"列字段的创建规则,从日-年按照1-4的顺序创建,这样处理是为了在可视化组件中可以按照从左往右的顺序逐级折叠。

    3.建立度量值

    需要建立的具体度量值如下所示。

    [salse]为基础度量值,这里不再赘述。

    [test]度量值为测试度量值,它并没有直接参与到最终的数据呈现中,那我为何要建立它呢?各位小伙伴可不要小看它的作用,在我们日常写特别复杂的度量时,经常会被上下文环境弄晕头,那么这个度量就是解决此问题的利器,你可以将复杂度量中的步骤一一拆解写入到测试度量中,以验证每一步的结果是否符合预期,这将使你的工作事半功倍。

    前方高能!核心度量即将登场!(代码比较长,请耐心看完。)

    view =

    --根据切片器取对应值

    VAR select_d =

       SELECTEDVALUE ( '日期'[日名称])

    VAR select_w =

       SELECTEDVALUE ( '日期'[周名称])

    VAR select_m =

       SELECTEDVALUE ( '日期'[月份名称] )

    VAR select_q =

       SELECTEDVALUE ( '日期'[季度名称] )

    VAR select_y =

       SELECTEDVALUE ( '日期'[年份名称] )

    --对周界点进行判断

    VAR tf_w =

        MOD (SELECTEDVALUE ( '日期'[周值] ), 7 )

    --判断当前上下文字段

    VAR findd =

        FIND ("D", SELECTEDVALUE ( '日期维度表'[维度明细] ),, 0 ) = 7

    VAR findw =

        FIND ("W", SELECTEDVALUE ( '日期维度表'[维度明细] ),, 0 ) = 5

    VAR findm =

        FIND ("M", SELECTEDVALUE ( '日期维度表'[维度明细] ),, 0 ) = 5

    VAR findq =

        FIND ("Q", SELECTEDVALUE ( '日期维度表'[维度明细] ),, 0 ) = 5

    VAR findy =

        FIND ("Y", SELECTEDVALUE ( '日期维度表'[维度明细] ),, 0 ) = 1

    --求当前维度的下级维度最小值

    VAR min_w_d =

        CALCULATE( MIN ( '日期'[日名称] ), FILTER (ALL ( '日期' ), [周名称] = select_w) )

    VAR min_m_w =

        CALCULATE( MIN ( '日期'[周名称] ), FILTER (ALL ( '日期' ), [月份名称] = select_m) )

    VAR min_q_m =

        CALCULATE( MIN ( '日期'[月份名称] ), FILTER (ALL ( '日期' ), [季度名称] = select_q) )

    VAR min_y_q =

        CALCULATE( MIN ( '日期'[季度名称] ), FILTER (ALL ( '日期' ), [年份名称] = select_y) )

    --返回结果

    RETURN

        SWITCH (

            TRUE(),

            findd

               && SELECTEDVALUE ( '日期维度表'[维度明细] ) <= select_d

               && SELECTEDVALUE ( '日期维度表'[维度明细] ) >= min_w_d

               && tf_w = 0 , CALCULATE ( [salse], TREATAS ( VALUES ( '日期维度表'[日期] ), '日期'[日期] ) ),

            findw

               && SELECTEDVALUE ( '日期维度表'[维度明细] ) <= select_w

                &&SELECTEDVALUE ( '日期维度表'[维度明细] )>= min_m_w

               && tf_w = 0 , CALCULATE ( [salse], TREATAS ( VALUES ( '日期维度表'[日期] ), '日期'[日期] ) ),

            findw

               && SELECTEDVALUE ( '日期维度表'[维度明细] ) < select_w

               && SELECTEDVALUE ( '日期维度表'[维度明细] ) >= min_m_w

               && tf_w > 0, CALCULATE ( [salse], TREATAS ( VALUES ( '日期维度表'[日期] ), '日期'[日期] ) ),

            findm

               && SELECTEDVALUE ( '日期维度表'[维度明细] ) < select_m

               && SELECTEDVALUE ( '日期维度表'[维度明细] ) >= min_q_m,

               CALCULATE ( [salse], TREATAS ( VALUES ( '日期维度表'[日期] ), '日期'[日期] ) ),

            findq

               && SELECTEDVALUE ( '日期维度表'[维度明细] ) < select_q

               && SELECTEDVALUE ( '日期维度表'[维度明细] ) >= min_y_q,

               CALCULATE ( [salse], TREATAS ( VALUES ( '日期维度表'[日期] ), '日期'[日期] ) ),

            findy

               && SELECTEDVALUE ( '日期维度表'[维度明细] ) < select_y,

               CALCULATE ( [salse], TREATAS ( VALUES ( '日期维度表'[日期] ), '日期'[日期] ) )

        )

    不要被它的长度吓到,代码的长度和难度并不成正比哦,下面重点对此度量进行剖析:

    为了便于理解,我将代码分成了四个部分:

    提取切片值

    对周界点判断

    对当前上下文字段进行判断

    求当前日期维度的下级维度最小值

    返回结果

    讲之前啰嗦几句,类似这种关于日期的动态展示,关键点在于逻辑的梳理,不要一上来就开始写代码,最好先在纸上将每一步需要满足的条件画出来,逐步拆解,以便于对各日期界点清晰的判断,从而做到全盘考量,不会遗漏任何细节,才能最终得出想要的结果。碍于篇幅所限,就不展开讲了。

    这里重点说一下度量的第二部分和第五部分,其余部分可以看源文件中的注释自行理解。

    对周界点判断部分

    这里采用取余函数进行判断,例如我们这里需要判断2011年3月23号是其所在周的周几,如果余数是0,则表示该天是星期日。可能细心的小伙伴会问,为何这里你只对周界点进行判断,那月度,季度,和年份界点呢?别着急,往下继续看。

    返回结果部分

    看着虽长,但是通过代码格式化后可看出基本范式是一样的,会写一种,写其他的都手到擒来。

    发现了没?为何这里的日维度和周维度的变量和别的都不一样?看着有些复杂? 

    揭晓答案,根据触发点的不同,其实这里我对日期是做了两种折叠展现方式,哪两种呢?

    1.触发点在当日,比如1月9日为周日,当切片器选择1月9日时,会立即折叠为周,缺点显而易见,1月9日的数据无法看到。

    2.触发点在次日,同样用上述例子,当切片器选择1月9日时,并不会触发折叠,而是当切片器选择1月10日时,会触发折叠,优点也是显而易见的,这样每天的数据都能得到展现。

    个人倾向于使用第二种方式,数据会得到完整展示,而且代码量也会少很多。当然小伙伴们可以视情况自由选择。

    这里同样采取了无侵入的设计思路,尽量少的建立表关系,而通过TREATAS实现虚拟关联。

    这一部分是整体代码的核心所在,也是难点所在,不要奢望一下能写出结果,要勇于试错,同时要注意细节,多一个或者少一个"="都会让你原地打转很久,所以一定要提前梳理清楚逻辑。

    4.制作可视化

    可视化没什么好说的,将建好的度量放入矩阵中,放入柱状图也是不错的选择。效果如下图所示:

     写在最后

    最后让我们一起对本文重点内容进行回顾总结:

    1.动手之前做导图,理清逻辑。

    2.可建立测试度量,方便验证。

    3.写代码注意细节,避免遗漏。

    可能有的小伙伴会说这种需求在实际工作中遇到的很少,将不同的日期维度放在一起展示进行比较没有实际意义,但我想说的是这里面的思维和实现过程是值得学习借鉴的,掌握了它,相信大家以后对于处理大部分的日期维度问题将会更游刃有余。

    本文是基于对单日期切片,如果想对一段日期实现此效果呢?是否可以加入一个日期维度切片,更便于比较?等等一系列的问题,我在这里抛砖引玉,更多的可能等待着小伙伴们去探索发现。还是那句话:能做的还有很多,这仅仅只是开始。

    本人能力有限,文中如有不当之处,请各位小伙伴给予批评指正。

    最后感谢@佐罗老师的数据源,感谢@焦鹏子老师的珠玉在前,给了我很大的启发。

    农历新年将至,在这里祝各位小伙伴在新的一年中,

    存远志,常读书,乐交友,惜四时!

    全家福安,一生长乐!

    -精彩推荐-

    PDF转Excel,这个秘籍推荐给你

    利用PowerBI移动平均来进行准确预测

    体验PowerBI:零基础制作一个可视化报表

    如果你刚开始学习Power BI,可在微信公众号后台回复"PowerBI",获取《七天入门PowerBI》电子书,轻松上手。

    采悟@PowerBI星球

    相关文章

      网友评论

        本文标题:Power BI技巧:时间维度动态折叠显示

        本文链接:https://www.haomeiwen.com/subject/vddiohtx.html