Mappers
You can plot anything in a chart as soon as you let the library how to handle that object, LiveCharts already supports
the types short
, int
, long
, float
, double
, decimal
, their nullable versions short?
, int?
, long?
, float?
,
double?
, decimal?
, and finally some common objects defined by the library WeightedPoint
(to make bubble charts),
ObservableValue
, ObservableValueF
(float), ObservablePoint
(use full to specify both, X and Y), and ObservablePointF
.
A mapper is a function that maps an element in the Series.Values
collection to a point in a chart, this function will run
for every item in the Series.Values
collection, and will let the library where and how to place that object in a chart. The
mapper function takes the an item from or values collection and the point in the chart as arguments, you must populate the
point PrimaryValue
(normally the Y coordinate), SecondaryValue
(normally the X coordinate) and TertiaryValue
(normally
the weight in a weighted series) properties.
Lets take the following City
class as an example:
public class City
{
public string Name { get; set; }
public double Population { get; set; }
public double Density { get; set; }
}
Having an array of the City
class:
var cities = new City[]
{
new City { Name = "Tokio", Population = 10, Density = 5 },
new City { Name = "Cape Town", Population = 9, Density = 6 },
new City { Name = "New York", Population = 8, Density = 7 }
}
Finally to see our cities array in a chart we would:
myChartControlSeries = new ObservableCollection<ISeries>
{
new LineSeries<City> { Values = cities }
}
If we run our application now, the previous code will throw an exception because LiveCharts currently does not know how to display
the City
class in a chart, thus we need to register a mapper for our City
class.
Global mappers
The following code registers the City
class globally, this means that every time the City
class is used in a chart all over
our application, the library will use the mapper we indicated.
// this code must be placed where your application or view starts
LiveCharts.Configure(config =>
config
.HasMap<City>((city, point) =>
{
// use the city Population property as the primary value
point.PrimaryValue = (float)city.Population;
// and the index of the city in our cities array as the secondary value
point.SecondaryValue = point.Context.Index;
}));
Run the application again and the exception is gone, LiveCharts now knows that when it founds a City
instance it must use the
Population
property and the index of the instance in our collection, but if we required to plot the Density
property, then
we would build a mapper like the following:
// this code must be placed where your application or view starts
LiveCharts.Configure(config =>
config
.HasMap<City>((city, point) =>
{
point.PrimaryValue = (float)city.Density;
point.SecondaryValue = point.Context.Index;
}));
Global mappers are unique for a type, this means that now our previous mapper will be ignored, and from now on LiveCharts will use
the Density
property every time it founds a City
instance.
Global mappers should ideally register only once when your application starts.
Local mappers
Imagine the case were we require a chart that displays the Density
and a chart that display the Population
property, in this
case global mappers are not enough because global mappers are unique for a type, thus we will use the Series.Mapping
property to
override the global configuration for a specific series:
myChartControlSeries = new ObservableCollection<ISeries>
{
new LineSeries<City>
{
Values = cities,
Mapping = (city, point) =>
{
// use the Population property in this series
point.PrimaryValue = (float)city.Population;
point.SecondaryValue = point.Context.Index;
}
},
new LineSeries<City>
{
Values = cities,
Mapping = (city, point) =>
{
// but for this series use the Density
point.PrimaryValue = (float)city.Density;
point.SecondaryValue = point.Context.Index;
}
}
}
Now even we are on the same chart and we are using the same cities
instance, every series is drawing a different property in
the user interface.
The Series.Mapping
property is null
by default which means that it will try to pull a mapper from the global settings, if
Series.Mapping
is null
and the type is not registered globally, the library will throw an exception.
Point Context
Notice we used the point.Context.Index
property to grab the index of the city in our array, LiveCharts exposes many
properties in a ChartPointContext
instance, in the case of a mapper you normally only need the Index
but this property lets
you know more about a specific point, such as the series or the chart that contains the point.
Orientation
It is also important to mention that LiveCharts supports vertical and horizontal series, the ChartPoint.PrimaryValue
is not
always the Y coordinate (in a Cartesian coordinate system), commonly you could see the PrimaryValue
as the Y coordinate, but
for example in the case of a RowSeries
where its orientated horizontally, the PrimaryValue
property is the X coordinate,
As a general rule, for vertical orientated series PrimaryValue
is the Y
coordinate and SecondaryValue
is the X
coordinate, for horizontal orientated series PrimaryValue
is the X
coordinate and SecondaryValue
is the Y
coordinate, TertiaryValue
is normally only used in a weighted chart, such as a bubble series, where every point has a
different diameter.
You really do not need to do anything special to handle orientation, this is just a reminder to let you know how the library
works, the following example will work for both, ColumnSeries
and RowSeries
.
myChartControlSeries = new ObservableCollection<ISeries>
{
new ColumnSeries<City> { Values = cities },
new RowSeries<City> { Values = cities }
}
// the following code must be placed where your application or view starts
LiveCharts.Configure(config =>
config
.HasMap<City>((city, point) =>
{
point.PrimaryValue = (float)city.Population;
point.SecondaryValue = point.Context.Index;
}));