Graceful Approach to Working with Core Plot

When we need to build graphs for iOS app, the first thing that comes to mind is a well-known Core Plot library that was created by an enthusiast Eric Skroch. This is a very powerful tool that allows you to build a great variety of different types of graphs on both iOS and OS X platforms. There are many tutorials and articles devoted to Core Plot library. Also, you can look for the information on Stackoverflow, where Core Plot’s creator is a frequent visitor.

Core Plot is ultimately flexible but requires you to write a lot of code to set it up. Organizing all this code and building out a proper architecture turns out to be quite difficult.

Core Plot uses DataSource pattern for setup, which is similar to UITableView. As you know, using view controller as a data source can turn it into a huge class full of tangled code, a so-called Massive view controller. If we are used to UITableView, some miscalculations in the Core Plot’s architecture can become a real nightmare.

We had to deal with Core Plot at one of our projects, a time-tracking app called SYLO Study Time and so, we decided to avoid Massive view controller by extracting the maximum amount of potentially reusable code and placing it into separate classes. Following this plan we adhere to “Light-weight view controller” pattern, according to which view controller acts as a link between model and view and doesn’t carry any business logic.

Before getting down to describing the approach we developed, let’s see what the Core Plot library is all about by looking at its classes.

Main classes of the Core Plot

Core Plot’s classes have a complex hierarchical structure. CPTGraph is a central class in the Core Plot. The term “graph” refers to the whole diagram, which includes coordinates and the name of the graph or a few plots (CPTPlot). Plot is a concrete data display in the graph. Plot and data are absolutely independent from one another.

The container for CPTGraph object is CPTGraphHostingView class. The graph, which is built with the help of Core Plot has the following structure:

Any object, that implements CPTPlotDataSource protocol can be a data source for the plot.

@protocol CPTPlotDataSource <NSObject>
// Implement one of the following
-(NSArray *)numbersForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndexRange:(NSRange)indexRange;
-(NSNumber *)numberForPlot:(CPPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index;

The fields can be viewed as identifiers of the table’s columns and the record’s index as an analogue of the table’s row index. Each plot has a fixed set of fields. For example, a scatter diagram has two fields: one for the axis Х and the other one for Y.

typedef enum _CPTScatterPlotField {
} CPTScatterPlotField;


CPTPlot is a superclass for all plots. This is an abstract class; each CPTPlot’s subclass is a certain set of diagrams. For example, there is a class CPTPiePlot for pie chart, CPTBarPlot for columnar diagram.

The object plot is closely connected to CPTPlotSpace class. In order to build the plot you need to transform the values received through dataSource to the system of coordinates.

Read more about Core Plot classes here.

There are two steps you need to take to work with Core Plot:

1. Graph design setup.
2. Implementation of the Core Plot data source methods.

Data source implementation

We made an attempt to create a fully fledged analogue of UITableView. We took the following steps:

1. Create a subclass of CPTGraphHostingView class and encapsulate inside all the logic of the graph’s look setup (the color of coordinates axises, fonts, etc.).

2. Create a protocol to make it possible for each data model to expand its interface by implementing this protocol and provide all the data needed to draw a graph (size of the columns, color of the sectors).

3. Сreate a public dataSource and transfer the output data to the internal dataSource Core Plot. The methods of the Core Plot dataSource should be implemented in the view class.

4. Create a method reloadData, which after getting and processing the data to display on the diagram, will recalculate the size of the coordinates’ axises, scale the graph and add plots to it.

Скриншот 2015-02-24 13.58.08


Let’s imagine the following data model that displays sportsman’s progress according to the days of training.


There is a value “Exercises”, which has the following fields:

1. The name of the exercise.
2. Hexadecimal color value as string. This value has a link “sets”, one of many to the value “YALSet” and includes the following fields:
- the number of repeats for each exercise.
- the date when the sportsman did this exercise.

Let’s say we have a default set of data and need to display a general progress for each of the following exercises:

- Push ups
- Pull ups
- Leg press
- Twisting

Read alsoMastering UIKit performance

Columnar diagram

Let’s say a sportsman did a good job with push ups but couldn’t do pulls up with the same vigor and gave up after a couple of attempts. In this case, the column that displays the number of pull ups will not be noticeable along with the column that displays the push up progress.

Step 1 – creating a separate view for columnar diagram.

Let’s create a class YALBarChartView and set up a diagram design there. We will allocate design setup in awakeFromNib method.

Note: This method is enough for the tutorial, you don’t need to extract anything from it.

Step 2 – Creating a protocol for transferring the data to the graph.

Each “Exercise” value will be displayed in the form of a column. So in order to draw a column, every copy of the “Exercise” value should provide the graph with progress (the total amount of repeats), which will define the size of each column (columns can be drawn both vertically and horizontally), the color, which corresponds to the exercise, and also the data for displaying the legend of the graph.

@protocol YALBarChartProtocol <NSObject>
- (UIColor *)barColor;
- (NSNumber *)barValue;
- (NSString *)barName;
- (NSString *)barLegendString;

Let’s expand the interface of the YALExercise class by implementing the methods of the protocol YALBarChartProtocol.

We implement this protocol in the extension to the model’s class. But in the real project we recommend you to use class-adapter. Why don’t we learn more about MVVM?

//color for each exercise
- (UIColor *)barColor {
return [UIColor yal_colorFromHexString:self.colorHexName];
//the size of the column for each exercise
- (NSNumber *)barValue {
return [self.sets valueForKeyPath:@"@sum.repCount"];
//data for graph’s legend
- (NSString *)barName {
- (NSString *)barLegendString {
double totalValue = 0;
for (YALSet* set in [YALSet MR_findAll]) {
totalValue += [[set valueForKeyPath:@"repCount"] floatValue];
double percentage = (100.f * [[self barValue] integerValue]) / totalValue;
NSString *legendLabelString = [NSString stringWithFormat:@"%@ %ld (%.2f%%)", [self barName],
(long)[[self barValue] integerValue], percentage];
return legendLabelString;

Step 3 – creating public dataSource for transferring external data.

//protocol for our public datasource
@protocol YALBarChartViewDataSource <NSObject>
- (NSInteger)numberOfBarsInBarChartView:(YALBarChartView *)barChartView;
- (id <YALBarChartProtocol>)barChartView:(YALBarChartView *)barChartView barAtIndex:(NSInteger)index;

The first method simply returns the number of columns in the diagram.

The second method returns the object which implements the protocol for our data model. In our case it will return the object of the class “Exercise”, which expanded its interface with our protocol. Already collected data will be used by the internal dataSource Core Plot during drawing the graph.

For example, the overall progress of each exercise will correspond to the value on X axis. We will also create a property dataSource in the public interface of the YALBarChartView class and make it IBOutlet.

Step 4 – implement the method reloadData.

Here we will calculate a maximum height of the column and scale the system of coordinates accordingly. We will also calculate a minimum visible size of the column for displaying small values and add plot or, in this case, a section of the table. In the end, we’ll reload the graph.

After all the aforementioned steps, we can implement methods of public dataSource YALBarChartView in the corresponding controller. We can create a separate object that will collect the necessary information for building a graph from the data source and will implement the methods of public dataSource YALBarChartView.

Since our class YALBarChartView implements the method (instancetype) initWithCoder, we can simply work with our view in StoryBoard. Since our dataSource is IBOutlet, we can also add the object dataSource of our view in Storyboard.


As a result we’ve built a graph without even creating a subclass of UIViewController.

iOS Simulator Screen Shot 24 дек. 2014 г., 1.15.31 после полудня 2

Read alsoLoose coupling using Dependency Injection and Service Locator

Pie chart

Working with pie charts doesn’t differ much from working with columnar diagrams. Plot (section of the table) is a circle, and sectors are “cells” in the table. Just like in the previous case we need to create a separate view, a protocol for data model and an external dataSource. The only difference is calculation of the minimum sector of the circle, because we need to know what amount of data corresponds to a single degree of the circle.

iOS Simulator Screen Shot 20 февр. 2015 г., 1.11.38 после полудня

Stacked bar chart

This diagram is the most complicated, but also the most interesting graph, in our opinion. For example, we need to show the training stats for the last 7 days. In a single column that will correspond to a particular day, there will be a few columns for each exercise done on that particular day. In other words, stacked bar chart is a stack of columns.

iOS Simulator Screen Shot 20 февр. 2015 г., 1.10.30 после полудня

We can build this graph and work with it the same way as with a table, because we basically have the same table, but with more, than one section. Each small column is a cell in the section.

In our implementation each cell in the column is not a record, but a plot with one record. We need to adapt to work with our model. The first class YALStackedBarChartObject will collect all the data to build a plot (cells in the table) for each exercise. The second class YALStackedBarChartSection will be responsible for creating a section, which corresponds to a particular day. We can locate a few plots in this section, since a sportsman can do a few different exercises.


We need to know how many plots (cells) there are in every section and provide a concrete set of data for building a plot according to the corresponding index.

Using this approach, we just supplemented the interface of the public dataSource with methods for calculating the number of sections, the number of plots (“cells”) for each section, and the height of the plot and section.

In order to create a stack of bars when implementing internal dataSource Core Plot, we use the field BarBaseValue, which means that the bar needs to be drawn with certain offset. For that we need to provide each bar, except the first one, with the total height of all the lower bars. Since we work with the graph in the same way as with the table — through sections and cells — we can set an identifier for each plot with an index. For this reason we adapted the data model by creating separate objects for collecting data by sections and cells.

As in the previous case, instead of abusing a controller, we can create a separate object, which will implement the methods of our public dataSource, and provide the needed data. Then, we’ll connect this object with dataSource of our view in Storyboard.

Read alsoFrom JSON to Core Data fast and effectively


As a result, we achieved clear and transparent architecture while keeping the main view-controller lightweight. We also encapsulated all the code, responsible for setting up graph display which resulted in achieving reusable and flexible solution, entirely corresponding to MVC pattern.

Core Plot offers extensive possibilities for manual setup, which are necessary to go through once you decide to get use of the library. Needless to say, Core Plot is time-consuming and complicated to deal with. In case you do not need all the power this library can provide, you can look for simpler ready solutions on CocoaControls or elsewhere and satisfy your needs without having to invest huge amounts of time and energy.

You can take a look at our test project here.

1.0/ 5.0
Article rating
Remember those Facebook reactions? Well, we aren't Facebook but we love reactions too. They can give us valuable insights on how to improve what we're doing. Would you tell us how you feel about this article?
See what else we can do

Check out our knowledge and capabilities

Let's talk code