Moving average calculation
Skip() is not optimized for IList&lt;T&gt;, it always enumerates the skipped elements. This means that your algorithm is O(n2) for no good reason. What you should do instead is to manually iterate just the required part of the input in each iteration using for. Something like:

double sum = 0;
for (int i = 0; i &lt; actualFrameSize; i++)
{
    sum += data[start + i].Y;
}


(I don't like using GetRange() for this, as in tinstaafl's answer, because it unnecessarily copies the frame into a new list.)

If frameSize is large, another optimization would be not to recompute the sum of the frame for each index. Instead, just add the item from the front and subtract the item from the back:

public PointPairList GetMovingAverage(int frameSize, PointPairList data)
{
    var movAvgPoints = new PointPairList();

    //Before zero
    int currentFrameSize = frameSize/2;
    double sum = data.Take(currentFrameSize).Sum(p =&gt; p.Y);

    //Smooth each point in the list
    for (int i = 0; i &lt; data.Count; i++)
    {
        int removed = i - (frameSize/2) - 1;
        int added = i + (frameSize/2);

        if (removed &gt;= 0)
        {
            sum -= data[removed].Y;
            currentFrameSize--;
        }
        if (added &lt; data.Count)
        {
            sum += data[added].Y;
            currentFrameSize++;
        }

        movAvgPoints.Add(new PointPair(data[i].X, sum/actualFrameSize));
    }

    return movAvgPoints;
}


If the length of data is n and frameSize is f, then the previous algorithm would be O(fn), but the improved one just O(n).



Another thing: there is usually no need to create types that derive from List, just use List&lt;PointPair&gt; directly.