New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【建议】折线的平滑问题 #7158

Closed
Erimus-Koo opened this Issue Nov 30, 2017 · 6 comments

Comments

Projects
None yet
3 participants
@Erimus-Koo

Erimus-Koo commented Nov 30, 2017

One-line summary [问题简述]

正常期望的平滑曲线

image

option = {
    xAxis: {
        type: 'category',
        boundaryGap: false,
        data: [1,2,3],
    },
    yAxis: {
        type: 'value',
    },
    series: [
        {
            name:'data',
            type:'line',
            smooth: 'spline',
            areaStyle: {
                normal: {
                    color:'red',
                }
            },
            data: [0,1,0]
        },
    ]
};

当出现两个连续数值一致的点

image
中间这点不能叫平滑吧?

option = {
    xAxis: {
        type: 'category',
        boundaryGap: false,
        data: [1,2,3],
    },
    yAxis: {
        type: 'value',
    },
    series: [
        {
            name:'data',
            type:'line',
            smooth: 'spline',
            areaStyle: {
                normal: {
                    color:'red',
                }
            },
            data: [0,1,1] //连续两个一样的数值<<<<<
        },
    ]
};

连续两个接近的数值

image
还是有角。

option = {
    xAxis: {
        type: 'category',
        boundaryGap: false,
        data: [1,2,3,4],
    },
    yAxis: {
        type: 'value',
    },
    series: [
        {
            name:'data',
            type:'line',
            smooth: 'spline',
            smoothMonotone: 'x',
            markPoint: {
                symbol: 'pin',
                data: [{
                    name: 'max',
                    type: 'max',
                }],
            },
            areaStyle: {
                normal: {
                    color:'red',
                }
            },
            data: [0,1900,2000,0] //连续两个接近的数值<<<<<
        },
    ]
};

坡度较平缓的情况下

image

option = {
    xAxis: {
        type: 'category',
        boundaryGap: false,
        data: [1,2,3,4],
    },
    yAxis: {
        type: 'value',
        min: 0,
        max: 100,
    },
    series: [
        {
            name:'data',
            type:'line',
            symbol: 'none',
            smooth: 'spline',
            // smoothMonotone: 'x',
            areaStyle: {
                normal: {
                    color:'red',
                }
            },
            data: [50,60,60,50] //起伏平缓的数值<<<<<
        },
    ]
};

综合情况 问题分析

image
看了下代码,有箱体这个设定。
箱体最高值和最低值会影响中间的曲线表现,这个其实挺奇怪的。

我作为一个美术的理解,应该就是三个点,中间那点取切线。
切角可以根据数值差距有调整。

现在的设计,可能是为了避免高于实际点的线段,避免视觉误导。
但现在这个方法中间部分也还是存在高于实际数据点的线段。

如果是为了避免超出grid范围。
比如我grid范围本来就设置了,大于数值范围,但折线只以自身数值为箱体,那显示就很难看。
超出grid另外做处理比较好吧,现在有点粗暴。

option = {
    xAxis: {
        type: 'value',
        boundaryGap: false,
        // data: [1,2,3,4,5,6,7,8],
    },
    yAxis: {
        type: 'value',
        min: 0,
        max: 100,
    },
    series: [
        // 先看最后一组红色,三个平顶。
        {
            name:'data',
            type:'line',
            symbol: 'none',
            smooth: true,
            // smooth: 'spline',
            smoothMonotone: 'x',
            areaStyle: {
                normal: {
                    color:'white',
                }
            },
            data: [
                [0,40],[15,70],[20,70],[22.5,72],[25,70],[30,70],[45,40],
                [55,40],[70,70],[85,70],[100,30]] //右侧最低值影响中间<<<<<
        },
        {
            name:'data',
            type:'line',
            symbol: 'none',
            smooth: true,
            // smooth: 'spline',
            smoothMonotone: 'x',
            areaStyle: {
                normal: {
                    color:'yellow',
                }
            },
            data: [
                [0,30],[15,60],[30,60],[45,30],
                [55,30],[70,60],[75,60,],[77.5,62],[80,60],[85,60],[100,30]] //右侧非连续部分影响到左侧<<<<<
        },
        {
            name:'data',
            type:'line',
            symbol: 'none',
            smooth: true,
            // smooth: 'spline',
            smoothMonotone: 'x',
            areaStyle: {
                normal: {
                    color:'red',
                }
            },
            data: [
                [0,20],[15,50],[30,50],[45,20],
                [55,20],[70,50],[85,50],[100,20]] //三段水平线<<<<<
        },
    ]
};

Version & Environment [版本及环境]

  • ECharts version [ECharts 版本]:
  • Browser version [浏览器类型和版本]:
  • OS Version [操作系统类型和版本]:

Expected behaviour [期望结果]

ECharts option [ECharts配置项]

option = {

}

Other comments [其他信息]

@Erimus-Koo

This comment has been minimized.

Erimus-Koo commented Nov 30, 2017

找到一个简单魔改的方法

增加一个不存在的最大/最小值
image
下面那条曲线是加值之后的。
还是希望官方能改一下。

魔改的问题点

  1. markPoint自动识别失效
  2. 如果使用datazoom,需要关闭filter。
  3. datazoom的数据缩略图会显示额外追加的数据,无法隐藏。
option = {
    xAxis: {
        type: 'category',
        boundaryGap: false,
        data: [1,2,3,4],
    },
    yAxis: {
        type: 'value',
    },
    series: [
        {
            name:'old data',
            type:'line',
            smooth: 'spline',
            smoothMonotone: 'x',
            areaStyle: {
                normal: {
                    color:'yellow',
                }
            },
            data: [10,30,30,10]
        },
        {
            name:'new data',
            type:'line',
            smooth: 'spline',
            smoothMonotone: 'x',
            markPoint: { //缺点是markPoint自动识别失效<<<<<
                symbol: 'pin',
                data: [{
                    name: 'max',
                    type: 'max',
                }],
            },
            areaStyle: {
                normal: {
                    color:'red',
                }
            },
            data: [0,20,20,0,,30] //增加一个不显示的高于max的值<<<<<
        },
    ]
};

@Erimus-Koo Erimus-Koo changed the title from 【急】没人觉得折线的smooth很奇怪吗?为啥会有尖角啊? to 【建议】折线的平滑问题 Nov 30, 2017

@Erimus-Koo

This comment has been minimized.

Erimus-Koo commented Nov 30, 2017

又做了几个关于smoothMonotone的测试

123

前两个图看,开启monotone效果更好,不开的话有点戛然而止。

从第三个图起,是数据波动极大的情况下:

  • 开启monotone,再用附加的伪数据限制高度,转角产生了不平滑的情况。
  • 第4个是不限高,开启monotone之后,显然超过太多了,虽然转角平滑。
  • 第5个关闭了smoothMonotone,转角平滑了。但超出部分高度是固定值,不受数值影响。
    也就是对本身波动小的数值,效果看上去平滑。对波动大的数值,效果看上去转折大。

期望效果

  • 转角平滑(类似smoothMonotone关闭)
  • 高度可以自定义(比如按比例)
option = {
    xAxis: {
        type: 'category',
        boundaryGap: false,
        data: ['普通/开启',,'普通/关闭',,'',,'极端/开启/限高',,'极端/开启/不限高',,'极端/关闭',,],
    },
    yAxis: {
        type: 'value',
        min: 0,
        max: 50,
    },
    series: [
        {
            name:'1',
            type:'line',
            showSymbol: false,
            smooth: true,
            smoothMonotone: 'x',//开启
            data: [0,40,40,0,,,,50]//一般数据(小波动)
        },
        {
            name:'2',
            type:'line',
            showSymbol: false,
            smooth: true,
            // smoothMonotone: 'x',//关闭
            data: [,,0,40,40,0,,,,50]//一般数据(小波动)
        },
        {
            name:'3',
            type:'line',
            showSymbol: false,
            smooth: true,
            smoothMonotone: 'x',//开启
            data: [,,,,-100,40,40,-100,,,45] //极端数据-限高
        },{
            name: '4',
            type: 'line',
            showSymbol: false,
            smooth: true,
            smoothMonotone: 'x',//开启
            data: [,,,,,,-100,40,40,-100,,9999], //极端数据-不限高
        },{
            name: '5',
            type: 'line',
            showSymbol: false,
            smooth: true,
            // smoothMonotone: 'x',//关闭
            data: [,,,,,,,,-100,40,40,-100,,9999],//极端数据-不限高
        }
    ]
};
@Erimus-Koo

This comment has been minimized.

Erimus-Koo commented Nov 30, 2017

补充参考 PS里的关于路径圆滑的表达

untitled-1

画得比较糙,凑合看。

反正作为美术,一般我画的时候会遵循这几项原则。

  • 节点两侧句柄平行。
  • 句柄角度根据前后两个点距离确定(距离远的夹角小/角度倾向于远的点)。
  • 句柄长度根据前后两个点夹角确定(夹角大的句柄短)。

虽然我看了js的实现,跟PS不一样。就当参考吧。

@Erimus-Koo

This comment has been minimized.

Erimus-Koo commented Nov 30, 2017

untitled-2

@pissang

This comment has been minimized.

Contributor

pissang commented Nov 30, 2017

@Erimus-Koo 感谢!默认情况下计算出来的贝塞尔曲线手柄是平行的,但是因为平滑后需要保留最大值和最小值,所以会对其作调整,可能调整后就不再平行了就出现了这个效果,后面会优化这点

@pissang pissang added the enhancement label Dec 1, 2017

@Ovilia Ovilia closed this in 6eeb3b0 Feb 12, 2018

Ovilia added a commit that referenced this issue Feb 12, 2018

Ovilia added a commit that referenced this issue Feb 12, 2018

@Ovilia

This comment has been minimized.

Contributor

Ovilia commented Feb 12, 2018

原先的算法会根据当前点与前一个点、后一个点,共同决定控制点位置,并且控制点两边一般是在一条直线上的(除非因为超出了最大最小值而被调整)。正如 @Erimus-Koo 在上面列出的(感谢~),这一算法会在某些情况下出现不理想的平滑结果,并且是比较常见的。
因此,我们新实现了一种更简单有效的平滑算法,也就是每个控制点两边都保持水平或竖直(取决于数据点是在哪个方向上单调递增)。这样的好处是,生成的曲线是可导的(每个点都是连续并且存在导数),不会产生突变的情况。缺点是没法处理不单调的情况(比如点坐标依次是:[100, 100], [200, 200], [150, 180])。
因此,ECharts 默认对于单调的情况采用新算法,对于不单调的情况采用老算法。如果想要强行使用老算法,可以将 smoothMonotone 指定为 'none' 实现。例子参见 0af0297
后面我会在文档里补充图文,更清楚地说明这一问题。

Ovilia added a commit to ecomfe/echarts-doc that referenced this issue Feb 13, 2018

Ovilia added a commit that referenced this issue Feb 13, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment