// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) 2014 OxyPlot contributors // // // Provides examples for the ExtrapolationLineSeries. // // -------------------------------------------------------------------------------------------------------------------- namespace ExampleLibrary.Series { using ExampleLibrary.Utilities; using OxyPlot; using OxyPlot.Axes; using OxyPlot.Legends; using OxyPlot.Series; using System; using System.Collections.Generic; using System.Linq; /// /// Provides examples for the . /// [Examples("ExtrapolationLineSeries")] [Tags("Series")] public static class ExtrapolationLineSeriesExamples { /// /// Creates an example showing a line fit which is extrapolated /// beyond the range given by the data points. /// /// A . [Example("Line Fit (Ignore Extrapolation For Scaling)")] public static PlotModel ExtrapolatedLineSeries() { var model = new PlotModel { Title = "Line Fit" }; var scatterSeries = new ScatterSeries() { Title = "Data", }; scatterSeries.Points.Add(new ScatterPoint(3, 1.4)); scatterSeries.Points.Add(new ScatterPoint(4, 1.3)); scatterSeries.Points.Add(new ScatterPoint(5, 1.6)); scatterSeries.Points.Add(new ScatterPoint(6, 2.3)); scatterSeries.Points.Add(new ScatterPoint(7, 2.2)); scatterSeries.Points.Add(new ScatterPoint(8, 2.5)); scatterSeries.Points.Add(new ScatterPoint(9, 2.9)); scatterSeries.Points.Add(new ScatterPoint(10, 3.1)); scatterSeries.Points.Add(new ScatterPoint(11, 3.1)); scatterSeries.Points.Add(new ScatterPoint(12, 3.8)); model.Series.Add(scatterSeries); CalculateLinearRegressionParameters(scatterSeries.Points, out double slope, out double intercept); var lineSeries = new ExtrapolationLineSeries { Title = "Fit", Color = OxyColors.Black, LineStyle = LineStyle.Solid, ExtrapolationColor = OxyColors.DarkGray, ExtrapolationLineStyle = LineStyle.Dash, StrokeThickness = 3, IgnoreExtraplotationForScaling = true, }; lineSeries.Intervals.Add(new DataRange(double.NegativeInfinity, scatterSeries.Points.Select(p => p.X).Min())); lineSeries.Intervals.Add(new DataRange(scatterSeries.Points.Select(p => p.X).Max(), double.PositiveInfinity)); var fitPoints = Enumerable .Range(-100, 200) .Select(x => new DataPoint(x, (slope * x) + intercept)); lineSeries.Points.AddRange(fitPoints); model.Series.Add(lineSeries); var legend = new Legend { LegendPosition = LegendPosition.BottomRight, }; model.Legends.Add(legend); return model; } /// /// Creates an example showing a third-order polynomial with extra- and interpolation style. /// /// A . [Example("Interpolation")] public static PlotModel InterpolationStyleLineSeries() { var model = new PlotModel { Title = "Interpolation" }; var lineSeries = new ExtrapolationLineSeries { Title = "Third Order Polynomial", Color = OxyColors.Black, LineStyle = LineStyle.Dash, ExtrapolationColor = OxyColors.Gray, ExtrapolationLineStyle = LineStyle.Dot, StrokeThickness = 3, }; lineSeries.Intervals.Add(new DataRange(double.NegativeInfinity, -15)); lineSeries.Intervals.Add(new DataRange(10, 30)); lineSeries.Intervals.Add(new DataRange(55, double.PositiveInfinity)); var coefficients = new double[] { 0.1, -6.0, -12, 0 }; double PolynomialValue(double x, IEnumerable coeff) { // Horner's schema return coeff.Aggregate((acc, coefficient) => (acc * x) + coefficient); } var points = Enumerable .Range(-30, 100) .Select(x => new DataPoint(x, PolynomialValue(x, coefficients))); lineSeries.Points.AddRange(points); model.Series.Add(lineSeries); var legend = new Legend { LegendPosition = LegendPosition.TopCenter, }; model.Legends.Add(legend); return model; } /// /// Creates an example showing a third-order polynomial with extra- and /// interpolation style and an inverted y-axis. /// /// A . [Example("Interpolation (Y Axis reversed)")] public static PlotModel TwoColorLineSeriesReversed() { return InterpolationStyleLineSeries().ReverseYAxis(); } /// /// Creates an example where the provided extrapolation /// intervals overlap with each other. /// /// A . [Example("Intersecting Intervals")] public static PlotModel IntersectingIntervals() { var model = new PlotModel { Title = "Intersecting Intervals" }; var i1 = new DataRange(-20, 20); var i2 = new DataRange(0, 30); var i3 = new DataRange(10, 40); var lineSeries = new ExtrapolationLineSeries { Title = $"Overlapping intervals {i1}, {i2}, {i3}", Color = OxyColors.Black, LineStyle = LineStyle.Solid, ExtrapolationColor = OxyColors.Gray, ExtrapolationLineStyle = LineStyle.Dot, StrokeThickness = 3, }; lineSeries.Intervals.Add(i1); lineSeries.Intervals.Add(i2); lineSeries.Intervals.Add(i3); var coefficients = new double[] { 0.1, -6.0, -12, 0 }; double PolynomialValue(double x, IEnumerable coeff) { // Horner's schema return coeff.Aggregate((acc, coefficient) => (acc * x) + coefficient); } var points = Enumerable .Range(-30, 100) .Select(x => new DataPoint(x, PolynomialValue(x, coefficients))); lineSeries.Points.AddRange(points); model.Series.Add(lineSeries); var legend = new Legend { LegendPosition = LegendPosition.TopCenter, }; model.Legends.Add(legend); return model; } /// /// Creates an example showing a line using custom dash arrays for the /// normal and extrapolated parts of the curve. /// /// A . [Example("Custom Dashes")] public static PlotModel CustomDashes() { var model = new PlotModel { Title = "Custom Dashes" }; var lineSeries = new ExtrapolationLineSeries { Title = "y = 5", Color = OxyColors.Black, LineStyle = LineStyle.Dash, Dashes = new double[] { 5, 1 }, ExtrapolationColor = OxyColors.Gray, ExtrapolationLineStyle = LineStyle.Dot, ExtrapolationDashes = new double[] { 1, 5 }, StrokeThickness = 3, }; lineSeries.Intervals.Add(new DataRange(double.NegativeInfinity, 0)); var points = Enumerable .Range(-100, 200) .Select(x => new DataPoint(x, 5)); lineSeries.Points.AddRange(points); model.Series.Add(lineSeries); var legend = new Legend { LegendPosition = LegendPosition.TopCenter, }; model.Legends.Add(legend); return model; } /// /// Creates an example to test the performance with 100000 points and 100 intervals. /// /// A . [Example("Many Intervals")] public static PlotModel ManyIntervals() { var model = new PlotModel { Title = "ManyIntervals" }; var lineSeries = new ExtrapolationLineSeries { Title = "y = x", Color = OxyColors.Red, LineStyle = LineStyle.Solid, ExtrapolationLineStyle = LineStyle.Solid, StrokeThickness = 3, IgnoreExtraplotationForScaling = true, }; lineSeries.Intervals.Add(new DataRange(-1000, 10_000)); var intervals = Enumerable .Range(0, 98) .Select(x => new DataRange(1000 * x, (1000 * x) + 500)); foreach(var interval in intervals) lineSeries.Intervals.Add(interval); lineSeries.Intervals.Add(new DataRange(200_000, double.PositiveInfinity)); var points = Enumerable .Range(0, 100_000) .Select(x => new DataPoint(x, x)); lineSeries.Points.AddRange(points); model.Series.Add(lineSeries); var legend = new Legend { LegendPosition = LegendPosition.TopCenter, }; model.Legends.Add(legend); return model; } /// /// Creates an example where Moore's law is fitted and /// extrapolated to the future. /// /// A . [Example("Moore's Law")] public static PlotModel MooresLaw() { var model = new PlotModel { Title = "Moore's Law" }; var scatterSeries = new ScatterSeries() { Title = "Data", }; scatterSeries.Points.AddRange(GetPointForMooresLaw()); model.Series.Add(scatterSeries); model.Axes.Add(new LinearAxis { Title = "Year", Position = AxisPosition.Bottom }); model.Axes.Add(new LogarithmicAxis { Title = "Transistors (in thousands)", Position = AxisPosition.Left }); CalculateLinearRegressionParameters(scatterSeries.Points.Select(p => new ScatterPoint(p.X, Math.Log10(p.Y))), out double slope, out double intercept); var lineSeries = new ExtrapolationLineSeries { Title = "Fit and Extrapolation", Color = OxyColors.Black, LineStyle = LineStyle.Solid, ExtrapolationColor = OxyColors.Blue, ExtrapolationLineStyle = LineStyle.Dot, StrokeThickness = 3, }; lineSeries.Intervals.Add(new DataRange(2015, double.PositiveInfinity)); var fitPoints = Enumerable .Range(1970, 55) .Select(x => new DataPoint(x, Math.Pow(10, (slope * x) + intercept))); lineSeries.Points.AddRange(fitPoints); model.Series.Add(lineSeries); var legend = new Legend { LegendPosition = LegendPosition.TopCenter, }; model.Legends.Add(legend); return model; } /// /// Sets the slope and intercept of a linear regression line through the provided points. /// private static void CalculateLinearRegressionParameters(IEnumerable points, out double slope, out double intercept) { if (points == null) { throw new ArgumentNullException(nameof(points)); } if (points.Count() < 2) { throw new ArgumentException("at least two points required", nameof(points)); } var meanX = points.Select(p => p.X).Average(); var meanY = points.Select(p => p.Y).Average(); var cov = Covariance(points, meanX, meanY); var var2_x = Variance2(points.Select(p => p.X)); slope = cov / var2_x; intercept = meanY - (slope * meanX); } /// /// Returns the covariance between the points x and y values. /// private static double Covariance(IEnumerable points, double meanX, double meanY) { var res = points.Sum(p => p.X * p.Y); res -= points.Count() * meanX * meanY; res /= points.Count() - 1; return res; } /// /// Returns the squared variance of a quantity. /// private static double Variance2(IEnumerable values) { var mean = values.Average(); var res = values.Sum(x => x * x); res -= values.Count() * mean * mean; res /= values.Count() - 1; return res; } /// /// Returns data points to demonstrate Moore's law. /// Source: https://www.karlrupp.net/2015/06/40-years-of-microprocessor-trend-data/. /// private static IEnumerable GetPointForMooresLaw() { yield return new ScatterPoint(1971.875, 2.30824152676); yield return new ScatterPoint(1972.30769231, 3.55452235561); yield return new ScatterPoint(1974.32692308, 6.09756235221); yield return new ScatterPoint(1979.56730769, 29.1637757405); yield return new ScatterPoint(1982.30769231, 135.772714211); yield return new ScatterPoint(1985.91346154, 273.841963426); yield return new ScatterPoint(1986.25, 109.411381058); yield return new ScatterPoint(1988.65384615, 121.881418484); yield return new ScatterPoint(1989.47115385, 1207.90074743); yield return new ScatterPoint(1990.57692308, 1207.90074743); yield return new ScatterPoint(1992.40384615, 1207.90074743); yield return new ScatterPoint(1992.69230769, 3105.90022362); yield return new ScatterPoint(1992.69230769, 1113.97385999); yield return new ScatterPoint(1993.02884615, 1715.43789634); yield return new ScatterPoint(1993.41346154, 3105.90022362); yield return new ScatterPoint(1993.41346154, 922.239565104); yield return new ScatterPoint(1994.71153846, 1910.95297497); yield return new ScatterPoint(1994.71153846, 2788.12666541); yield return new ScatterPoint(1995.43269231, 9646.61619911); yield return new ScatterPoint(1995.72115385, 3105.90022362); yield return new ScatterPoint(1996.15384615, 5473.70326288); yield return new ScatterPoint(1996.34615385, 6792.52507006); yield return new ScatterPoint(1996.34615385, 3651.74127255); yield return new ScatterPoint(1996.44230769, 4293.51021008); yield return new ScatterPoint(1996.82692308, 9646.61619911); yield return new ScatterPoint(1997.35576923, 5473.70326288); yield return new ScatterPoint(1997.45192308, 3554.52235561); yield return new ScatterPoint(1997.54807692, 8896.4911282); yield return new ScatterPoint(1997.64423077, 7566.6953714); yield return new ScatterPoint(1998.89423077, 15261.3780258); yield return new ScatterPoint(1999.13461538, 9389.79801048); yield return new ScatterPoint(1999.18269231, 6978.3058486); yield return new ScatterPoint(1999.47115385, 9389.79801048); yield return new ScatterPoint(1999.47115385, 21673.9216957); yield return new ScatterPoint(2000.19230769, 22266.7201035); yield return new ScatterPoint(2000.67307692, 28387.3596476); yield return new ScatterPoint(2000.67307692, 37180.2666391); yield return new ScatterPoint(2001.10576923, 29163.7757405); yield return new ScatterPoint(2001.20192308, 42550.6550247); yield return new ScatterPoint(2001.68269231, 25482.9674798); yield return new ScatterPoint(2001.82692308, 37180.2666391); yield return new ScatterPoint(2002.40384615, 55730.6040127); yield return new ScatterPoint(2002.78846154, 38197.1754928); yield return new ScatterPoint(2002.88461538, 220673.406908); yield return new ScatterPoint(2003.41346154, 151247.254531); yield return new ScatterPoint(2003.50961538, 54246.9093701); yield return new ScatterPoint(2003.65384615, 106498.563535); yield return new ScatterPoint(2004.80769231, 125214.968907); yield return new ScatterPoint(2004.80769231, 106498.563535); yield return new ScatterPoint(2004.80769231, 273841.963426); yield return new ScatterPoint(2005.72115385, 232909.659246); yield return new ScatterPoint(2005.81730769, 112403.866377); yield return new ScatterPoint(2005.96153846, 305052.789027); yield return new ScatterPoint(2006.05769231, 115478.198469); yield return new ScatterPoint(2006.875, 378551.524926); yield return new ScatterPoint(2006.875, 155383.983127); yield return new ScatterPoint(2006.92307692, 245824.406892); yield return new ScatterPoint(2006.97115385, 296931.48482); yield return new ScatterPoint(2006.97115385, 582941.534714); yield return new ScatterPoint(2007.06730769, 151247.254531); yield return new ScatterPoint(2007.64423077, 582941.534714); yield return new ScatterPoint(2007.74038462, 232909.659246); yield return new ScatterPoint(2007.78846154, 805842.187761); yield return new ScatterPoint(2007.83653846, 115478.198469); yield return new ScatterPoint(2007.98076923, 509367.521678); yield return new ScatterPoint(2008.22115385, 445079.406236); yield return new ScatterPoint(2008.46153846, 410469.838044); yield return new ScatterPoint(2009.18269231, 457252.669897); yield return new ScatterPoint(2009.27884615, 784388.558145); yield return new ScatterPoint(2009.66346154, 2308241.52676); yield return new ScatterPoint(2009.71153846, 1910952.97497); yield return new ScatterPoint(2010.19230769, 410469.838044); yield return new ScatterPoint(2010.38461538, 1309747.2643); yield return new ScatterPoint(2011.16, 1170000); yield return new ScatterPoint(2011.32, 2600000); yield return new ScatterPoint(2011.9, 1200000); yield return new ScatterPoint(2012.40, 2400000); yield return new ScatterPoint(2012.41, 2300000); yield return new ScatterPoint(2012.7, 2100000); yield return new ScatterPoint(2012.9, 1200000); yield return new ScatterPoint(2013.4, 5000000); yield return new ScatterPoint(2013.8, 4300000); yield return new ScatterPoint(2014.16, 4300000); yield return new ScatterPoint(2014.5, 4200000); yield return new ScatterPoint(2014.8, 2600000); yield return new ScatterPoint(2014.81, 3800000); yield return new ScatterPoint(2014.82, 5700000); } } }