如何在可视化对象中高亮显示单个值

本文翻译自Kurt Buhler的文章—《RHighlighting a data point and comparing to all others in a distribution》来源:SQLBI 本文介绍了在将某单个值的度量分布与其他所有值的度量分布进行比较时,如何在可视化中突出显示单个值。

有效的可视化提供了信息,由此用户可以解释这些数字以及它们对你的意义。这个数字是坏的还是好的?这对于旨在提供快速的、概览的可视化(如卡片、KPI和简单的趋势线)尤为重要。你可以通过与目标进行比较来提供背景信息,但如果没有目标,你也可以与中心趋势的度量进行比较,如平均值或中位数。然而,除了与聚合数据进行比较外,你还可能希望与其他类别进行比较。

考虑以下示例,它展示了本文所需的最终结果:一个图表,它突出显示选定的值,以便用户可以将其与其他值进行比较。本示例使用了一些DAX和格式设置,通过折线图和散点图来实现抖动图顶部的联合图的效果。

在这个示例中,我们重点突出了单个数据点,以便与分布中的其他数据点进行比较。这样,我们可以看到完整的上下文,包括数据点的总数、它们的分布以及最高值和最低值。当分布不典型时,这种方法特别有用,例如当异常值或数据点群集偏离平均值时,或者当显示数据点数量很重要时。

在现实生活中,有很多可能的情况需要应用这种方法。例如,你可能想要展示个人(如销售代表)的目标达成情况或某个类别(如客户)的销售额与其他所有类别的比较。在创建钻取报表时,你经常会使用这样的图表。

这篇文章我们将玩点有趣的东西,看一个不那么真实的例子。我们将通过分析桌上角色扮演游戏《龙与地下城》中幻想生物的统计数据来进行这项分析。

创建抖动图

在本次分析中,我们想要分析不同生物的多种统计数据,比如它们的生命值或命中点数(HP)。一般来说,本报告的目的是一次分析一个生物,并将其统计数据与其他所有生物进行比较。为此,我们将使用一种名为抖动图(或蜂群图)的散点图,它允许我们比较单个度量中数据点的分布情况。

抖动图不是默认的图表类型,尽管在某些情况下我们可以使用散点图核心视觉对象来创建。

第一步是创建抖动图,以可视化所有生物的单个度量值的分布情况。为此,我们首先创建一个度量值来计算生物HP的平均值,并将其添加到散点图视觉对象的值中,然后将生物的“名称”添加到“值”字段中:

生物表中的度量值

Avg. Creature HP = AVERAGE ( 'Creatures'[HP] )

这生成了以下散点图,其宽度大于高度。


要这样使用散点图,您需要为视觉对象的一般设置禁用“响应性”属性。此外,您现在已经可以对标记、标题和轴进行格式设置。一个有用的格式设置技巧是添加Y轴标签,以更清楚地指示图表的开始位置。这个Y轴标签实际上是一条名为“HP”的Y轴常量线,它之所以可见,是因为X轴的最小值被设置为较低的负值。

理论上,我们可以到此为止,因为这个点图已经显示了分布。然而,这并不有效,因为重叠的数据点很难区分。重叠会影响分析,因为它模糊了数据点的数量和可能存在的组别。为了解决这个问题,我们进行下一步,即在Y轴上添加随机抖动(或分散)。

添加抖动仅仅意味着我们沿着Y轴随机分布数据点,这样它们就不太可能重叠。我们可以在度量值中使用RAND DAX函数来实现这一点,该函数为每个数据点返回一个0到1之间的随机数:

生物表中的度量值

Jitter (RAND)= RAND()

当我们将这个度量值添加到Y轴上时,更容易看到数据点的数量和分布。请注意,在度量值中,每次用户与报表交互时,RAND都会评估为一个不同的随机数。这很烦人,因为数据点会在Y轴上跳来跳去,可能会误导用户认为他们正在筛选视觉对象。稍后我们将通过将数据抖动移动到计算列来解决这个问题,该列仅在其表刷新时进行评估。

查看抖动图时,我们看到数据点分散在大量的垂直空间中,使图表看起来杂乱无章。我们可以通过调整抖动来使其更加保守,从而解决这个问题:

生物表中的度量值

Jitter (Adjusted RAND) = ( RAND () – 0.5 ) * 0.9

这样就得到了显示生物生命值分布的蜂群图。我们可以清楚地看到这是一个左偏分布,其中绝大多数生物的生命值较低,而少数非常强大的生物的生命值较高。下一步是添加功能,以便我们可以选择一个怪物,并在抖动图中突出显示它。

仅高亮显示选中的数据点

在当前的抖动图中,选择一个单一的生物只会导致一个数据点被高亮,这会使我们失去上下文。这显然不是很有用,如下例所示。

相反,我们希望选中的数据点能在其他所有数据点中突出显示。这有助于我们在跨类别比较时理解该值的上下文。要做到这一点,我们首先需要在数据模型中添加一些东西。

第一步是,我们需要一个包含生物名称的维度表。此外,我们还将抖动作为计算表中的一列包含在内,以便 RAND 仅在模型刷新时评估,而不是在每次报告交互后评估。这个计算表将与模型的其他部分断开连接;它与其他表没有关联。我们通过在导入模型中使用 DAX 来添加此表,但您也可以使用您喜欢的任何其他上游方法:

计算表

Creature Names =

ADDCOLUMNS (

DISTINCT ( 'Creatures'[Name] ),

"Jitter", ( RAND () - 0.5 ) * 0.9

)

创建此表后,我们将“名称”列添加到抖动图的“值”区域中,替换原来来自“生物”表的“名称”列。现在,Y轴中使用的“抖动”度量应该仅从“生物名称”表中获取随机值:

生物表中的度量值

Jitter (Calculated Column) = MAX ( 'Creatures Names'[Jitter] )

当我们使用“抖动”(计算列)时,它不会在我们每次与报告交互时重新计算。

接下来,我们需要调整“平均生物HP”度量值。具体来说,我们必须使用TREATAS来应用一个虚拟关系,以便新计算表中的“名称”可以从原始“生物”表中相同列的筛选器上下文中取值。这确保了我们能够获取生物HP的适当分布:

生物表中的度量值

Avg. Creature HP =

CALCULATE (

AVERAGE ( 'Creatures'[HP] ),

TREATAS (

DISTINCT ( 'Creature Names'[Name] ), --Virtual relationship from here…

'Creatures'[Name] --…to here.

)

)

我们使用这种不连接的计算表的原因是利用DAX中可以操作的筛选器上下文。请考虑以下图表,它描绘了切片器中选择一个生物名称对可视化对象的正常影响。

通常,从切片器中选择一个生物名称会导致对“生物”表的特定行进行筛选。存在的唯一行是那些Name列中具有选定值的行。因此,抖动图仅显示一个生物,即我们选中的那个。我们无法强制可视化显示更多生物,因为这个筛选器是在可视化对象的SUMMARIZECOLUMNS查询级别应用的,我们无法拦截它。

相反,我们创建了一个新的生物名称表,该表不受此切片器的影响。然后,我们可以选择性地应用来自该切片器的筛选器上下文以实现高亮显示。我们在DAX中通过使用“高亮生物”计算组来实现这一点。该计算组包含两个计算项:“选定生物”和“所有生物”:

“高亮生物”表中的计算项(Calculation Item)

Selected Creature =

CALCULATE (

SELECTEDMEASURE ( ),

KEEPFILTERS ( -- Optional; allows for selective highlighting of multiple values.

TREATAS (

DISTINCT ( 'Creatures'[Name] ), -- Apply the filter from here…

'Creature Names'[Name] -- …to here.

)

)

)

第一个计算项“选定生物”使用TREATAS将来自“生物”表中“名称”列的筛选器上下文应用到“生物名称”表中的“名称”列。结果是,选定的度量值将仅针对选定的生物进行评估:

“高亮生物”表中的计算项(Calculation Item)

All Creatures = SELECTEDMEASURE () --Unmodified filter context

二个计算项“所有生物”仅返回选定的度量值而不修改筛选器上下文。或者,它也可以筛选出选定值,以便仅返回“其他生物”:

“高亮生物”表中的计算项(Calculation Item)

Other Creatures =

--Alternative to All Creatures, not used in the samples or images.

CALCULATE (

SELECTEDMEASURE ( ),

KEEPFILTERS (

EXCEPT (

ALL ( 'Creature Names'[Name] ),

DISTINCT ( 'Creatures'[Name] )

)

)

)

总结来说,在添加这些新的DAX对象后,我们进行了以下更改以突出显示选定值:

将“生物名称”计算表中的“名称”添加到“详细信息”区域。

将“抖动”度量更改为使用计算表的列。

将“生物HP”度量更改为使用从计算表中的“名称”到“生物”表中的“名称”的虚拟关系。

将新的计算组突出显示的生物添加到“图例”区域。此计算组应包含两个计算项:“选定生物”和“所有生物”。

设置标记格式,以便“选定生物”高亮显示,而“所有生物”为灰色。
更改“选定生物”计算项的序数,使其高于(1)“所有生物”计算项(0)。这可以确保高亮显示的数据点位于顶部。

现在,我们得到了以下结果,正如预期那样,它突出了选定的生物。

我们将在下面的图表中解释这种选择性高亮的工作原理。

在这个新场景中,通过使用CALCULATE函数中的TREATAS针对SELECTEDMEASURE,来自“生物”表的筛选器仅应用于“选定生物”计算项中的“生物名称”。在剩余的计算项“所有生物”中,不应用筛选器。相反,我们对来自“生物名称”的“Name”的SELECTEDVALUE进行筛选,以便显示所有其他值。当将此计算组应用于视觉图例时,它会产生预期的效果,即仅高亮显示选定值。

我们在此方法中使用了计算组,但也可以使用应用条件格式的DAX度量。下面展示了这种度量的DAX代码:

生物表中的度量值

Highlighting (Conditional Formatting) =

IF (

SELECTEDVALUE ( 'Creature Names'[Name] )

IN

DISTINCT ( 'Creatures'[Name] ),

"#56B056", -- Green highlight

"#D2D2D2" -- Grey default

)

虽然用于条件格式化的DAX度量更简单、更容易理解,但它不能用于条件格式化之外的其他上下文。例如,我们可能希望使用这种方法来比较其他视觉类型中的类别或其他度量,这时计算组将非常有用。此外,条件格式化方法还有更多限制。实际上,我们无法控制数据点的Z轴顺序或形状,这使得它们容易被同一簇中的其他数据点遮挡,从而影响可视化效果。以下是一个示例。

创建联合图(Joint Plot)

到目前为止,我们已经创建了一个抖动图,该图通过类别显示了度量的分布,并允许我们查看一个或多个选定的类别,并将它们与其余类别进行比较。然而,即使使用抖动图,仍然很难更精确地了解一个集群内的数据点数量。解决这个问题的一种方法是添加第二个图表,以提供关于分布的补充信息,这被称为联合图。

在联合图中,我们希望看到按生命值(HP)分布的生物。我们可以在直方图或折线/面积图中完成此操作,但在此示例中我们将选择折线图。为此,我们首先需要修改计算表以包含生物的生命值(HP)。但是,我们将使用FLOOR函数将HP分组为大小为20的组,以平滑分布:

计算表

Creature Names =

ADDCOLUMNS (

DISTINCT ( 'Creatures'[Name] ),

"HP (bins)", CALCULATE ( FLOOR ( MAX ( 'Creatures'[HP] ), 20 ) ), -- Newly added

"Jitter", ( RAND () - 0.5 ) * 0.9

)

为了制作联合图,我们创建一个折线图,该图在X轴上绘制HP(组)(来自调整后的计算表“生物名称”),在Y轴上绘制“生物数量”:

生物表上的度量值

Creatures = COUNTROWS ( DISTINCT ( 'Creature Names'[Name] ) )

与联合图类似,我们禁用“响应式”并将折线图缩小为更水平而不是更垂直。然后,我们将其直接放置在抖动图上方,确保X轴对齐,并应用一些基本格式:

禁用轴和轴标题。
将线条和区域的颜色设置为与我们已创建的联合图相匹配。

最后一步是在此分布中突出显示选定的生物。最简单的方法是通过返回HP的SELECTEDVALUE来实现,我们在X轴常量线中使用它:

生物表上的度量值

Selected Creature HP = SELECTEDVALUE('Creatures'[HP])

此外,我们还可以选择以最后一步结束,即使用动态标题来声明选定值。标题还可以提供额外的上下文信息,例如低于选定值的数据点数量。这将产生我们最终想要的结果,即我们可以快速轻松地比较选定类别与其他所有类别的值。

需要提及的是,这种特定方法仅限于一次只显示一个选定值。要显示多个值,可以通过应用我们之前用于制作抖动图的计算组方法来实现。然而,这种方法不允许我们使用线条;它只会显示组中的值,这些值不会像X轴常量线那样与抖动图对齐。

最后,我们应该对视觉对象进行一些最终的清理工作。例如,我们可以添加一个背景容器,然后在选择窗格中分组并命名所有视觉容器。我们还应该处理工具提示和标题图标(如“聚焦模式”),以避免它们遮挡视觉对象,例如,如果不需要,可以禁用它们,或者使用自定义报表页面工具提示,以避免在其中显示令人困惑的信息,如抖动值。

管理报表对象

此方法涉及创建多个专门用于特定视觉需求的报表对象。与往常一样,重要的是要避免这些报表对象使模型杂乱无章并让用户或其他开发人员感到困惑。为了缓解这一问题,您应该将这些对象与“核心”语义模型分开。例如,您可以隐藏度量值、计算组和计算表,并将报表对象度量值隔离到它们自己的度量值表中。您还应该在对象描述中记录哪些视觉对象使用这些对象以及它们的工作原理。

此外,使用此解决方案,我们在模型中复制了一些信息;但是,这种影响是微不足道的。新表具有较低的基数(706个值),并且在小型模型中占用的空间很小。为了避免用户和其他开发人员的混淆,我们还可以隐藏该表,或将其设置为私有,这样既可以隐藏它,又无法查看隐藏对象或在DAX自动完成功能中看到对象名称。


如果您想深入学习微软Power BI,欢迎登录网易云课堂试听学习我们的“从Excel到Power BI数据分析可视化”系列课程。或者关注我们的公众号(PowerPivot工坊)后猛戳”在线学习”。




长按下方二维码关注“Power Pivot工坊”获取更多微软Power BI、PowerPivot相关文章、资讯,欢迎小伙伴儿们转发分享~


Power Pivot工坊