相关文章推荐
跑龙套的感冒药  ·  JS--JavaScript焦点处理(获取焦 ...·  2 年前    · 
好帅的海龟  ·  mysql使用一张表的数据更新另一张表upd ...·  2 年前    · 
纯真的蚂蚁  ·  HttpContext.Current.Se ...·  2 年前    · 
刀枪不入的皮带  ·  itext7 : html转PDF - 知乎·  2 年前    · 
豪气的炒饭  ·  qtreewidget基本使用_qtreew ...·  2 年前    · 
Code  ›  PowerBI 全网首发原生平滑曲线 - 原理及实现开发者社区
算法 axis powerbi
https://cloud.tencent.com/developer/article/1786768
冷静的山寨机
2 年前
作者头像
BI佐罗
0 篇文章

PowerBI 全网首发原生平滑曲线 - 原理及实现

前往专栏
腾讯云
开发者社区
文档 意见反馈 控制台
首页
学习
活动
专区
工具
TVP
文章/答案/技术大牛
发布
首页
学习
活动
专区
工具
TVP
返回腾讯云官网
社区首页 > 专栏 > PowerBI战友联盟 > PowerBI 全网首发原生平滑曲线 - 原理及实现

PowerBI 全网首发原生平滑曲线 - 原理及实现

作者头像
BI佐罗
发布 于 2021-02-08 21:09:48
1.2K 0
发布 于 2021-02-08 21:09:48
举报

仅以本文致敬本科的数学老师们,终于用上了一招。

大家都知道,Power BI 的折线图并没有平滑的曲线,这在很多时候非常不方便。

本文来探讨 Power BI 中原生平滑曲线的实现。这要借助一些成熟的数学算法,我们并不打算研究这些数学算法的具体细节,而是仅仅给出 DAX 实现以及对比。

效果

假设先有一个折线如下:

该折线的问题就是看着太生硬,我们希望它可以更加平滑。得到如下效果:

对于生硬的红色折线,我们希望它可以变得平滑,如蓝线所示。

那么问题来了:

  • 如何从红色折线得到蓝色光滑曲线
  • 如何确保蓝色线是连续光滑的
  • 如何确保蓝色线的生成方式是通用的

为此,我们需要研究从独立散点到形成光滑曲线的方法。

插值算法

我们研究了数学中的几种插值算法,所谓插值,顾名思义,就是在已知的的点之间,插入一些新的值,在连线后,形成整条曲线。我们希望这条曲线满足:

  • 连续性
  • 最速接近
  • 高性能

我们考察了数学中的几种算法,如下:

其中,紫色的 Cubic.Pro 和粉色的 Hermite 是重合的。

可以看出:粉色线是同时满足三个条件的最佳算法。

算法实现

由于 Cubic.Pro 和 Hermite 算法默认重合,这里仅仅使用 Cubic.Pro 算法。

对于某个维度 X ,其每个点可由度量值计算出相应的值。

所谓插值,就是将维度 X 的每两个点之间插入新的节点,可以插入 1 ~ 1000 个点都可以。

而不难猜测,插入的点越多,越平滑,但计算量也越大。

例如:

插入 3 个点时:

很明显,在弯折处是不够光滑的。

插入 10 个点时:

已经很光滑,但在细节处,我们放大看:

还是不够光滑。

插入 20 个点时:

此时已经非常光滑。

这样,我们就得到了从点图(折线图)到完美的光滑曲线的最佳实践,为:

  • 采用 Cubic.Pro 插值算法
  • 将原来的两个点中插入 20 个点进行插值计算
  • 满足连续性以及光滑
  • 性能没有问题

DAX实现

第一步,对已有坐标轴进行扩展,如下:

Axis.Ex = 
VAR _n = 20 // 用于区间内分割的点数
RETURN
FILTER(
    GENERATEALL(
        VALUES( 'Axis.X'[X] ) ,
        SELECTCOLUMNS( GENERATESERIES( 0 , _n - 1 ) , "X'" , [X] + [Value] / _n )
    [X'] <= MAX( 'Axis.X'[X] ) // 去除超过原区间大小的点
)

第二步,实现 Cubic.Pro 插值算法,如下:

Axis.Y.Smooth.Cubic.Pro = 
VAR _y_min = CALCULATE( [Axis.Y.Sample] , TREATAS( { MIN( 'Axis.X'[X] ) } , 'Axis.X'[X] ) )
VAR _y_max = CALCULATE( [Axis.Y.Sample] , TREATAS( { MAX( 'Axis.X'[X] ) } , 'Axis.X'[X] ) )
VAR _y0 = COALESCE( CALCULATE( [Axis.Y.Sample] , TREATAS( { VALUES( 'Axis.Ex'[X] ) - 1 } , 'Axis.X'[X] ) ) , _y_min )
VAR _y1 = CALCULATE( [Axis.Y.Sample] , TREATAS( { VALUES( 'Axis.Ex'[X] ) + 0 } , 'Axis.X'[X] ) )
VAR _y2 = CALCULATE( [Axis.Y.Sample] , TREATAS( { VALUES( 'Axis.Ex'[X] ) + 1 } , 'Axis.X'[X] ) )
VAR _y3 = COALESCE( CALCULATE( [Axis.Y.Sample] , TREATAS( { VALUES( 'Axis.Ex'[X] ) + 2 } , 'Axis.X'[X] ) ) , _y_max )
VAR _dx = SELECTEDVALUE( 'Axis.Ex'[X'] ) - SELECTEDVALUE( 'Axis.Ex'[X] )
RETURN
    VAR _u1 = _dx
    VAR _u2 = _dx * _dx
 
推荐文章
跑龙套的感冒药  ·  JS--JavaScript焦点处理(获取焦点focus、失去焦点blur)_js focus_吴声子夜歌的博客-CSDN博客
2 年前
好帅的海龟  ·  mysql使用一张表的数据更新另一张表update_mysql一个表更新另一个表_好大的月亮的博客-CSDN博客
2 年前
纯真的蚂蚁  ·  HttpContext.Current.Session.SessionID相关问题及备忘 - 程序诗人 - 博客园
2 年前
刀枪不入的皮带  ·  itext7 : html转PDF - 知乎
2 年前
豪气的炒饭  ·  qtreewidget基本使用_qtreewidget列宽自适应 - 腾讯云开发者社区-腾讯云
2 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号