none
How to smooth a noisy Line Graph in C# charting? RRS feed

  • Question

  • 

    My line graph (which is the derivative of some values) is bit noisy and looks bad. I have tried using Spline but all I get is the same noisy graph. Is there any easy way to smooth the curve?

    Thanks..

    Monday, August 12, 2019 4:28 AM

Answers

  • There are a virtually infinite number of filtering methods for smoothing data.  It all depends on what you're after.  A moving average can do a lot of good; replace each point by the average of the 5 points in its neighborhood.  Butterworth and Chebyshev filters are both good at clearing out high-frequency data, which will tend to smooth out the results.  If you just have a few wild points, it can be easier just to scan through your data and toss out the odd points.

    https://www.centerspace.net/tag/c-iir-filtering

    However, you do need to understand that the data you get back no longer accurately represents the derivative of your input data.  If your input is noisy, then maybe you should be showing the user a noisy plot.


    Tim Roberts | Driver MVP Emeritus | Providenza & Boekelheide, Inc.

    • Marked as answer by Magesh85 Wednesday, October 9, 2019 9:18 AM
    Monday, August 12, 2019 9:49 PM

All replies

  • Greetings Magesh.

    What do you mean, "noisy and looks bad"? Can you post a picture to show what you mean?

    Monday, August 12, 2019 5:59 AM
  • There are a virtually infinite number of filtering methods for smoothing data.  It all depends on what you're after.  A moving average can do a lot of good; replace each point by the average of the 5 points in its neighborhood.  Butterworth and Chebyshev filters are both good at clearing out high-frequency data, which will tend to smooth out the results.  If you just have a few wild points, it can be easier just to scan through your data and toss out the odd points.

    https://www.centerspace.net/tag/c-iir-filtering

    However, you do need to understand that the data you get back no longer accurately represents the derivative of your input data.  If your input is noisy, then maybe you should be showing the user a noisy plot.


    Tim Roberts | Driver MVP Emeritus | Providenza & Boekelheide, Inc.

    • Marked as answer by Magesh85 Wednesday, October 9, 2019 9:18 AM
    Monday, August 12, 2019 9:49 PM
  • Hi Magesh85, 

    Thank you for posting here.

    For your question, you want to smooth a noisy Line Graph in C# charting.

    I suggest you use Ramer–Douglas–Peucker algorithm to reduce number of points.

    I use the algorithm to make a test on my side, and you can refer it.

    Here’s the code.

    Form1:

            List<int> lt = new List<int>();
            List<int> lt2 = new List<int>();
            List<Point> points = new List<Point>() {
                    new Point(){ year = 1990,value = 100 },
                    new Point(){ year = 1991,value = 200 }
                    // Add data ...
                };
            public Form1()
            {
                InitializeComponent();
            }
            private void Form1_Load(object sender, EventArgs e)
            {
                fillChart();
            }      
            private void fillChart()
            {
                var series = new Series("Data");
                
                for(int i=0;i<points.Count;i++)
                {
                    lt.Add(points[i].year);
                    lt2.Add(points[i].value);
                }
                series.Points.DataBindXY(lt,lt2);
                chart1.Series.Add(series);
                series.ChartType = SeriesChartType.Line;
            }
            private void button1_Click(object sender, EventArgs e)
            {
                lt.Clear();
                lt2.Clear();
                chart1.Series.Clear();
                List<Point> po = Utility.DouglasPeuckerReduction(points, Convert.ToDouble(numericUpDown1.Value));
                for (int i = 0; i < po.Count; i++)
                {
                    lt.Add(po[i].year);
                    lt2.Add(po[i].value);
                }
                var series = new Series("Data");
                series.Points.DataBindXY(lt, lt2);
                chart1.Series.Add(series);
                series.ChartType = SeriesChartType.Line;
            }

    Point Class:

        public class Point
        {
            public int year { get; set; }
            public int value { get; set; }
        }

    Utility Class:

        public class Utility
        {
            public static List<Point> DouglasPeuckerReduction(List<Point> Points, Double Tolerance)
            {
    
                if (Points == null || Points.Count < 3)
                    return Points;
    
                Int32 firstPoint = 0;
                Int32 lastPoint = Points.Count - 1;
                List<Int32> pointIndexsToKeep = new List<Int32>();
    
                pointIndexsToKeep.Add(firstPoint);
                pointIndexsToKeep.Add(lastPoint);
    
                while (Points[firstPoint].Equals(Points[lastPoint]))
                {
                    lastPoint--;
                }
    
                DouglasPeuckerReduction(Points, firstPoint, lastPoint, Tolerance, ref pointIndexsToKeep);
    
                List<Point> returnPoints = new List<Point>();
                pointIndexsToKeep.Sort();
                foreach (Int32 index in pointIndexsToKeep)
                {
                    returnPoints.Add(Points[index]);
                }
                return returnPoints;
            }
            private static void DouglasPeuckerReduction(List<Point> points, Int32 firstPoint, Int32 lastPoint, Double tolerance, ref List<Int32> pointIndexsToKeep)
            {
                Double maxDistance = 0;
                Int32 indexFarthest = 0;
    
                for (Int32 index = firstPoint; index < lastPoint; index++)
                {
                    Double distance = PerpendicularDistance(points[firstPoint], points[lastPoint], points[index]);
                    if (distance > maxDistance)
                    {
                        maxDistance = distance;
                        indexFarthest = index;
                    }
                }
                if (maxDistance > tolerance && indexFarthest != 0)
                {
                    pointIndexsToKeep.Add(indexFarthest);
                    DouglasPeuckerReduction(points, firstPoint, indexFarthest, tolerance, ref pointIndexsToKeep);
                    DouglasPeuckerReduction(points, indexFarthest, lastPoint, tolerance, ref pointIndexsToKeep);
                }
            }
            public static Double PerpendicularDistance(Point Point1, Point Point2, Point Point)
            {
                Double area = Math.Abs(.5 * (Point1.year * Point2.value + Point2.year * Point.value + Point.year * Point1.value - Point2.year * Point1.value - Point.year * Point2.value - Point1.year * Point.value));
                Double bottom = Math.Sqrt(Math.Pow(Point1.year - Point2.year, 2) + Math.Pow(Point1.value - Point2.value, 2));
                Double height = area / bottom * 2;
                return height;
            }
        }

    Original value

    The lower the value of numericUpDown1, the closer the points are to the original points:

    The higher the value of numericUpDown1, the more points will be deleted by the algorithm:

    Hope it can help you.

    Best Regards,

    Xingyu Zhao



    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, August 14, 2019 3:18 AM
    Moderator