删除线图的冗余点

时间:2011-01-16 21:55:49

标签: math charts 2d plot linegraph

我试图用一些库绘制大量的点。这些点按时间排序,其值可能被认为是不可预测的。

目前我的问题是,大量的点会使图书馆花费太长时间来渲染。许多点是多余的(即 - 它们“在”函数y = ax + b定义的同一行上“)。有没有办法检测和删除冗余点以加快渲染速度?

感谢您的时间。

3 个答案:

答案 0 :(得分:6)

以下是1.5d图的Ramer-Douglas-Peucker算法的变体:

  1. 计算第一个和最后一个点之间的线方程
  2. 检查所有其他点以查找距离该行最远的地方
  3. 如果最差点低于您想要的公差,则输出单个段
  4. 否则,考虑两个子阵列递归调用,使用最差点作为分离器
  5. 在python中,这可能是

    def simplify(pts, eps):
        if len(pts) < 3:
            return pts
        x0, y0 = pts[0]
        x1, y1 = pts[-1]
        m = float(y1 - y0) / float(x1 - x0)
        q = y0 - m*x0
        worst_err = -1
        worst_index = -1
        for i in xrange(1, len(pts) - 1):
            x, y = pts[i]
            err = abs(m*x + q - y)
            if err > worst_err:
                worst_err = err
                worst_index = i
        if worst_err < eps:
            return [(x0, y0), (x1, y1)]
        else:
            first = simplify(pts[:worst_index+1], eps)
            second = simplify(pts[worst_index:], eps)
            return first + second[1:]
    
    print simplify([(0,0), (10,10), (20,20), (30,30), (50,0)], 0.1)
    

    输出为[(0, 0), (30, 30), (50, 0)]

    关于可能不明显的数组的python语法:

    • x[a:b]是从索引a到索引b的数组的一部分(不包括在内)
    • x[n:]是使用从x到结尾的n元素制作的数组
    • x[:n]是使用n
    • 的第一个x元素制作的数组
    • a+bab是数组意味着连接时
    • x[-1]是数组的最后一个元素

    可以看到在eps值增加超过100,000点的图表上运行此实施的结果示例{/ 3}}。

答案 1 :(得分:0)

在我有了这个想法后,我遇到了这个问题。跳过绘图上的冗余点。我相信我想出了一个更好、更简单的解决方案,我很高兴分享我在 SO 上提出的第一个解决方案。我已经对它进行了编码,它对我来说效果很好。它还考虑了屏幕比例。这些绘图点之间可能有 100 个点的值,但如果用户的图表尺寸较小,他们将看不到它们。

因此,遍历数据/绘图循环,在绘制/添加下一个数据点之前,先查看下一个值并计算屏幕比例(或值,但我认为上述屏幕比例)的变化理由更好)。现在对前面的下一个值做同样的事情(获取这些值只是在你的数组/集合/列表/等中向前看的问题,在循环中将 for next step 增量(可能是 1/2)添加到当前的 for 值)。如果 2 个值相同(或者可能是非常小的变化,根据您自己的喜好),您可以通过简单地在循环中添加“继续”来跳过图表中的这一点,跳过添加数据点,因为该点正好位于前后点之间的斜率。

使用这种方法,我将图表从 963 点减少到 427 点,例如,视觉变化绝对为零。

我认为您可能需要多读几遍才能理解,但它比此处提到的其他最佳解决方案简单得多,重量更轻,并且对您的情节的视觉效果为零。

答案 2 :(得分:-2)

我可能应用“最小二乘法”算法来获得最佳拟合线。然后,您可以查看靠近该线的点和向下过滤连续点。您只需要绘制异常值,以及将曲线带回最佳拟合线的点。

修改:您可能不需要使用“最小二乘法”;如果你的输入预计会像你说的那样徘徊在“y = ax + b”附近,那么这已经是你最合适的线,你可以使用它。 :)