All posts
iOS

Beautiful charts in Swift

Piotr Sochalewski

Piotr Sochalewski

Charts are a lovely way to present complicated data sets. Everything seems to be easier when you present it in on a chart. One picture is worth of thousand words and the same can be said about charts.

Unfortunately charts libraries are often not-so-easy or (and that’s the worst) after multiple hours spent with it you see that’s something is impossible with that one. Probably one of the most popular is CorePlot. For me that was an overkill. I believe you can make beautiful chart with it, but it takes hours or even days. On the other hand, iOS-Charts gives beautiful charts without spending whole week on it. Out of the box your charts seem to be cool. In addition it has so many properties letting you configure a chart the way you want – it’s really powerful. Also it’s written in modern Swift.

Furthermore it can be considered as a port of great MPAndroidChart, meaning that you can easily achieve the same effect on Android OS too. That makes iOS-Charts the best choice.

Before you take iOS-Charts for a spin, let’s see how to use it. In fact iOS-Charts has only one big disadvantage – it’s not well documented. But thanks to the fact it’s really similar to Android library, MPAndroidChart Wiki is really helpful.

First, create a new iOS project. Remember to not name the project ‘Charts’, because that would make conflict with module names. I named my ‘ChartsDemo’. Choose Swift as programming language and add pod 'Charts' to your Podfile.

Two things. First, if you don’t know much about CocoaPods or even about creating projects, you can find more info in one of our previous tutorials, like this one. Second, you may think it’s weird that pod named Charts is connected with library named iOS-Charts. As far as I know with the next release of the library it’s going to be changed and repository’s name would be the same as pod’s name. Woohoo!

Your Podfile should look like the one below.

Okay, you’ve got empty project with installed pod. Let’s start then.

Charts lets you make line, bar, pie, scatter, bubble and radar charts. Everything you want. But before we start, we need some data that can be presented on a chart. If you don’t have any, I’ve prepared data generator that I use in this tutorial.

This code is self-explanatory. Class func data gives sample i.e. sales data with profit for each month. That’s a perfect fit for bar or line chart, so let’s do those!

Open storyboard and add in the first view controller new UIView. In Identity Inspector change its class to BarChartView (class names are really simple and if you want a line chart then a proper class is named just LineChartView), and then pin the view with margin equals zero to all edges of the superview.

Zrzut ekranu 2016-03-22 o 14.04.57

We need an outlet to this new view, so make one ctrl-dragging this to ViewController.swift. I named mine just barChart. Your Xcode should notice really fast that BarChartView class is a one big mystery for it. Just add import Charts at the top of your file. You view controller’s class can look like this:

Now we should give the chart some data to present. I do all the steps in viewDidLoad like so:

It should work now. In my case after running the app it looked like this:

Simulator Screen Shot 22.03.2016, 15.12.53

Not bad for first attempt, but a little boring. Let’s polish it right now.

There’re multiple things that we can easily fix. First, we don’t need ‘Description’ in the right bottom corner. To remove it we need just this:

Unfortunately although Charts is written in Swift, it doesn’t use all available semantic. descriptionText is not an optional, so it can’t be niled. But an empty string does the job.

Second, there is no legend and/or values with month’s names. How would I know that these 12 bars are representing one year instead of twelve years or days? We have to add some labels. It’s simple and requires exactly one line of code:

But if you run the app right now you can notice that only every second label is shown. That’s because Charts have an algorithm that detect how many labels can be shown to make them readable. Take a shot and show every single legend element this way:

Next thing, we precisely know min and max values that can be received from DataGenerator. Why not add them to the setup to make the chart scaling more accurate?

The bars are definitely not happy or even colorful. Why not paint them with some bright colors?

Probably you have noticed that single chart can present multiple chart data sets (that’s exactly why I showed you BarChartData initializer with dataSets instead of also available dataSet parameter). That’s why we can color each data set separately. We can give an array of colors or use one of predefined colors from ChartColorTemplates enum.

As I said we’ve got only one chart data set, so there is no need for the legend at the bottom. Again it’s just one line of code:

Out of the box, iOS-Charts lets you pinch-to-zoom on a graph. If you want to disable it, then of course it’s possible. It can be enabled separately for each axis, but the code below disables both of them including double tap to zoom.

Another nice option is choosing bars by tapping them. Then you can show some kind of balloon with value or description. We don’t need that in our case, so selection can be disabled.

It looks like right axis is unnecessary here. The chart is really simple and there is no need to duplicate the left one. Also we don’t need vertical grid lines. Let’s hide them right now.

Last, but not least. What about a nice animation making first impression even better? Animations often are a pain in the neck. But not with Charts! Add this line just after setting bar chart’s data.

That’s all. Not so hard, huh? Take a look at the final effect we achieved here.

light.mov

Of course that’s not everything that Charts lets you do. Check this library out with it’s numerous charts types and take a look at hundreds of properties that let you customize charts that you create.

Thank you for reading. Have a happy Easter and feel free to comment!

Newsletter

The post is created by Droids On Roids Team Member.
We would love to take care of your business.

Leave comment

  • Thanx! The nice tutorial, I’m a new on Swift development, it helps me

  • Tony M

    Thanks for your tutorial. I tried it using Xcode Version 8.1 (8B62) and got the following compiler errors. Any suggestions?
    https://uploads.disquscdn.com/images/3025cf1e0b588191572291d92fe715e663d65ae6b889d4bc5906dbdcc274d1f2.png

    • Hi Tony. The syntax has changed when Charts started using Swift 3.0. Now it looks like this:
      ChartDataEntry(x:y:)

      • Per Brondum Jakobsen

        Both API’s have changed. xVals is gone. How do you set X-labels now?

        • Gautam Tiwari

          import Foundation
          import Charts

          public class LargeValueFormatter: NSObject, IValueFormatter, IAxisValueFormatter
          {
          private static let MAX_LENGTH = 5

          /// Suffix to be appended after the values.
          ///
          var tickArray: NSArray!

          /// An appendix text to be added at the end of the formatted value.
          public var appendix: String?

          public override init()
          {

          }

          public init(tickArray: NSArray){
          self.tickArray = tickArray
          }

          public init(appendix: String?)
          {
          self.appendix = appendix
          }

          private func format(value: Double) -> String
          {
          var sig = value
          var length = 0
          let maxLength = suffix.count – 1

          while sig >= 1000.0 && length String
          {

          return self.tickArray.object(at: Int(value)) as! String

          // return months[Int(value)]
          }

          public func stringForValue(_ value: Double, entry: ChartDataEntry, dataSetIndex: Int, viewPortHandler: ViewPortHandler?) -> String
          {
          return format(value: value)
          }
          }

          let formatter = LargeValueFormatter()
          formatter.tickArray = self.graph.xAxisTickArray
          let xAxis = XAxis()
          xAxis.valueFormatter = formatter
          self.barChartView.xAxis.valueFormatter = xAxis.valueFormatter

  • TDS200

    How do you set the salesMonths labels after Swift 3.0?

  • shaikh farooq

    Can show an example of pie chart with swift 3 and charts 3.0.0

  • ghantasala nagaraja

    Hi,
    Thanks for your tutorial.
    But I am facing following problem, please help me. https://uploads.disquscdn.com/images/043a4c93f78f391cff6422c65abccba566194edc32b912392c51fc17ddea89b6.png

  • harikrista

    https://uploads.disquscdn.com/images/0129a43f8a7484cfa7f3522bc8197618657b588bb246e22b7039994d9c530454.png Hi,
    I am getting bar width only 1 pixel. How can I increase bar width ?

    • Have you figured it out?

      • harikrista

        I figured it out but now i just forgot what exactly I changed. My working code is below please go through it. It might help you.
        func styleBarChart() {

        barChartView.rightAxis.drawGridLinesEnabled = false;

        barChartView.noDataText = “No data to show at the moment.”

        barChartView.xAxis.labelRotationAngle = -70;
        barChartView.xAxis.granularity = 1

        barChartView.leftAxis.spaceBottom = 0.0;

        barChartView.chartDescription?.enabled = false

        barChartView.xAxis.gridColor = .lightGray;
        barChartView.rightAxis.gridColor = .lightGray;
        barChartView.leftAxis.gridColor = .lightGray;

        barChartView.xAxis.gridLineWidth = 0.1;
        barChartView.rightAxis.gridLineWidth = 0.1;
        barChartView.leftAxis.gridLineWidth = 0.1;

        barChartView.legend.enabled = false
        barChartView.xAxis.labelPosition = .bottom;
        }

        func updateGraph(filterNum:Int) {

        // this forces to display each value of datapoint in xAxis
        self.barChartView.xAxis.setLabelCount(self.edh.epic.graphPoints.count, force: false);
        barChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values:self.edh.epic.getXLabelValues());

        // empty values are provided. its a trick to hide those long values in rightaxis and leftaxis
        // barChartView.leftAxis.valueFormatter = IndexAxisValueFormatter(values: []);
        barChartView.rightAxis.valueFormatter = IndexAxisValueFormatter(values: []);

        let chartDataSet = BarChartDataSet(values: self.edh.epic.getDataEntries(filterNum: filterNum), label: “”)

        chartDataSet.colors = [Constants.Color.colorGraph1,Constants.Color.colorGraph2,Constants.Color.colorGraph3,Constants.Color.colorGraph4,Constants.Color.colorGraph5];

        let chartData = BarChartData(dataSet: chartDataSet)

        // bar will occupy leaving no extra space.Value provide in percentage
        // barChartView.xAxis.labelTextColor = .red;
        barChartView.xAxis.labelFont = NSUIFont.systemFont(ofSize: 11.0);
        // barChartView.xAxis.centerAxisLabelsEnabled = false;

        barChartView.data = chartData

        // this resets the animation zoom etc
        // self.barChartView.fitScreen();

        barChartView.animate(yAxisDuration: 0.75, easingOption: .easeInOutQuart)
        }