#region Setup using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using ChartForgeX.Core; using ChartForgeX.Primitives; using ChartForgeX.Rendering; using ChartForgeX.Themes; using ChartForgeX.Topology; using ChartForgeX.Typography; using ChartForgeX.VisualArtifacts; using ChartForgeX.VisualBlocks; var mode = VisualThemeMode.Light; var theme = VisualTheme.Graphite(); var model = TrendLineModelRecipe.Create("power", mode); var context = new VisualRenderContext( new VisualLayoutOptions(new VisualSize(800, 440)), theme, mode, new VisualFrame("Request volume and its trend", "", showLegend: null, showSurface: false)); var prepared = model.Prepare(context); File.WriteAllText("visual.svg", prepared.ToSvg()); File.WriteAllBytes("visual.png", prepared.ToPng()); File.WriteAllText("visual.html", prepared.ToArtifact("example", VisualArtifactKind.Chart).ToHtmlPage()); #endregion /// Fits the selected native model to retained measurements with a pointwise interval. public static class TrendLineModelRecipe { /// Creates observed values and a fitted curve; logarithmic-response intervals describe the conditional median. public static Chart Create(string variant = "polynomial", VisualThemeMode mode = VisualThemeMode.Light) { var selection = variant.StartsWith("compact-", StringComparison.Ordinal) ? variant.Substring(8) : variant; var model = selection switch { "polynomial" => ChartTrendLineModel.Polynomial, "logarithmic" => ChartTrendLineModel.Logarithmic, "exponential" => ChartTrendLineModel.Exponential, "power" => ChartTrendLineModel.Power, "confidence" or "prediction" => ChartTrendLineModel.Linear, _ => throw new ArgumentOutOfRangeException(nameof(variant)) }; var source = Enumerable.Range(1, 12).Select(index => { double x = index, residual = index % 3 - 1; var value = model switch { ChartTrendLineModel.Polynomial => 8 + .4 * x * x - .9 * x + .4 * residual, ChartTrendLineModel.Logarithmic => 4 + 5 * Math.Log(x) + .2 * residual, ChartTrendLineModel.Exponential => 5 * Math.Exp(.13 * x) * (1 + .04 * residual), ChartTrendLineModel.Power => 2 * Math.Pow(x, 1.4) * (1 + .04 * residual), _ => 12 + 1.8 * x + .8 * residual }; return new ChartPoint(x, value); }).ToArray(); var observations = ChartSeries.CreateScatter(new ChartSeriesId("measurements"), "Measured observations", source); var fit = ChartSeries.CreateTrendLine(new ChartSeriesId("native-fit"), model + " fit", source, null, options => { options.Model = model; options.PolynomialDegree = 2; options.Interval = selection == "prediction" ? ChartTrendLineIntervalKind.Prediction : ChartTrendLineIntervalKind.Confidence; options.ConfidenceLevel = .95; }); return Chart.Create().WithXAxis("Source X").WithYAxis("Observed response").WithLegend(true).WithDataLabels(false) .AddSeries(observations).AddSeries(fit); } }