Bring Your Ionic App to Life: Getting Started with D3.js

14 December 2015Ionic, D3.js

Learn how to use D3.js with this guest post by Hunter Leaman, creator of the Rapid Prototyping with Ionic: Build a Data-Driven Mobile App course. Read on until the end for a special offer!

Over the past few years, D3.js has emerged as the web standard for data visualization and charting by enabling developers to take full advantage of everything modern browsers have to offer, which is a lot… you can take a look at their examples to see for yourself (there are nearly 100 of them!).

In this article, I’m going to demonstrate how to install, setup, and use D3.js in an Ionic application.

Let’s start by creating a new Ionic project:

$ ionic start d3Examples blank
$ cd d3Examples

With a new project all setup, we can install D3.js. We’re going to use Angular-nvD3 additionally to make our interacting with D3 a little easier. All we need to do is run:

$ bower install angular-nvd3

Then we just need to link to the dependent files in our index.html file at the end of its head section:

<script src=”lib/d3/d3.js”></script>
<script src=”lib/nvd3/build/nv.d3.min.js”></script>
<script src=”lib/angular-nvd3/dist/angular-nvd3.min.js”></script>
<link rel=”stylesheet” href=”lib/nvd3/build/nv.d3.css”>

And finally, add Angular-nvD3 as a dependency to the app:

angular.module(‘starter’, [
  ‘ionic’,
  ‘nvd3’
])

Now we’re ready to start charting. For the first example, let’s create a simple pie chart to visualize the popularity of modern SPA’s in terms of their GitHub stars. (This data is for demonstration purposes only, so I’m using some Google-searched site’s Github-sourced data points from January 2, 2014.) And with that being said, the first thing we need to do is add an element with two attributes to pass in the required options object and data array from our controller:

<ion-content>
   <nvd3 options="vm.options" data="vm.data"></nvd3>
</ion-content>

Now we can add a controller to our app.js file and define the options object and data array:

.controller(‘mainController’, [‘$scope’, mainController]);

function mainController($scope) {
  var vm = this;
  vm.options = {};
  vm.data = {};
}

With the infrastructure in place, let’s check out Angular-nvD3’s example pie chart. At the bottom of the page, you’ll find the chart options code for the example (but note it’s missing the chart’s x and y properties). We’re going to check out the actual source code by clicking the “Source” link below the example, so we can then copy and paste the example chart’s options object into our vm.options object:

vm.options = {
  chart: {
    type: ‘pieChart’,
    height: 500,
    x: function(d){return d.key;},
    y: function(d){return d.y;},
    showLabels: true,
    duration: 500,
    labelThreshold: 0.01,
    labelSunbeamLayout: true,
    legend: {
      margin: {
        top: 5,
        right: 35,
        bottom: 5,
        left: 0
      }
    }
  }
};

Now we just need to understand the pie chart’s data formatting. Let’s copy and paste the example chart’s data array content into ours:

vm.data = [
  {
    key: “One”,
    y: 5
  },
  {
    key: “Two”,
    y: 2
  },
  {
    key: “Three”,
    y: 9
  },
  {
    key: “Four”,
    y: 7
  },
  {
    key: “Five”,
    y: 4
  },
  {
    key: “Six”,
    y: 3
  },
  {
    key: “Seven”,
    y: .5
  }
];

1

In order to display our data, all we need to do is replace the example data:

vm.data = [
  {
    key: “Angular”,
    y: 18567
  },
  {
    key: “Backbone”,
    y: 16651
  },
  {
    key: “Ember”,
    y: 9023
  },
  {
    key: “Flight”,
    y: 4655
  },
  {
    key: “Knockout”,
    y: 4487
  },
  {
    key: “Marionette”,
    y: 4261
  },
  {
    key: “React”,
    y: 3691
  }
];

2

Now that we have a chart initialized with our data, we can start customizing its appearance. Angular-nvD3’s example charts all include an “extended” options view, comprising every available option for each chart, all of which you can edit right there on the page. That means it’s time to start experimenting! Let’s toggle the showLabels option to false, adjust its width to 320, toggle title on, toggle donut to true, and turn tooltips off. How easy was that? By adjusting only a few predefined properties, you can alter the appearance of your chart substantially. Now to finish this first example, let’s add those changes to our chart:

vm.options = {
  chart: {
    type: ‘pieChart’,
    height: 500,
    x: function(d){return d.key;},
    y: function(d){return d.y;},
    showLabels: false,
    duration: 500,
    labelThreshold: 0.01,
    labelSunbeamLayout: true,
    width: 320,
    title: “Sweet!”,
    donut: true,
    tooltips: false,
    legend: {
      margin: {
        top: 5,
        right: 0,
        bottom: 5,
        left: 0
      }
    }
  }
};

3

In the next example, we’re going to build on the first example’s data by including each framework’s current number of GitHub stars. We’ll visualize these new data by initializing a multibar chart to highlight each framework’s popularity growth over the past two years. Head to the Angular nvD3’s example MultiBar Horizontal Chart’s source code and copy and paste its options object into your options object (below) and note the data array’s format.

vm.options = {
  chart: {
    type: ‘multiBarHorizontalChart’,
    height: 450,
    x: function(d){return d.label;},
    y: function(d){return d.value;},
    showControls: true,
    showValues: true,
    duration: 500,
    xAxis: {
      showMaxMin: false
    },
    yAxis: {
      axisLabel: ‘GitHub Stars’,
      tickFormat: function(d) {
        return d3.format(‘,.2f’)(d);
      }
    }
  }
};

Now, let’s gather and initialize all of the necessary data. Here are each framework’s stars from Jan ’14 (stars.framework[0]) followed by their current stars (stars.framework[1]) as of December ’15:

var stars = {
  “Angular” : [18567 , 44913],
  “Backbone” : [16651 , 23633],
  “Ember” : [9023 , 15249],
  “Flight” : [4655 , 6380],
  “Knockout” : [4487 , 6990],
  “Marionette” : [4261 , 6629],
  “React” : [3691 , 32656]
};

Now we can feed that data into our data array. The first series will be “As of Jan ‘14” and the second will be “As of Dec ‘15”. ***(Note: When the bars are stacked, their values are cumulative so we need to subtract the first quantity of stars (old) from the second (current) quantity of stars.) Your *data* array should look like this:

vm.data = [
  {
    “key”: “As of Jan ‘14”,
    “color”: “#1f77b4”,
    “values”: [
       {
         “label” : “Angular” ,
         “value” : stars.Angular[0]
       },
       {
         “label” : “Backbone” ,
         “value” : stars.Backbone[0]
       },
       {
         “label” : “Ember” ,
         “value” : stars.Ember[0]
       },
       {
         “label” : “Flight” ,
         “value” : stars.Flight[0]
       },
       {
         “label” : “Knockout” ,
         “value” : stars.Knockout[0]
       },
       {
         “label” : “Marionette” ,
         “value” : stars.Marionette[0]
       },
       {
         “label” : “React” ,
         “value” : stars.React[0]
       }
    ]
  },
  {
    “key”: “As of Dec ‘15”,
    “color”: “#2b93db”,
    “values”: [
       {
         “label” : “Angular” ,
         “value” : stars.Angular[1] - stars.Angular[0]
       },
       {
         “label” : “Backbone” ,
         “value” : stars.Backbone[1] — stars.Backbone[0]
       },
       {
         “label” : “Ember” ,
         “value” : stars.Ember[1] — stars.Ember[0]
       },
       {
         “label” : “Flight” ,
         “value” : stars.Flight[1] — stars.Flight[0]
       },
       {
         “label” : “Knockout” ,
         “value” : stars.Knockout[1] — stars.Knockout[0]
       },
       {
         “label” : “Marionette” ,
         “value” : stars.Marionette[1] — stars.Marionette[0]
       },
       {
         “label” : “React” ,
         “value” : stars.React[1] — stars.React[0]
       }
    ]
  }
];

Finally, we’re going to adjust a few of the chart’s options—set the bars to display stacked by default and turn the controls off:

vm.options = {
  chart: {
    type: ‘multiBarHorizontalChart’,
    height: 450,
    x: function(d){return d.label;},
    y: function(d){return d.value;},
    showControls: false,
    showValues: true,
    duration: 500,
    stacked: true,
    xAxis: {
      showMaxMin: false
    },
    yAxis: {
      axisLabel: ‘GitHub Stars’,
      tickFormat: function(d) {
        return d3.format(‘,.2f’)(d);
      }
    }
  }
};

4

For the final example, we’re going to create a simple box plot chart to display a 3-day temperature forecast for San Francisco. (I’ll be using the Weather Underground API to get the data for this demonstration, but regardless of where you get your data, the format required by nvd3 will remain consistent).

We’ll be using a box plot chart so we can display each day’s temperature range by way of their respective highs and lows. In order to get this data, I’ve set up a constant—to hold my Weather Underground API key—and a service provider—to request data from the API:

.constant(‘API_KEY’, ‘my_API_key’)

.service(‘weatherDataService’, [‘$http’, ‘API_KEY’, weatherDataService])

function weatherDataService($http, API_KEY) {

  return {

    threeDayForecast: function() {
      var url = ‘http://api.wunderground.com/api/' + API_KEY + ‘/forecast/q/CA/San_Francisco.json’;
      return $http.get(url);
    }
  };
}

The next task is to initialize variables for every data point we’ll need in our controller:

var data = jsonData.data.forecast.simpleforecast.forecastday,
  secondDay = data[1].date.weekday_short,
  thirdDay = data[2].date.weekday_short,
  fourthDay = data[3].date.weekday_short

  lows = [
    data[0].low.fahrenheit,
    data[1].low.fahrenheit,
    data[2].low.fahrenheit,
    data[3].low.fahrenheit
  ],

  highs = [
    data[0].high.fahrenheit,
    data[1].high.fahrenheit,
    data[2].high.fahrenheit,
    data[3].high.fahrenheit
  ],

  forecastMin = Math.min.apply(null, lows),
  forecastMax = Math.max.apply(null, highs);

In the code above, we define a data variable initialized with the API’s returned JSON object property path, and then initialize the second-, third-, and fourthDay variables with their corresponding weekdays (we’ll manually enter “Today” for the current day). Then, in order to find the forecast’s min and max temperatures, we use the Math object’s min and max methods on our lows and highs arrays. Finally, we need to initialize our chart’s options object and data array:

vm.options = {
  chart: {
    type: ‘boxPlotChart’,
    height: 450,
    margin : {
      top: 5,
      right: 0,
      bottom: 20,
      left: 30
    },
    color: [‘darkorange’],
    x: function(d){return d.label;},
    maxBoxWidth: 10,
    yDomain: [forecastMin — 2, forecastMax + 2]
  },
  title : {
    enable: true,
    text: ‘San Francisco’
  }
};


vm.data = [
  {
    label: “Today”,
    values: {
      Q1: lows[0],
      Q2: ‘’,
      Q3: highs[0]
    }
  },
  {
    label: secondDay,
    values: {
      Q1: lows[1],
      Q2: ‘’,
      Q3: highs[1]
    }
  },
  {
    label: thirdDay,
    values: {
      Q1: lows[2],
      Q2: ‘’,
      Q3: highs[2]
  }
  },
  {
    label: fourthDay,
    values: {
      Q1: lows[3],
      Q2: ‘’,
      Q3: highs[3]
    }
  }
];

5

And there you have it—a simple 3-day forecast chart.

The box plot chart can also display whiskers and outliers as a typical box plot chart does by way of the following properties within each data point’s values property:

{
  label: “Today”,
  values: {
    Q1: lows[0],
    Q2: ‘’,
    Q3: highs[0],
    whisker_low: 25,
    whisker_high: 95,
    outliers: [5, 115, 125]
  }
}

That brings this article to a close. Thanks for reading this far!

As a token of my appreciation (and a desire for you to check out the Ionic framework :] ), I’m pleased to offer you a 75% off coupon for my in-depth course, which demonstrates step-by-step how to build a stock market app, featuring interactive, data-driven charts powered by D3.js, and much more. Click here to start learning Ionic now!.

WRITTEN BY
profile
Hunter Leaman

Hunter is an entrepreneur with a passion for web development, working to help other aspiring entrepreneurs realize their goals by providing guidance through his business.