Pie Series
This article do not include all the properties of the Pie Series class, it only highlights some features, to explore the full object checkout the API explorer
Name property
The name property is a string identifier that is normally used in tooltips and legends to display the data name, if this property is not set, then the library will generate a name for the series that by default is called "Series 1" when it is the first series in the series collection, "Series 2" when it is the second series in the series collection, "Series 3" when it is the third series in the series collection, and so on a series n will be named "Series n".
SeriesCollection = new ISeries[]
{
new PieSeries<int>
{
Values = new []{ 2, 5, 4, 2, 6 },
Name = "Income", // mark
Stroke = null
},
new PieSeries<int>
{
Values = new []{ 3, 7, 2, 9, 4 },
Name = "Outcome", // mark
Stroke = null
}
};
Values property
The Values
property is of type IEnumerable<T>
, this means that you can use any object that implements the IEnumerable<T>
interface,
such as Array
, List<T>
or ObservableCollection<T>
, this property contains the data to plot, you can use any type as the
generic argument (<T>
) as soon as you let the library how to handle it, the library already knows how to handle multiple types,
but you can register any type and teach the library how to handle any object in a chart, for more information please see the
mappers article.
var series1 = new PieSeries<int>
{
Values = new List<int> { 2, 1, 3 }
};
// == Update the chart when a value is added, removed or replaced == // mark
// using ObservableCollections allows the chart to update
// every time you add a new element to the values collection
// (not needed in Blazor, it just... updates)
var series2 = new PieSeries<double>
{
Values = new ObservableCollection<double> { 2, 1, 3 }
}
series2.add(4); // and the chart will animate the change!
// == Update the chart when a property in our collection changes == // mark
// if the object implements INotifyPropertyChanged, then the chart will
// update automatically when a property changes, the library already provides
// many 'ready to go' objects such as the ObservableValue class.
var observableValue = new ObservableValue(5);
var series3 = new PieSeries<ObservableValue>
{
Values = new ObservableCollection<ObservableValue> { observableValue },
}
observableValue.Value = 9; // the chart will animate the change from 5 to 9!
// == Passing X and Y coordinates // mark
// you can indicate both, X and Y using the Observable point class.
// or you could define your own object using mappers.
var series4 = new PieSeries<ObservablePoint>
{
Values = new ObservableCollection<ObservablePoint> { new ObservablePoint(2, 6)}
}
// == Custom types and mappers == // mark
// finally you can also use your own object, take a look at the City class.
public class City
{
public string Name { get; set; }
public double Population { get; set; }
}
// we must let the series know how to handle the city class.
// use the Mapping property to build a point from the city class
// you could also register the map globally.
// for more about global mappers info see:
// https://livecharts.dev/docs/maui/2.0.0-beta.950/Overview.Mappers
var citiesSeries = new PieSeries<City>
{
Values = new City[]
{
new City { Name = "Tokio", Population = 9 },
new City { Name = "New York", Population = 11 },
new City { Name = "Mexico City", Population = 10 },
},
Mapping = (city, point) =>
{
// this function will be called for every city in our data collection
// in this case Tokio, New York and Mexico city
// it takes the city and the point in the chart liveCharts built for the given city
// you must map the coordinates to the point
// use the Population property as the primary value (normally Y)
point.PrimaryValue = (float)city.Population;
// use the index of the city in our data collection as the secondary value
// (normally X)
point.SecondaryValue = point.Context.Index;
}
};
Automatic updates do not have a significant performance impact in most of the cases!
DataLabels
Data labels are labels for every point in a series, there are multiple properties to customize them, take a look at the following sample:
Series { get; set; } = new List<ISeries>
{
new PieSeries<double>
{
Values = new List<double> { 8 },
DataLabelsPaint = new SolidColorPaint(SKColors.Black),
DataLabelsSize = 22,
// for more information about available positions see:
// https://livecharts.dev/api/2.0.0-beta.950/LiveChartsCore.Measure.PolarLabelsPosition
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.Middle,
DataLabelsFormatter = point => point.PrimaryValue.ToString("N2") + " elements"
},
new PieSeries<double>
{
Values = new List<double> { 6 },
DataLabelsPaint = new SolidColorPaint(SKColors.Black),
DataLabelsSize = 22,
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.Middle,
DataLabelsFormatter = point => point.PrimaryValue.ToString("N2") + " elements"
},
new PieSeries<double>
{
Values = new List<double> { 4 },
DataLabelsPaint = new SolidColorPaint(SKColors.Black),
DataLabelsSize = 22,
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.Middle,
DataLabelsFormatter = point => point.PrimaryValue.ToString("N2") + " elements"
}
};
The series above result in the following chart:
You can also use the DataLabelsRotation
property to set an angle in degrees for the labels in the chart,
notice the constants LiveCharts.CotangentAngle
and LiveCharts.TangentAngle
to build labels rotation.
This is the result when we set all the series to LiveCharts.CotangentAngle
:
And this is the result when we set all the series to LiveCharts.TangentAngle
:
Finally you can also combine tangent and cotangent angles with decimal degrees:
Series { get; set; } = new List<ISeries>
{
new PieSeries<double>
{
DataLabelsRotation = 30, // in degrees
},
new PieSeries<double>
{
DataLabelsRotation = LiveCharts.TangentAngle + 30, // the tangent + 30 degrees
},
new PieSeries<double>
{
DataLabelsRotation = LiveCharts.CotangentAngle + 30, // the cotangent + 30 degrees
}
};
Stroke property
If the stroke property is not set, then LiveCharts will create it based on the series position in your series collection and the current theme.
using LiveChartsCore;
using LiveChartsCore.SkiaSharpView;
using LiveChartsCore.SkiaSharpView.Painting;
using SkiaSharp;
using System.Collections.Generic;
namespace ViewModelsSamples.Pies.Basic
{
public class ViewModel
{
public IEnumerable<ISeries> Series { get; set; } = new List<ISeries>
{
new PieSeries<double>
{
Values = new List<double> { 4 },
Pushout = 8,
Stroke = new SolidColorPaint(SKColors.Red) { StrokeThickness = 3 } // mark
},
new PieSeries<double> { Values = new List<double> { 2 } },
new PieSeries<double> { Values = new List<double> { 1 } },
new PieSeries<double> { Values = new List<double> { 4 } },
new PieSeries<double> { Values = new List<double> { 3 } }
};
}
}
<lvc:PieChart Series="{Binding Series}"></lvc:PieChart>
Paints can create gradients, dashed lines and more, if you need help using the Paint
instances take
a look at the Paints article.
Fill property
If the fill property is not set, then LiveCharts will create it based on the series position in your series collection and the current theme.
using LiveChartsCore;
using LiveChartsCore.SkiaSharpView;
using LiveChartsCore.SkiaSharpView.Painting;
using SkiaSharp;
using System.Collections.Generic;
namespace ViewModelsSamples.Pies.Basic
{
public class ViewModel
{
public IEnumerable<ISeries> Series { get; set; } = new List<ISeries>
{
new PieSeries<double>
{
Values = new List<double> { 4 },
Pushout = 8,
Fill = new SolidColorPaint(SKColors.Yellow) // mark
},
new PieSeries<double> { Values = new List<double> { 2 } },
new PieSeries<double> { Values = new List<double> { 1 } },
new PieSeries<double> { Values = new List<double> { 4 } },
new PieSeries<double> { Values = new List<double> { 3 } }
};
}
}
<lvc:PieChart Series="{Binding Series}"></lvc:PieChart>
Paints can create gradients, dashed lines and more, if you need help using the Paint
instances take
a look at the Paints article.
Pushout property
It is the distance in pixels between the center of the control and the pie slice, notice the
HoverPushout
property defines the push-out when the pointer is above the pie slice shape.
var pieSeries = new PieSeries<int>
{
Values = new [] { ... },
Pushout = 40 // mark
};
InnerRadius property
The inner radius of the slice in pixels.
var pieSeries = new PieSeries<int>
{
Values = new [] { ... },
InnerRadius = 50 // mark
};
MaxOuterRadius property
Specifies the max radius (in percentage) the slice can take, the value goes from 0 to 1, where 1 is the full available radius and 0 is none, default is 1.
var pieSeries = new PieSeries<int>
{
Values = new [] { ... },
MaxOuterRadius = 0.8 // mark
};
Plotting custom types
You can teach LiveCharts to plot any type as soon as you let the library how to handle that object, there are
two ways of doing so: Mappers or implementing IChartEntity
, mappers are quick to setup, implementing
IChartEntity
is more performant and is the recommended way.
Mappers
public record TempSample(int Time, double Temperature, string Unit);
var chart = new SKCartesianChart
{
Width = 900,
Height = 600,
Series = new[]
{
new PieSeries<TempSample>
{
Mapping = (sample, chartPoint) =>
{
// use temperature as primary value (normally Y)
chartPoint.PrimaryValue = sample.Temperature;
// use time as secondary value (normally X)
chartPoint.SecondaryValue = sample.Time;
},
Values = samples
}
},
XAxes = new[] { new Axis { Labeler = value => $"{value} seconds" } },
YAxes = new[] { new Axis { Labeler = value => $"{value} °C" } }
};
// -------------------------------------------------------------------
// IMPORTANT NOTE
// -------------------------------------------------------------------
// There are 2 special plots that use more than X and Y coordinates.
// Weighted plots: HeatMaps and Bubble charts use 3 coordinates, X, Y and Weight.
// Mapping = (sample, chartPoint) =>
// {
// chartPoint.PrimaryValue = sample.X;
// chartPoint.SecondaryValue = sample.Y;
// chartPoint.TertiaryValue = sample.Weigth;
// }
// While financial Points use 5.
// Coordinate = new Coordinate(High, X, Open, Close, Low);
// Mapping = (sample, chartPoint) =>
// {
// chartPoint.PrimaryValue = sample.High;
// chartPoint.SecondaryValue = sample.X;
// chartPoint.TertiaryValue = sample.Open;
// chartPoint.QuaternaryValue = sample.Close;
// chartPoint.QuinaryValue = sample.Low;
//}
Implementing IChartEntity
var chart = new SKCartesianChart
{
Width = 900,
Height = 600,
Series = new[]
{
new LineSeries<TempSample>
{
Values = samples
}
},
XAxes = new[] { new Axis { Labeler = value => $"{value} seconds" } },
YAxes = new[] { new Axis { Labeler = value => $"{value} °C" } }
};
// this object uses the CommunityToolkit.Mvvm to implement INotifyPropertyChanged also
public partial class TempSample : ObservableObject, IChartEntity
{
[ObservableProperty]
private int _time;
[ObservableProperty]
private double _temperature;
// Use the coordinate property to let LiveCharts know the position of the point.
public Coordinate Coordinate { get; protected set; }
// The meta data property is used by LiveCharts to store info about the plot.
public ChartEntityMetaData? MetaData { get; set; }
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
Coordinate = new(Time, Temperature);
base.OnPropertyChanged(e);
}
}
// -------------------------------------------------------------------
// IMPORTANT NOTE
// -------------------------------------------------------------------
// There are 2 special plots that use more than X and Y coordinates.
// Weited plots: HeatMaps and Bubble charts use 3 coordinates, X, Y and Weight.
// Coordinate = new Coordinate(X, Y, Weight);
// https://github.com/beto-rodriguez/LiveCharts2/blob/master/src/LiveChartsCore/Defaults/WeightedPoint.cs
// While financial Points use 5.
// Coordinate = new Coordinate(High, X, Open, Close, Low);
// https://github.com/beto-rodriguez/LiveCharts2/blob/master/src/LiveChartsCore/Defaults/FinancialPoint.cs
See the full custom types article
Custom geometries
You can use any geometry to represent a point in a series.
Series = new List<ISeries>
{
// use the second argument type to specify the geometry to draw for every point
// there are already many predefined geometries in the
// LiveChartsCore.SkiaSharpView.Drawing.Geometries namespace
new PieSeries<double, RectangleGeometry>
{
Values = new double[] { 3, 3, -3, -2, -4, -3, -1 }
},
// you can also define your own SVG geometry
// MyGeometry class let us change the Path at runtime
// Click on the on any point to change the path.
// You can find the MyGeometry.cs file below
new PieSeries<double, MyGeometry>
{
Values = new double[] { -2, 2, 1, 3, -1, 4, 3 }
}
// Note: Depending on the series type, the geometry could require to satisfy some constrains
};
public class MyGeometry : LiveChartsCore.SkiaSharpView.Drawing.Geometries.SVGPathGeometry
{
public MyGeometry()
: base(SVGPoints.Star)
{
// the LiveChartsCore.SkiaSharpView.SVGPoints contains many predefined SVG paths
// you can also pass your own path there.
}
}
ZIndex property
Indicates an order in the Z axis, this order controls which series is above or behind.
IsVisible property
Indicates if the series is visible in the user interface.
DataPadding
The data padding is the minimum distance from the edges of the series to the axis limits, it is of type System.Drawing.PointF
both coordinates (X and Y) goes from 0 to 1, where 0 is nothing and 1 is the axis tick an axis tick is the separation between
every label or separator (even if they are not visible).
If this property is not set, the library will set it according to the series type, take a look at the following samples:
new LineSeries<double>
{
DataPadding = new System.Drawing.PointF(0, 0),
Values = new ObservableCollection { 2, 1, 3, 5, 3, 4, 6 },
GeometryStroke = null,
GeometryFill = null,
Fill = null
}
Produces the following result:
But you can remove the padding only from an axis, for example:
new LineSeries<double>
{
DataPadding = new System.Drawing.PointF(0.5f, 0),
Values = new ObservableCollection<double> { 2, 1, 3, 5, 3, 4, 6 },
GeometryStroke = null,
GeometryFill = null,
Fill = null
}
Or you can increase the distance:
new LineSeries<double>
{
DataPadding = new System.Drawing.PointF(2, 2),
Values = new ObservableCollection<double> { 2, 1, 3, 5, 3, 4, 6 },
GeometryStroke = null,
GeometryFill = null,
Fill = null
}