ScottPlot.NET
GitHub Repo stars

Bar Plot

Bar Plot Quickstart

Bar plots can be added from a series of values.

ScottPlot.Plot myPlot = new();

// add bars
double[] values = { 5, 10, 7, 13 };
myPlot.Add.Bars(values);

// tell the plot to autoscale with no padding beneath the bars
myPlot.Axes.Margins(bottom: 0);

myPlot.SavePng("demo.png", 400, 300);

Bar Plot Legend

A collection of bars can appear in the legend as a single item.

ScottPlot.Plot myPlot = new();

double[] xs1 = { 1, 2, 3, 4 };
double[] ys1 = { 5, 10, 7, 13 };
var bars1 = myPlot.Add.Bars(xs1, ys1);
bars1.LegendText = "Alpha";

double[] xs2 = { 6, 7, 8, 9 };
double[] ys2 = { 7, 12, 9, 15 };
var bars2 = myPlot.Add.Bars(xs2, ys2);
bars2.LegendText = "Beta";

myPlot.ShowLegend(Alignment.UpperLeft);
myPlot.Axes.Margins(bottom: 0);

myPlot.SavePng("demo.png", 400, 300);

Bar with Value Labels

Set the Label property of bars to have text displayed above each bar.

ScottPlot.Plot myPlot = new();

double[] values = { 5, 10, 7, 13 };
var barPlot = myPlot.Add.Bars(values);

// define the content of labels
foreach (var bar in barPlot.Bars)
{
    bar.Label = bar.Value.ToString();
}

// customize label style
barPlot.ValueLabelStyle.Bold = true;
barPlot.ValueLabelStyle.FontSize = 18;

myPlot.Axes.Margins(bottom: 0, top: .2);

myPlot.SavePng("demo.png", 400, 300);

Bar with Value Labels (horizontal)

Set the Label property of bars to have text displayed beside (left or right) of each bar.

ScottPlot.Plot myPlot = new();

double[] values = { -20, 10, 7, 13 };

// set the label for each bar
var barPlot = myPlot.Add.Bars(values);
foreach (var bar in barPlot.Bars)
{
    bar.Label = "Label " + bar.Value.ToString();
}

// customize label style
barPlot.ValueLabelStyle.Bold = true;
barPlot.ValueLabelStyle.FontSize = 18;
barPlot.Horizontal = true;

// add extra margin to account for label
myPlot.Axes.SetLimitsX(-45, 35);
myPlot.Add.VerticalLine(0, 1, Colors.Black);

myPlot.SavePng("demo.png", 400, 300);

Labels on Top

Bars with labels are rendered one at a time by default, but this makes it possible for bar labels to get overlapped by other bars. Bar chars may be configured to render labels last, even above other plottables.

ScottPlot.Plot myPlot = new();

double[] values = Generate.Consecutive(5, first: 1);

// create two bar plots
var bars1 = myPlot.Add.Bars(values);
var bars2 = myPlot.Add.Bars(values);

// enable the LabelsOnTop feature on one of the bars
bars2.LabelsOnTop = true;

// give each bar a label and style it to demonstrate the effect
static void StyleBar(ScottPlot.Plottables.BarPlot barPlot, double xOffset)
{
    barPlot.ValueLabelStyle.FontSize = 32;
    for (int i = 0; i < barPlot.Bars.Count; i++)
    {
        var bar = barPlot.Bars[i];
        bar.Label = i.ToString();
        bar.CenterLabel = true;
        bar.Position = i * .5 + xOffset;
        bar.FillColor = bar.FillColor.WithAlpha(.9);
    }
}

StyleBar(bars1, 0);
StyleBar(bars2, 4);

myPlot.Add.Text("Default", 0, 6);
myPlot.Add.Text("LabelsOnTop", 4, 6);

myPlot.HideGrid();

myPlot.SavePng("demo.png", 400, 300);

Bar Positioning

The exact position and size of each bar may be customized.

ScottPlot.Plot myPlot = new();

ScottPlot.Bar[] bars =
{
    new() { Position = 1, Value = 5, ValueBase = 3, FillColor = Colors.Red },
    new() { Position = 2, Value = 7, ValueBase = 0, FillColor = Colors.Blue },
    new() { Position = 4, Value = 3, ValueBase = 2, FillColor = Colors.Green },
};

myPlot.Add.Bars(bars);

myPlot.SavePng("demo.png", 400, 300);

Bars with Error

Bars can have errorbars.

ScottPlot.Plot myPlot = new();

ScottPlot.Bar[] bars =
{
    new() { Position = 1, Value = 5, Error = 1, FillColor = Colors.Red },
    new() { Position = 2, Value = 7, Error = 2, FillColor = Colors.Orange },
    new() { Position = 3, Value = 6, Error = 1, FillColor = Colors.Green },
    new() { Position = 4, Value = 8, Error = 2, FillColor = Colors.Blue },
};

myPlot.Add.Bars(bars);

// tell the plot to autoscale with no padding beneath the bars
myPlot.Axes.Margins(bottom: 0);

myPlot.SavePng("demo.png", 400, 300);

Bars with Labeled Ticks

Bars can be labeled by manually specifying axis tick mark positions and labels.

ScottPlot.Plot myPlot = new();

myPlot.Add.Bar(position: 1, value: 5, error: 1);
myPlot.Add.Bar(position: 2, value: 7, error: 2);
myPlot.Add.Bar(position: 3, value: 6, error: 1);
myPlot.Add.Bar(position: 4, value: 8, error: 2);

Tick[] ticks =
{
    new(1, "Apple"),
    new(2, "Orange"),
    new(3, "Pear"),
    new(4, "Banana"),
};

myPlot.Axes.Bottom.TickGenerator = new ScottPlot.TickGenerators.NumericManual(ticks);
myPlot.Axes.Bottom.MajorTickStyle.Length = 0;
myPlot.HideGrid();

// tell the plot to autoscale with no padding beneath the bars
myPlot.Axes.Margins(bottom: 0);

myPlot.SavePng("demo.png", 400, 300);

Bar Fill Style

Each bar may be individually styled.

ScottPlot.Plot myPlot = new();

// add bars with sample data
double[] values = { 3, 7, 9 };
var barPlot = myPlot.Add.Bars(values);

// bars may be styled after they have been added
barPlot.Bars[0].FillColor = Colors.Orange;
barPlot.Bars[1].FillColor = Colors.Green;
barPlot.Bars[2].FillColor = Colors.Navy;

barPlot.Bars[0].FillHatch = new ScottPlot.Hatches.Striped();
barPlot.Bars[1].FillHatch = new ScottPlot.Hatches.Dots();
barPlot.Bars[2].FillHatch = new ScottPlot.Hatches.Checker();

foreach (var bar in barPlot.Bars)
{
    bar.LineWidth = 2;
    bar.LineColor = bar.FillColor.Darken(0.5);
    bar.FillHatchColor = bar.FillColor.Lighten(0.1);
}

// tell the plot to autoscale with no padding beneath the bars
myPlot.Axes.Margins(bottom: 0);

myPlot.SavePng("demo.png", 400, 300);

Customized Bar Plot

Ultimate control of bar plot styling and positioning may be achieved by creating each bar individually, styling it as desired, and setting its exact size and location. This level of customization may be used to create extremely advanced stacked or grouped bar plots.

ScottPlot.Plot myPlot = new();

ScottPlot.Bar bar1 = new()
{
    Position = 2,
    Value = 5,
};

myPlot.Add.Bar(bar1);

ScottPlot.Bar bar2 = new()
{
    Position = 5,
    Value = 7,
    ValueBase = 2,
    Error = 1,
    FillColor = Colors.Magenta,
    LineWidth = 3,
    LineColor = Colors.Navy,
    FillHatch = new ScottPlot.Hatches.Striped(),
    FillHatchColor = Colors.Magenta.Lighten(.2),
};

myPlot.Add.Bar(bar2);

myPlot.HideGrid();

myPlot.SavePng("demo.png", 400, 300);

Stacked Bar Plot

Bars can be positioned on top of each other.

ScottPlot.Plot myPlot = new();

ScottPlot.Palettes.Category10 palette = new();

ScottPlot.Bar[] bars =
{
    // first set of stacked bars
    new() { Position = 1, ValueBase = 0, Value = 2, FillColor = palette.GetColor(0) },
    new() { Position = 1, ValueBase = 2, Value = 5, FillColor = palette.GetColor(1) },
    new() { Position = 1, ValueBase = 5, Value = 10, FillColor = palette.GetColor(2) },

    // second set of stacked bars
    new() { Position = 2, ValueBase = 0, Value = 4, FillColor = palette.GetColor(0) },
    new() { Position = 2, ValueBase = 4, Value = 7, FillColor = palette.GetColor(1) },
    new() { Position = 2, ValueBase = 7, Value = 10, FillColor = palette.GetColor(2) },
};

myPlot.Add.Bars(bars);

Tick[] ticks =
{
    new(1, "Spring"),
    new(2, "Summer"),
};

myPlot.Axes.Bottom.TickGenerator = new ScottPlot.TickGenerators.NumericManual(ticks);
myPlot.Axes.Bottom.MajorTickStyle.Length = 0;
myPlot.HideGrid();

// tell the plot to autoscale with no padding beneath the bars
myPlot.Axes.Margins(bottom: 0);

myPlot.SavePng("demo.png", 400, 300);

Grouped Bar Plot

Bars can be grouped by position and color.

ScottPlot.Plot myPlot = new();

ScottPlot.Palettes.Category10 palette = new();

ScottPlot.Bar[] bars =
{
    // first group
    new() { Position = 1, Value = 2, FillColor = palette.GetColor(0), Error = 1 },
    new() { Position = 2, Value = 5, FillColor = palette.GetColor(1), Error = 2 },
    new() { Position = 3, Value = 7, FillColor = palette.GetColor(2), Error = 1 },

    // second group
    new() { Position = 5, Value = 4, FillColor = palette.GetColor(0), Error = 2 },
    new() { Position = 6, Value = 7, FillColor = palette.GetColor(1), Error = 1 },
    new() { Position = 7, Value = 13, FillColor = palette.GetColor(2), Error = 3 },

    // third group
    new() { Position = 9, Value = 5, FillColor = palette.GetColor(0), Error = 1 },
    new() { Position = 10, Value = 6, FillColor = palette.GetColor(1), Error = 3 },
    new() { Position = 11, Value = 11, FillColor = palette.GetColor(2), Error = 2 },
};

myPlot.Add.Bars(bars);

// build the legend manually
myPlot.Legend.IsVisible = true;
myPlot.Legend.Alignment = Alignment.UpperLeft;
myPlot.Legend.ManualItems.Add(new() { LabelText = "Monday", FillColor = palette.GetColor(0) });
myPlot.Legend.ManualItems.Add(new() { LabelText = "Tuesday", FillColor = palette.GetColor(1) });
myPlot.Legend.ManualItems.Add(new() { LabelText = "Wednesday", FillColor = palette.GetColor(2) });

// show group labels on the bottom axis
Tick[] ticks =
{
    new(2, "Group 1"),
    new(6, "Group 2"),
    new(10, "Group 3"),
};
myPlot.Axes.Bottom.TickGenerator = new ScottPlot.TickGenerators.NumericManual(ticks);
myPlot.Axes.Bottom.MajorTickStyle.Length = 0;
myPlot.HideGrid();

// tell the plot to autoscale with no padding beneath the bars
myPlot.Axes.Margins(bottom: 0);

myPlot.SavePng("demo.png", 400, 300);

Horizontal Bar Plot

Bar plots can be displayed horizontally.

ScottPlot.Plot myPlot = new();

ScottPlot.Bar[] bars =
{
    new() { Position = 1, Value = 5, Error = 1, },
    new() { Position = 2, Value = 7, Error = 2, },
    new() { Position = 3, Value = 6, Error = 1, },
    new() { Position = 4, Value = 8, Error = 2, },
};

var barPlot = myPlot.Add.Bars(bars);
barPlot.Horizontal = true;

myPlot.Axes.Margins(left: 0);

myPlot.SavePng("demo.png", 400, 300);

Stacked Bar Chart

Bars can be stacked to present data in groups.

ScottPlot.Plot myPlot = new();

string[] categoryNames = { "Phones", "Computers", "Tablets" };
Color[] categoryColors = { Colors.C0, Colors.C1, Colors.C2 };

for (int x = 0; x < 4; x++)
{
    double[] values = Generate.RandomSample(categoryNames.Length, 1000, 5000);

    double nextBarBase = 0;

    for (int i = 0; i < values.Length; i++)
    {
        ScottPlot.Bar bar = new()
        {
            Value = nextBarBase + values[i],
            FillColor = categoryColors[i],
            ValueBase = nextBarBase,
            Position = x,
        };

        myPlot.Add.Bar(bar);

        nextBarBase += values[i];
    }
}

// use custom tick labels on the bottom
ScottPlot.TickGenerators.NumericManual tickGen = new();
for (int x = 0; x < 4; x++)
{
    tickGen.AddMajor(x, $"Q{x + 1}");
}
myPlot.Axes.Bottom.TickGenerator = tickGen;

// display groups in the legend
for (int i = 0; i < 3; i++)
{
    LegendItem item = new()
    {
        LabelText = categoryNames[i],
        FillColor = categoryColors[i]
    };
    myPlot.Legend.ManualItems.Add(item);
}
myPlot.Legend.Orientation = Orientation.Horizontal;
myPlot.ShowLegend(Alignment.UpperRight);

// tell the plot to autoscale with no padding beneath the bars
myPlot.Axes.Margins(bottom: 0, top: .3);

myPlot.SavePng("demo.png", 400, 300);

Bar with Custom Text

Full control over bar labels may be achieved by placing fully customizable text objects on top of bars according to their dimensions.

ScottPlot.Plot myPlot = new();

ScottPlot.Palettes.Category10 palette = new();

// create 5 groups of stacked bars
for (int i = 0; i < 5; i++)
{
    // create 3 individual bars with stacking
    List<ScottPlot.Bar> bars = [];
    double valueBase = 0;
    for (int j = 0; j < 3; j++)
    {
        double barSize = Generate.RandomInteger(10, 20);
        ScottPlot.Bar bar1 = new()
        {
            FillColor = palette.GetColor(j),
            Position = i,
            ValueBase = valueBase,
            Value = valueBase + barSize,
            Label = $"{barSize}",
            CenterLabel = true,
        };

        bars.Add(bar1);
        valueBase += barSize;
    }

    // plot the stacked bars
    var barPlot = myPlot.Add.Bars(bars);
    barPlot.Horizontal = true;
}

// style the plot so the bars start on the left edge
myPlot.Axes.Margins(left: 0);

// add custom group labels
double[] tickPositions = Generate.Consecutive(5);
string[] tickLabels = Enumerable.Range(1, 5).Select(x => $"Worker #{x}").ToArray();
myPlot.Axes.Left.SetTicks(tickPositions, tickLabels);

myPlot.SavePng("demo.png", 400, 300);

Range Chart

A range chart displays a discrete set of named value ranges

ScottPlot.Plot myPlot = new();

List<(string name, CoordinateRange range)> ranges =
[
    ("Africa", new(-35, 37)),
    ("Antarctica", new(-90, -60)),
    ("Asia", new(-11, 81)),
    ("Europe", new(-36, 71)),
    ("North America", new(-7, 83)),
    ("South America", new(-56, 13)),
    ("Australia", new(-47, -28)),
];
myPlot.Add.Ranges(ranges);

// style the axes
myPlot.Title("Latitude Range of the Continents");
myPlot.Axes.Bottom.TickLabelStyle.Rotation = -45;
myPlot.Axes.Bottom.TickLabelStyle.Alignment = Alignment.MiddleRight;
myPlot.Axes.Bottom.MinimumSize = 100;

// use tick labels with a degree symbol
ScottPlot.TickGenerators.NumericAutomatic tickGen = new();
myPlot.Axes.Left.TickGenerator = tickGen;
tickGen.LabelFormatter = (x) => $"{x}º";

// add a horizontal line at zero and push it beneath the range plot
var hl = myPlot.Add.HorizontalLine(0, 1, Colors.Black, LinePattern.DenselyDashed);
myPlot.MoveToBack(hl);

myPlot.SavePng("demo.png", 400, 300);

Horizontal Range Chart

Range charts may be created using horizontally oriented bars

ScottPlot.Plot myPlot = new();

List<(string name, CoordinateRange range)> ranges =
[
    ("Ontario", new(-9, 51)),
    ("England", new(0, 63)),
    ("Kentucky", new(-4, 72)),
];

myPlot.Add.Ranges(ranges, horizontal: true);

myPlot.XLabel("Temperature (ºF)");

myPlot.SavePng("demo.png", 400, 300);

Stacked Range Chart

Stacked range charts depict multiple ranges for a discrete set of items

ScottPlot.Plot myPlot = new();

// prepare a custom color palette
string[] colorCodes = ["#3369cc", "#95bce3", "#f4a861", "#fd8d00"];
ScottPlot.Palettes.Custom palette = new(colorCodes);

// create a stacked bar chart with a collection of named ranges
string[] rangeNames = ["Yearly Low", "Mean Daily Low", "Mean Daily High", "Yearly High"];
List<(string name, double[] edges)> ranges =
[
    ("Ontario", [-9, 3, 7, 13, 27]),
    ("England", [4, 7, 12, 16, 24]),
    ("Kentucky", [-4, 7, 13, 20, 30]),
];
myPlot.Add.StackedRanges(ranges, palette);

// use tick labels with a degree symbol
ScottPlot.TickGenerators.NumericAutomatic tickGen = new();
myPlot.Axes.Left.TickGenerator = tickGen;
tickGen.LabelFormatter = (x) => $"{x}º";

// display the legend outside the data area
myPlot.ShowLegend(Edge.Right);

// add items to the legend manually
for (int i = 0; i < rangeNames.Length; i++)
{
    LegendItem item = new()
    {
        LabelText = rangeNames[i],
        FillColor = palette.GetColor(i),
    };
    myPlot.Legend.ManualItems.Add(item);
}
myPlot.Legend.ManualItems.Reverse();

// improve styling and alignment
myPlot.Legend.OutlineStyle.IsVisible = false;
myPlot.Legend.ShadowColor = Colors.Transparent;
myPlot.Legend.Padding = new(0);
myPlot.Axes.Right.MaximumSize = 0;

myPlot.SavePng("demo.png", 400, 300);

Stacked Horizontal Range Chart

Horizontally oriented stacked range charts may be created

ScottPlot.Plot myPlot = new();

List<(string name, double[] edges)> ranges =
[
    ("Ontario", [-9, 3, 7, 13, 27]),
    ("England", [4, 7, 12, 16, 24]),
    ("Kentucky", [-4, 7, 13, 20, 30]),
];

myPlot.Add.StackedRanges(ranges, horizontal: true);

myPlot.SavePng("demo.png", 400, 300);