Search code examples
c#.netwinformschartsmschart

smoothing stacked line graph


I have a c# Windows forms application that generates a stacked line graph using the standard MS Chart control, as in the below example.

Is there a way of "smoothing" the lines by formatting the series or some other property?

Looking at MSDN and Google I can't seem to find a way to do this, in Excel there a series.Smooth property...

I have I missed it or is it not possible?


Solution

  • If you liked the smooth look of the SplineAreas you can calculate the necessary values to get just that look:

    enter image description here

    A few notes:

    • I have reversed the order of the series; many ways to get the colors right.. (Instead one probably should accumulate in reverse)
    • The stacked DataPoints need to be aligned, as usual and any empty DataPoints should have their Y-Values to be 0.
    • Of course in the new series you can't access the actual data values any longer as you now have the accumulated values instead; at least not without reversing the calulation. So if need them keep them around somewhere. The new DataPoints' Tag property is one option..
    • You can control the ' smoothness' of each Series by setting its LineTension custom attribute:

     chart2.Series[0].SetCustomProperty("LineTension", "0.15");
    

    enter image description here Here is the full example code that creates the above screenshots calculating a 'stacked' SplineArea chart2 from the data in a StackedArea chart1:

    // preparation
    for (int i = 0; i < 4; i++)
    {
        Series s = chart1.Series.Add("S" + i);
        s.ChartType = SeriesChartType.StackedArea;
    
        Series s2 = chart2.Series.Add("S" + i);
        s2.ChartType = SeriesChartType.SplineArea;
    
    }
    
    for (int i = 0; i < 30; i++)   // some test data
    {
        chart1.Series[0].Points.AddXY(i, Math.Abs(Math.Sin(i / 8f)));
        chart1.Series[1].Points.AddXY(i, Math.Abs(Math.Sin(i / 4f)));
        chart1.Series[2].Points.AddXY(i, Math.Abs(Math.Sin(i / 1f)));
        chart1.Series[3].Points.AddXY(i, Math.Abs(Math.Sin(i / 0.5f)));
    }
    
    // the actual calculations:
    
    int sCount = chart1.Series.Count; 
    for (int i = 0; i < chart1.Series[0].Points.Count ; i++)
    {
        double v = chart1.Series[0].Points[i].YValues[0];
        chart2.Series[sCount - 1].Points.AddXY(i, v);
        for (int j = 1; j < sCount; j++)
        {
            v += chart1.Series[j].Points[i].YValues[0];
            chart2.Series[sCount - j - 1].Points.AddXY(i, v);
        }
    }
    
    // optionally control the tension:
    chart2.Series[0].SetCustomProperty("LineTension", "0.15");