如何绘制平滑/圆角/曲线图? (C#)

时间:2010-12-08 15:00:48

标签: c# graph line smooth curve

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

我已经阅读过有关线条平滑,抗锯齿,简化以及所有这些内容的内容。但我发现的一切似乎都与其他事情有关。

我不需要消除锯齿功能,.NET在屏幕上绘制线条时已经为我做了这一点。

我不想简化。我需要极端值才能保持可见,至少大部分都是如此。

我认为它是在样条曲线的方向,但我找不到很多示例图像来评估所描述的东西是否是我想要的。我确实在谷歌图书上找到了一本高度科学的书,里面装满了半页长的公式,我现在不喜欢看完......

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

我更喜欢C#代码,但其他语言的算法或代码也很好,只要我可以在没有外部引用的情况下将其移植到C#。

5 个答案:

答案 0 :(得分:6)

您可以进行一些数据平滑。而不是使用真实数据,应用一个简单的平滑算法,使峰值像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;

当使用5分时,前2点和后2点你需要平滑。

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

现在,您可以通过“平滑”数据绘制一条线。 np =点数越大,数据越平滑。但是你也放松了峰值准确度,但是在简单地将一些点平均在一起时并没有那么多。

答案 1 :(得分:2)

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

答案 2 :(得分:1)

我认为您所寻找的是提供“样条”的常规。这是一个描述样条线的链接:

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

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

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

鲍勃

答案 3 :(得分:0)

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

答案 4 :(得分:0)

网络流量图通常使用加权平均值。您可以每秒一次采样到长度为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比率以实际反映每个样本的时间周期,因为您的计时器不会每秒完全一次。