Exploring iOS Charting Libraries

Recently, Bemo started a new project that requires the use of graphs to display data. Data visualisation, particularly graphs that have some form of interaction, are becoming an important part of many applications. But how do we decide on a library which provides the best solution for our project? 

After some research, we decided on two libraries to explore in more detail -  CorePlot and charts. Both libraries offered the graph types we needed for development, so the deciding factor would be down to development in practice. Below is a breakdown of our findings, including a general overview of both libraries and a sample implementation of each, making it easier for you and your team to choose the best fit for your next visualisation based application.


CorePlot

Platform: iOS, Mac OS X, tvOS

Language: Objective C

Price: Free

License: BSD license.

Graph Types: Pie, Bar and Line Charts

One of the main attractions to CorePlot is that it is consistently maintained, despite the fact that it was created in 2009. It is a 2D Plotting library with no external dependencies, relying only on standard Apple frameworks like Quartz and Core Animation. The documentation is extensive, with a set of API documentation built with Doxygen, a wiki and clear descriptions of most of the methods and classes.


Implementation

Our project requires line charts, and so we will focus on this for this implementation example.

First, we create a CPTGraphHostingView which hosts the graphs. This view acts as a container for all the components that make up a graph (Axis, plots, legend, annotations, etc).

anatomy-graph.png

Then, we create components and add them to it. We can create and add a CPTScatterPlot and set the datasource to self.

- (void)configureChart
        {
            CPTGraph *graph = self.hostView.hostedGraph;
    
            CPTScatterPlot *plot = [[CPTScatterPlot alloc] 
            plot.dataSource = self;
            [graph addPlot: plot];
        }

To provide data for a CorePlot chart, the datasource CPTPlotDataSource is implemented, allowing you get user interaction events with delegates. It is similar to how a UITableView works.

 #pragma mark - CPTPlotDataSource
    
    - (NSUInteger)numberOfRecordsForPlot:(nonnull CPTPlot *)plot
    {
        return numberOfRecords;
    }
    
    - (nullable id)numberForPlot:(nonnull CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
    {
        return numberForRecordAndPlotIdentifier;
    }

Because are we already familiar with the use of protocols to manage interactions and data like a UITableView does, this makes it simple to implement. The fact that the library allows for the management of each component of the graph as a unique object makes the code scalable and readable.

 

charts

Platform: iOS, macOS, tvOS and Android

Language: Swift (Can be used with Objective-c)

Price: Free

License:Apache 2.0 license.

Graph Types: Pie, Bar, Line, Scatter, Candle Stick, Bubble and Radar Charts along with the possibility to combine different charts.

Charts uses Realm to store data, but because our project didn't require this feature, it essentially acted as a standalone library for our needs. The documentation is not as extensive as CorePlot, with a wiki for the Android Library that they claim is 95% equivalent to iOS. The code is well documented, which was easier to use than the wiki.


Implementation

Again, we will look at a line graph for the example implementation.

Creating a line chart is pretty simple - a call to LineChartView does the trick, as it already has all the components of the chart. To provide values, a set of data (LineChartDataSet) is created which has a list of ChartDataEntry with the X and Y values. The appearance can then be altered to suit the project's needs.

    NSMutableArray *values = [[NSMutableArray alloc] init];
    
    for (int i = 0; i < risks.count; i++)
    {
        Risk *risk = risks[i];
        [values addObject:[[ChartDataEntry alloc] initWithX:i y:risk.risk]];
    }
    
    LineChartDataSet *set1 = [[LineChartDataSet alloc] initWithValues:yRisk label:@"At Risk"];
    
    LineChartData *data = [[LineChartData alloc] initWithDataSets:@[set1]];
    self.chartView.data = data;

A delegate (ChartViewDelegate) can also be used to manage all interactions with the graph. The best part about this library is that so many of the features are already implemented - a few small tweaks of the existing code means it is ready to use for your specific needs.

Some of the more impressive features are:

  • Scaling on both axes (with touch-gesture, axes separately or pinch-zoom)
  • Dragging / Panning (with touch-gesture)
  • Combined-Charts (line-, bar-, scatter-, candle-stick-, bubble-)
  • Dual (separate) Axes
  • Customisable Axes (both x- and y-axis)
  • Highlighting values (with customisable popup-views)
  • Save chart to camera-roll / export to PNG/JPEG
  • Legends (generated automatically, customisable)
  • Animations (build up animations, on both x- and y-axis)
  • Limit lines (providing additional information, maximums, ...)

Conclusion

Both libraries are great, fully customisable, and really well maintained and documented. Either of them could be a perfect choice, depending on the projects specifications.

CorePlot

Pros

  • Scalable
  • Offers componentisation
  • Implementation is familiar

Cons

  • Gets tricky when the brief extends beyond basic chart types.

charts

Pros

  • Wide variety of graph types
  • Easily customisable 
  • Simple to install

Cons

  • Support documentation not as extensive as CorePlot

 

In the end, we decided on charts for our project. It offered the level of customisation and variety that we needed for our specific project, while also delivering a great interactive experience for the user.

Have you used any charting libraries in your development projects that you would recommend?