We have been working on multiple projects that required drawing 2D line graphs given a set of points. UIKit gives us the versatile
UIBezierPath, which allows us to create a straight line graph by appending segments using
addLineToPath for each point in our array. Easy, but not really pretty.
There are two different kinds of curves in
UIBezierPath: quadratic curves with a single control point (
addQuadCurveToPoint) and cubic curves with two control points (
addCurveToPoint). Calculating the control points is up to you and unfortunately
UIKit does not come with any ready-to-use implementations of interpolating curves.
However, while great for arbitrary points, both have issues when being used for 2D graphs. Looking at the following screenshots you can see that they extend the curve above the actual maximum and below the minimum y-values. Additionally, even though the three values in the middle section are equal, the graph indicates otherwise.
In our use-case, the above solutions were not acceptable as they may lead to wrong conclusions drawn by the user. To achieve our required results (= a smooth graph that respects global and local maxima and minima and passes through each point), we used quadratic curves. In order for the curve to go through every point, we have to divide each segment into two curves and calculate the control point for each part.
Less than 40 lines of code later, we have a nice extension of
UIBezierPath with exactly the desired results:
We draw the
CoreGraphics and overriding
draw(rect:) of our UIView subclass, but you could also use a
CAShapeLayer and even animate the drawing of the path.
This implementation is part of our
SimpleCharts framework, which we hope to open source in the near future.