Preview


800 × 440 pixels
Create this example
Create a console project, add the ChartForgeX package, and replace Program.cs with this source. Run it to write SVG, PNG and HTML with the default system fonts.
For the same typography as the gallery, download the gallery-font recipe and copy the gallery’s fonts directory beside your program.
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 = ComparisonRecipe.Create("wide", mode);
var context = new VisualRenderContext(
new VisualLayoutOptions(new VisualSize(800, 440)), theme, mode,
new VisualFrame("Checks over the reporting period", "One prepared scene for SVG and native PNG", 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());
/// <summary>Line, area and bar observations share categories, including explicit missing and empty states.</summary>
public static class ComparisonRecipe {
public static Chart Create(string variant = "wide", VisualThemeMode mode = VisualThemeMode.Light) {
var count = variant == "empty" ? 0 : variant == "dense" ? 24 : 7;
var names = variant == "wrapped-legend"
? new[] { "Observed checks across all locations", "Expected coverage of monitored services", "Capacity available for the next assessment" }
: new[] { "Observed", "Expected", "Capacity" };
var observed = ChartSeries.CreateLine(new ChartSeriesId("observed"), names[0], Points(count, variant, 0));
var expected = ChartSeries.CreateArea(new ChartSeriesId("expected"), names[1], Points(count, variant, 1));
var capacity = ChartSeries.CreateBar(new ChartSeriesId("capacity"), names[2], Points(count, variant, 2, false));
if (variant is "explicit-status" or "explicit-series") {
var colors = VisualTheme.Graphite().Resolve(mode);
var selected = variant == "explicit-status"
? new[] { colors.Status.Pass.Fill, colors.Status.Medium.Fill, colors.Status.Critical.Fill }
: colors.Palette.Take(3).ToArray();
observed.WithColor(selected[0]); expected.WithColor(selected[1]); capacity.WithColor(selected[2]);
}
return Chart.Create().WithXLabels(Enumerable.Range(1, count).Select(index => "Day " + index).ToArray())
.AddSeries(observed).AddSeries(expected).AddSeries(capacity);
}
private static IEnumerable<ChartPoint> Points(int count, string variant, int series, bool allowBreaks = true) {
for (var index = 0; index < count; index++) {
if (variant == "missing" && (index == 2 || index == 3)) continue;
var value = variant == "zero" ? 0 : 20 + series * 14 + index * (series + 3) % 23;
yield return new ChartPoint(index + 1, value, allowBreaks && variant == "missing" && index == 4);
}
}
}
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 = ComparisonRecipe.Create("wide", mode);
var context = new VisualRenderContext(
new VisualLayoutOptions(new VisualSize(800, 440)), theme, mode,
new VisualFrame("Checks over the reporting period", "One prepared scene for SVG and native PNG", 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());
/// <summary>Line, area and bar observations share categories, including explicit missing and empty states.</summary>
public static class ComparisonRecipe {
public static Chart Create(string variant = "wide", VisualThemeMode mode = VisualThemeMode.Light) {
var count = variant == "empty" ? 0 : variant == "dense" ? 24 : 7;
var names = variant == "wrapped-legend"
? new[] { "Observed checks across all locations", "Expected coverage of monitored services", "Capacity available for the next assessment" }
: new[] { "Observed", "Expected", "Capacity" };
var observed = ChartSeries.CreateLine(new ChartSeriesId("observed"), names[0], Points(count, variant, 0));
var expected = ChartSeries.CreateArea(new ChartSeriesId("expected"), names[1], Points(count, variant, 1));
var capacity = ChartSeries.CreateBar(new ChartSeriesId("capacity"), names[2], Points(count, variant, 2, false));
if (variant is "explicit-status" or "explicit-series") {
var colors = VisualTheme.Graphite().Resolve(mode);
var selected = variant == "explicit-status"
? new[] { colors.Status.Pass.Fill, colors.Status.Medium.Fill, colors.Status.Critical.Fill }
: colors.Palette.Take(3).ToArray();
observed.WithColor(selected[0]); expected.WithColor(selected[1]); capacity.WithColor(selected[2]);
}
return Chart.Create().WithXLabels(Enumerable.Range(1, count).Select(index => "Day " + index).ToArray())
.AddSeries(observed).AddSeries(expected).AddSeries(capacity);
}
private static IEnumerable<ChartPoint> Points(int count, string variant, int series, bool allowBreaks = true) {
for (var index = 0; index < count; index++) {
if (variant == "missing" && (index == 2 || index == 3)) continue;
var value = variant == "zero" ? 0 : 20 + series * 14 + index * (series + 3) % 23;
yield return new ChartPoint(index + 1, value, allowBreaks && variant == "missing" && index == 4);
}
}
}