In order for TKChart
to represents data, we should supply this data to it. Following the Model-View-Controller design pattern, the data source mediates between the application's data model (that is, its model objects) and the chart view. The data source provides the chart-view object with the information it needs to construct visualization using different chart types.
TKChart
can be bound to a wide variety of data sources. The common way to work with chart-view' data source is to subclass the UIViewController
and adopt the TKChartDataSource
protocol or subclass the built-in TKChartViewController
to manage the data source. Another way is to automate this task using the binding mechanism of TKChart
to setup the data source.
Following this approach, we supply TKChart
with data using a delegate. This works the same way as with UITableView
. You should implement the TKChartDataSource
protocol and specify the number of series, the number of points in each series, the series objects and the point objects. The TKChartDataSource
has two required methods. The numberOfSeriesForChart:
method tells the chart view how many series to display in the plot area, and the seriesForChart:atIndex:
method provides the series to display. Optional methods allow the data source to configure data points for each series.
Here is a sample subclass of TKChartViewController
which will provide TKChart with data points for one TKChartLineSeries
:
- (void)viewDidLoad
{
[super viewDidLoad];
chart = [[TKChart alloc] initWithFrame:self.view.bounds];
[self.view addSubview:chart];
chart.dataSource = self;
}
- (NSUInteger)numberOfSeriesForChart:(TKChart *)chart
{
return 1;
}
- (TKChartSeries *)seriesForChart:(TKChart *)c atIndex:(NSUInteger)index
{
TKChartLineSeries *series = [chart dequeueReusableSeriesWithIdentifier:@"series1"];
if (!series) {
series = [[TKChartLineSeries alloc] initWithItems:nil reuseIdentifier:@"series1"];
series.title = @"Delegate series";
}
return series;
}
- (NSUInteger)chart:(TKChart *)chart numberOfDataPointsForSeriesAtIndex:(NSUInteger)seriesIndex
{
return 10;
}
- (id<TKChartData>)chart:(TKChart *)chart dataPointAtIndex:(NSUInteger)dataIndex forSeriesAtIndex:(NSUInteger)seriesIndex
{
TKChartDataPoint *point = [[TKChartDataPoint alloc] initWithX:@(dataIndex) Y:@(arc4random() % 100)];
return point;
}
override func viewDidLoad() {
super.viewDidLoad()
let chart = TKChart(frame: self.view.bounds.insetBy(dx: 10, dy: 10))
self.view.addSubview(chart)
chart.dataSource = self
chart.autoresizingMask = UIViewAutoresizing(rawValue: UIViewAutoresizing.flexibleWidth.rawValue | UIViewAutoresizing.flexibleHeight.rawValue)
}
func series(for chart: TKChart, at index: UInt) -> TKChartSeries {
var series = chart.dequeueReusableSeries(withIdentifier: "series1") as? TKChartSeries
if series == nil {
series = TKChartLineSeries(items: nil, reuseIdentifier: "series1")
series!.title = "Series title"
}
return series!
}
func numberOfSeries(for chart: TKChart) -> UInt {
return 1
}
func chart(_ chart: TKChart, numberOfDataPointsForSeriesAt seriesIndex: UInt) -> UInt {
return 10
}
func chart(_ chart: TKChart, dataPointAt dataIndex: UInt, forSeriesAt seriesIndex: UInt) -> TKChartData {
let point = TKChartDataPoint(x: dataIndex, y: Int(arc4random_uniform(100)))
return point
}
public class ChartDocsPopulatingWithData : UIViewController
{
public ChartDocsPopulatingWithData ()
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
var chart = new TKChart (CGRect.Inflate (this.View.Bounds, -10, -10));
this.View.AddSubview (chart);
chart.DataSource = new ChartDataSource ();
chart.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
}
class ChartDataSource: TKChartDataSource
{
Random r = new Random();
public override nuint NumberOfSeries (TKChart chart)
{
return 1;
}
public override nuint PointsInSeries (TKChart chart, nuint seriesIndex)
{
return 10;
}
public override TKChartSeries GetSeries (TKChart chart, nuint index)
{
var series = chart.DequeueReusableSeriesWithIdentifier ("series1") as TKChartSeries;
if (series == null) {
series = new TKChartLineSeries (null, "series1");
series.Title = "Series title";
}
return series;
}
public override ITKChartData GetPoint (TKChart chart, nuint dataIndex, nuint seriesIndex)
{
var point = new TKChartDataPoint (new NSNumber (dataIndex), new NSNumber(r.Next (100)));
return point;
}
}
Another way to configure TKChart
data source is to set up data points for the TKChartSeries
object, and using the binding mechanism, the TKChart
control will automatically create and set up the built-in TKChartBindDingataSource
for you.
Here is a TKChartColumnSeries
with an attached collection of data points:
chart.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
NSArray *categories = @[ @"Greetings", @"Perfecto", @"NearBy", @"Family Store", @"Fresh & Green" ];
NSArray *values = @[ @70, @75, @58, @59, @88 ];
NSMutableArray *dataPoints = [[NSMutableArray alloc] init];
for (int i = 0; i < categories.count; i++) {
TKChartDataPoint *dataPoint = [[TKChartDataPoint alloc] initWithX:categories[i] Y:values[i]];
[dataPoints addObject:dataPoint];
}
TKChartColumnSeries *series = [[TKChartColumnSeries alloc] initWithItems:dataPoints];
[chart addSeries:series];
let chart = TKChart(frame: self.view.bounds.insetBy(dx: 10, dy: 10))
self.view.addSubview(chart)
let categories = ["Greetings", "Perfecto", "NearBy", "Family Store", "Fresh & Green" ];
let values = [70, 75, 58, 59, 88]
var dataPoints = [TKChartDataPoint]()
for i in 0 ..< categories.count {
dataPoints.append(TKChartDataPoint(x: categories[i], y: values[i]))
}
let series = TKChartColumnSeries(items: dataPoints)
chart.addSeries(series)
var chart = new TKChart (CGRect.Inflate (this.View.Bounds, -10, -10));
this.View.AddSubview (chart);
chart.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
var categories = new [] { "Greetings", "Perfecto", "NearBy", "Family Store", "Fresh & Green" };
var values = new [] { 70, 75, 58, 59, 88 };
var dataPoints = new List<TKChartDataPoint> ();
for (int i = 0; i < categories.Length; ++i) {
dataPoints.Add (new TKChartDataPoint (new NSString (categories [i]), new NSNumber (values [i])));
}
chart.AddSeries (new TKChartColumnSeries (dataPoints.ToArray ()));
In order to support full binding mechanism and minimize the amount of code used to initialize data source with model object of your application, TKChart
supports binding to properties of the model object. To use this powerful mechanism, you should describe in pairs the names of TKChartData
properties related to the property names of your custom object.
Binding to an array of custom object is quite easy with TKChart. Once your array is created, you just need to set the necessary members to the desired field. In the code snippet below we create one application specific custom object and bind its data to three line series:
chart.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
NSMutableArray *dataPoints = [[NSMutableArray alloc] init];
for (int i = 0; i<=5; i++) {
ModelObject *object = [[ModelObject alloc] initWithObjectID:i value1:arc4random() % 100 value2:arc4random() % 100 value3:arc4random() % 100];
[dataPoints addObject:object];
}
[chart beginUpdates];
[chart addSeries:[[TKChartLineSeries alloc] initWithItems:dataPoints forKeys:@{ @"dataXValue": @"objectID", @"dataYValue": @"value1"}]];
[chart addSeries:[[TKChartAreaSeries alloc] initWithItems:dataPoints forKeys:@{ @"dataXValue": @"objectID", @"dataYValue": @"value2"}]];
[chart addSeries:[[TKChartScatterSeries alloc] initWithItems:dataPoints forKeys:@{ @"dataXValue": @"objectID", @"dataYValue": @"value3"}]];
[chart endUpdates];
let chart = TKChart(frame: self.view.bounds.insetBy(dx: 10, dy: 10))
self.view.addSubview(chart)
var dataPoints = [ModelObject]()
for i in 0...5 {
let object = ModelObject(objectID: i, value1: Int(arc4random_uniform(100)), value2: Int(arc4random_uniform(100)), value3: Int(arc4random_uniform(100)))
dataPoints.append(object)
}
chart.beginUpdates()
chart.addSeries(TKChartLineSeries(items: dataPoints, forKeys: ["dataXValue": "objectID", "dataYValue": "value1"]))
chart.addSeries(TKChartAreaSeries(items: dataPoints, forKeys: ["dataXValue": "objectID", "dataYValue": "value2"]))
chart.addSeries(TKChartScatterSeries(items: dataPoints, forKeys: ["dataXValue": "objectID", "dataYValue": "value3"]))
chart.endUpdates()
var chart = new TKChart (CGRect.Inflate (this.View.Bounds, -10, -10));
this.View.AddSubview (chart);
chart.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
Random r = new Random ();
var dataPoints = new List<CustomObject> ();
for (int i=0; i<5; i++) {
CustomObject obj = new CustomObject () {
ObjectID = i,
Value1 = r.Next (100),
Value2 = r.Next (100),
Value3 = r.Next (100)
};
dataPoints.Add (obj);
}
chart.BeginUpdates ();
chart.AddSeries(new TKChartLineSeries(dataPoints.ToArray(), "ObjectID", "Value1"));
chart.AddSeries(new TKChartAreaSeries(dataPoints.ToArray(), "ObjectID", "Value2"));
chart.AddSeries(new TKChartScatterSeries(dataPoints.ToArray(), "ObjectID", "Value3"));
chart.EndUpdates();
@warning TKChart by default creates and sets up axes automatically to support this flexible and codeless binding behavior using the data types in the provided data source. You can always change or replace the axis type for TKChartSeries or change it auto-calculated default range.