How can I draw smoothed/rounded/curved line graphs? (C#)

c#, curve, graph, line, smoothing

Solution

You can do some data-smoothing. Instead of using the real data, apply a simple smoothing algorithm that keeps the peaks like a Savitzky-Golayfilter.

You can get the coefficients here.

The easiest to do is:

Take the top coefficients from the website I linked to:

// 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

// now for every point from your data you calculate a smoothed point:

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;

The first 2 and last 2 points you cannoth smooth when using 5 points.

If you want your data to be more "smoothed" you can experiment with coefficents with larger data points.

Now you can draw a line through your "smoothed" data. The larger your np = number of points, the smoother your data. But you also loose peak accuracy, but not as much when simply averaging some points together.

Problem

I'm measuring some system performance data to store it in a database. From those data points I'm drawing line graphs over time. In their nature, those data points are a bit noisy, ie. every single point deviates at least a bit from the local mean value. When drawing the line graph straight from one point to the next, it produces jagged graphs. At a large time scale like > 10 data points per pixel, this noise is compressed into a wide jagged line area that is, say, 20px high instead of 1px as in smaller scales. I've read about line smoothing, anti-aliasing, simplifying and all these things. But everything I've found seems to be about something else. I don't need anti-aliasing, .NET already does that for me when drawing the line on the screen. I don't want simplification. I need the extreme values to remain visible, at least most of them. I think it goes in the direction of spline curves but I couldn't find much example images to evaluate whether the described thing is what I want. I did find a highly scientific book at Google Books though, full of half-page long formulas, which I wasn't like reading through now... To give you an example, just look at Linux/Gnome's system monitor application. I draws the recent CPU/memory/network usage with a smoothed line. This may be a bit oversimplified, but I'd give it a try and see if I can tweak it. I'd prefer C# code but algorithms or code in other languages is fine, too, as long as I can port it to C# without external references.

Original source