#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.Dark; var theme = VisualTheme.Graphite(); var model = QuadrantChartRecipe.Create("wide", mode); var context = new VisualRenderContext( new VisualLayoutOptions(new VisualSize(800, 520)), theme, mode, new VisualFrame("Projects by effort and impact", "Thirteen proposals sorted into four action regions", 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 /// A quadrant chart: proposed projects placed by effort and impact, with four labelled regions. public static class QuadrantChartRecipe { public static Chart Create(string variant = "wide", VisualThemeMode mode = VisualThemeMode.Light) { if (variant is not ("wide" or "compact")) throw new ArgumentOutOfRangeException(nameof(variant)); var projects = new (string Name, double Effort, double Impact)[] { ("SSO rollout", 2.1, 8.6), ("Backup audit", 1.4, 6.9), ("MFA for admins", 1.1, 9.2), ("DNS cleanup", 2.8, 6.4), ("Data centre move", 8.7, 8.1), ("New SIEM", 7.6, 7.4), ("Zero trust", 9.1, 9.0), ("Wiki refresh", 1.8, 2.6), ("Printer fleet", 3.1, 1.7), ("Desk booking", 2.4, 3.8), ("ERP upgrade", 8.2, 3.9), ("Legacy CRM port", 6.9, 2.2), ("Intranet redesign", 6.1, 4.4) }; var count = variant == "compact" ? 8 : projects.Length; var series = ChartSeries.CreateScatter(new ChartSeriesId("projects"), "Projects", projects.Take(count).Select(project => new ChartPoint(project.Effort, project.Impact))); for (var index = 0; index < count; index++) series.WithPointLabel(index, projects[index].Name); series.ConfigureMarkers(markers => { markers.Radius = 6; }); var colors = VisualTheme.Graphite().Resolve(mode); return Chart.Create().WithXAxisBounds(0, 10).WithYAxisBounds(0, 10).WithLegend(false).WithDataLabels() .WithXAxis("Effort (person-months)").WithYAxis("Impact (score)").AddSeries(series) .AddPlotRegion(new(colors.Status.Pass.Fill, xMaximum: 5, yMinimum: 5, label: "Quick wins", opacity: .14)) .AddPlotRegion(new(colors.Palette.First(), xMinimum: 5, yMinimum: 5, label: "Major projects", opacity: .12)) .AddPlotRegion(new(colors.Status.Medium.Fill, xMaximum: 5, yMaximum: 5, label: "Fill-ins", opacity: .12)) .AddPlotRegion(new(colors.Status.Critical.Fill, xMinimum: 5, yMaximum: 5, label: "Thankless tasks", opacity: .1)); } }