【问题标题】:How can I draw smoothed/rounded/curved line graphs? (C#)如何绘制平滑/圆角/曲线图? (C#)
【发布时间】:2010-12-08 15:00:47
【问题描述】:

我正在测量一些系统性能数据以将其存储在数据库中。从这些数据点,我随着时间的推移绘制折线图。从本质上讲,这些数据点有点嘈杂,即。每个点都至少偏离局部平均值。当从一个点直接绘制线图到下一个点时,它会产生锯齿状的图形。在像每个像素 > 10 个数据点这样的大时间尺度上,这种噪声被压缩成一个宽的锯齿线区域,也就是说,20 像素高,而不是较小尺度的 1 像素。

我已经阅读了有关线条平滑、抗锯齿、简化和所有这些内容的信息。但我发现的一切似乎都与其他东西有关。

我不需要抗锯齿,.NET 在屏幕上画线时已经为我做了。

我不想简化。我需要让极端值保持可见,至少其中大部分是可见的。

我认为它是样条曲线的方向,但我找不到太多示例图像来评估所描述的东西是否是我想要的。不过,我确实在 Google Books 上找到了一本非常科学的书,里面全是半页长的公式,我现在不想读...

举个例子,看看 Linux/Gnome 的系统监视器应用程序。我用平滑线绘制了最近的 CPU/内存/网络使用情况。这可能有点过于简单,但我会尝试一下,看看我是否可以调整它。

我更喜欢 C# 代码,但算法或其他语言的代码也可以,只要我可以将其移植到 C# 而不需要外部引用。

【问题讨论】:

  • 你知道windows(和.net)有一个内置的性能计数器系统吗?我只是想确保您没有重新发明轮子(并不是说它们一定适用于您的情况)。
  • 我的数据是在 Linux 服务器上收集的,由许多不同的来源组成,我还有其他代码。数据应可视化,以便在 Mono 运行时下的桌面(交互式)或 Web 应用程序或可能的电子邮件报告中使用。在 Windows 上使用 Visual Studio 完成开发。

标签: c# graph line smooth curve


【解决方案1】:

您可以进行一些数据平滑处理。不要使用真实数据,而是应用一个简单的平滑算法来保持峰值,例如 Savitzky-Golayfilter。

You can get the coefficients here.

最简单的做法是:

从我链接到的网站上获取最高系数:

// For np = 5 = 5 data points
var h = 35.0;
var coeff = new float[] { 17, 12, -3 }; // coefficients from the site
var easyCoeff = new float[] {-3, 12, 17, 12, -3}; // Its symmetrical
var center = 2; // = the center of the easyCoeff array

// 现在为您的数据中的每个点计算一个平滑点:

smoothed[x] = 
   ((data[x - 2] * easyCoeff[center - 2]) +
    (data[x - 1] * easyCoeff[center - 1]) +
    (data[x - 0] * easyCoeff[center - 0]) +
    (data[x + 1] * easyCoeff[center + 1]) +
    (data[x + 2] * easyCoeff[center + 2])) / h;

前 2 点和后 2 点在使用 5 点时无法平滑。

如果您希望数据更加“平滑”,您可以尝试使用更大数据点的系数。

现在您可以通过“平滑”数据绘制一条线。 np = 点数越大,数据越平滑。但是您也会降低峰值准确度,但仅将一些点平均在一起时不会降低。

【讨论】:

  • 我现在已经实现了一个变体。首先,我将原始源数据点平均到每个像素约 3 个值。当以从几秒到几分钟的不同分辨率渲染数月的数据时,这会产生更均匀的数据密度。然后,我通过可以在其他站点上找到的最大系数列表运行这些值。它确实在图中产生了更平滑的线条。但是非常小的和极端的峰值会在图中产生有趣的效果。它在极值所在的曲线周围的另一个方向上剧烈振荡。我认为它来自负系数。
【解决方案2】:

您无法在图形代码中解决此问题。如果您的数据有噪音,那么无论您使用哪种线平滑算法,图表也会有噪音。您需要先过滤数据。使用从原始数据插值的点创建第二个数据集。最小二乘拟合是一种常用技术。平均很容易实现,但往往会隐藏极端情况。

【讨论】:

    【解决方案3】:

    我认为您正在寻找的是提供“样条线”的例程。这是一个描述样条的链接:

    http://en.wikipedia.org/wiki/Spline_(mathematics)

    如果是这种情况,我对样条库没有任何建议,但最初的谷歌搜索出现了一堆。

    抱歉,没有代码,但希望了解这些术语可以帮助您进行搜索。

    鲍勃

    【讨论】:

      【解决方案4】:

      在显示之前使用 MIN/MAX/AVG 减少数据点的数量。它会更好看,会更快

      【讨论】:

        【解决方案5】:

        网络流量图表通常使用加权平均值。您可以每秒对长度为 10 的循环列表进行一次采样,对于图形,在每个样本处,绘制样本的平均值。

        如果 10 个还不够,您可以存储更多。您也不需要从头开始重新计算平均值:

        new_average = (old_average*10 - replaced_sample + new_sample)/10
        

        但是,如果您不想存储全部 10 个,则可以使用以下近似值:

        new_average = old_average*9/10 + new_sample/10
        

        许多路由器使用它来节省存储空间。这会以指数方式向当前的流量速率倾斜。

        如果你确实实现了这个,做这样的事情:

        new_average = old_average*min(9,number_of_samples)/10 + new_sample/10
        number_of_samples++
        

        以避免最初的加速。您还应该调整 9/10、1/10 比率以实际反映每个样本的时间段,因为您的计时器不会每秒触发一次准确

        【讨论】:

          猜你喜欢
          • 2015-11-18
          • 1970-01-01
          • 2017-01-14
          • 1970-01-01
          • 2013-01-20
          • 2012-06-09
          • 2023-03-08
          • 2012-05-16
          • 2017-06-10
          相关资源
          最近更新 更多