Basic Chart - Pie Chart
FREE     Duration: 16:31
Part of Course: Introductory D3 Course
 

Takeaways:

  • You will use the CSV data from the D3js.org website Pie Chart example to see how a full D3 Pie Chart example data visualization is built
  • Notice that the styling is done in the <style> </style> section of the HTML document
  • Notice the D3 Margin Convention
  • Notice the D3 Ordinal Scale to be used for colors
  • Notice the D3 SVG Arc Path Generator Function and its accessor functions
  • Notice the D3 Pie Chart Layout Helper
  • Notice how the data is passed into the D3 Pie Chart Layout helper which then gets passed into the D3 Data Operator
  • Notice the D3 Data Join
  • Notice the SVG paths being appended to the SVG Group elements (and inherinting the bound data)
  • Notice the D3 SVG Arc Path Generator Function being used to set the "d" attribute of the SVG Path
  • Notice the use of the D3 SVG Arc Path Generator function centroid method being used to lable the pie chart slices

Transcript:

Basic Chart - Pie Chart


Visual Code Walk Through


[ Image: Pie Chart Example ]

We will cover the D3js.org website Pie Chart example.


What is crucial to understand about this chart is that it uses the same pattern we have been seeing for working with nested data.

We first create an array of JavaScript objects that have data inside.

This interior data consists of more JavaScript Objects with data inside of them.

In previous charts we created an array of JavaScript objects inside of each object.


In this chart we create one JavaScript Object inside of each object.

Once we have this array of objects where each object has an object inside of them, we can bind the outside objects to SVG Group Elements and we can bind the inside objects to SVG Path Elements based on the D3 Arc Generation Function and the D3 Pie Chart Layout function.


In this chart we use the D3 Pie Chart Layout Function to do the math behind the scenes for us.

[ Image: Data of Pie Chart Example ]

We will save the data from the example into a file called data.csv

This file is the one that will be loaded asynchronously using the D3.csv request functionality.


The document starts with the DocType, Meta Character Set and CSS styling.

BROWSER HIGHLIGHT First section

<!-DOCTYPE ....</style>

This is the standard HTML Doctype, meta character set definition and CSS Styling for the D3 Data Visualization we are making.


Next we go into the JavaScript Sections of the document.


First, we load the D3.js JavaScript Library from the web.

BROWSER Highlight <script src....></script>

This uses the D3 code hosted by the d3js.org website.


Next, we go into the D3 code that will create the Pie Chart.


We setup the SVG Container size and radius of the actual Pie Chart.

var width = 960,
    height = 500,
    radius = Math.min(width, height) / 2;


Next we setup an ordinal scale function for the colors that are going to be used for the different slices of data.

var color = d3.scale.ordinal()
    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

We define 7 HTML colors in the range of the function.

Note that the domain is not yet set.


Next we define the Arc Function which like the D3 Path Generator, is a D3 provided generator that helps to draw the SVG Shape.

var arc = d3.svg.arc()
    .outerRadius(radius - 10)
    .innerRadius(0);

Like the D3 Path Generator, we will pass data into this function and it will return the necessary SVG Commands to construct the SVG Shape for us.

We define the innerRadius as 0 because we are doing a pie chart - not a donut chart so the inner Radius will be zero.

We define the outer radius as the radius - 10.

Remember that radius was defined as the minimum of the width or height divided by 2.

Which means that we don't want the pie to abut the edge of the graphs.

The minus 10 means that there will be a 10 unit buffer around the Pie before it hits either the width or the height of the SVG Container.


Next we use a D3 Chart Layout Helper

var pie = d3.layout.pie()

This is the first time we are using a D3 layout helper.

The D3 layout helpers basically help do the heavy math lifting in the background, so you don't need to worry about doing the math.

The D3 Pie Chart layout helper computes the start and end angles of the arcs based on data that is passed in to the function.

So rather than you having to figure out what angles are needed and when they start and end, the D3 pie layout does all of it for you.

The deep dive into all of the layouts D3 provides is for another time.

For now, know that it is saving you from doing math.


So we define the D3 Pie Chart Layout.

var pie = d3.layout.pie()
    .sort(null)
    .value(function(d) { return d.population; });

We pass NULL to the dot sort because we do not want the data sorted for the pie chart based on the data, we want it sorted based on how comes in from the data.csv file.

The sorting the data.csv file uses is based on the age-groups going from youngest to oldest.

We also define an anonymous function that will serve as the accessor function to get the relevant population numbers out of the data we bind to the SVG Group Elements.


The next code creates the SVG Container and transform translates the inner SVG Group Element to the middle of the SVG Container.

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");


The next code is where D3 does the asynchronous call to the server to get the data and then builds the chart.

BROWSER HIGHLIGHT all d3.csv

In this case, the callback function is an anonymous function.

Note - this example uses d3.csv for comma separated values not d3.tsv for tab separated values.


Let's go through the callback function section by section.


This code iterates through the array of JavaScript objects generated by the d3.csv request.

data.forEach(function(d) {
    d.population = +d.population;
});

For each JavaScript object it does one thing: It converts the population string to a JavaScript Number and then it assigns it right back to the d.population key.


Next, this code uses the D3 pattern to bind data to SVG Group Elements with the class of "arc".

var g = svg.selectAll(".arc")
    .data(pie(data))
  .enter().append("g")
    .attr("class", "arc");

First the Array of JavaScript Objects returned from the D3.csv request are passed to the D3 Pie Layout Function.

The result of the calculation is then passed to the dot data D3 operator.

This binds data to placeholder elements.

Then we select the enter selection.

Then we merge the placeholder elements with the SVG Group Elements.

Next, each new SVG Group element is given the class of "arc".

The selection of all the SVG Group Elements just created is then assigned to the variable "g".

We explore this further in the JavaScript Console section.


Then, using the D3 pattern a second time, we bind the Data from each of the SVG Group Elements in the variable G to SVG Arcs.

g.append("path")
    .attr("d", arc)
    .style("fill", function(d) { return color(d.data.age); });

D3 implicitly uses the Data bound to the SVG Group elements as an input to the D3 Arc Generation function we named arc earlier.

The result of this function is then set as the d attribute for the path.

The style fill color is computed using the Ordinal Scale Function we defined earlier.

The color for each slice of the Pie Chart will be based on the data age group.

We explore this further in the JavaScript Console section.


Lastly, we add an SVG Text label to each slice of the Pie Chart.

g.append("text")
    .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
    .attr("dy", ".35em")
    .style("text-anchor", "middle")
    .text(function(d) { return d.data.age; });

Using the data attached to each of the SVG Group Elements in the "g" variable, we add an SVG Text Label denoting what Age Group the Pie Chart slice belongs to.

The text is transform translated using the D3 Arc Generator Function centroid functionality which defines the midpoint between the inner and outer radius and the midpoint between the starting and ending angle.

This ensures the text is in the middle of the slice.

Then the dy and text-anchor attributes are defined.

Lastly, the actual text of the label is defined using an anonymous function that extracts the age group name from the data that was bound to the SVG Group Element.


And that is the end of the callback function and the end of the d3.csv function.

});

When this is done, the graph will have been fully generated.


Let's now build this part by part in JavaScript.



JavaScript Code Build

Because in the web example the building of the chart happens inside of a callback function, we will use a more simple anonymous function in the JavaScript Console.

d3.csv("data.csv", function(error, data){...});

// =>

var callbackError, callbackData;

d3.csv("data.csv", function(error, data){
    callbackError = error;
    callbackData = data;
});


Alright, to the JavaScript Console.


CLEAR CHROME BROWSER CACHE


After downloading the data to a data.csv file, starting the Python SimpleHTTPServer and making sure D3 is loaded, we open the Chrome Developer Tools and go step by step building the visualization.


We start by defining the callbackError and callbackData variables which will be used to house the data we get back from the d3.csv function.

var callbackError, callbackData;


We setup the SVG Container size and radius of the actual Pie Chart.

var width = 960,
    height = 500,
    radius = Math.min(width, height) / 2;


Next - setup the ordinal scale function for the colors that are going to be used for the different slices of data based on the age groups.

var color = d3.scale.ordinal()
    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);


Next - define the D3 provided Arc Generator Function which helps to draw the SVG Shapes based on the data passed into it. var arc = d3.svg.arc() .outerRadius(radius - 10) .innerRadius(0);

innerRadius is zero because we are doing a pie chart - not a donut chart.

outerRadius is the radius as defined by the SVG Viewport minus 10 units to make sure it fits within the SVG Viewport.


Let's check what the arc variable is by running it through the JavaScript typeof function.

typeof(arc);

"arc" is a function.


Next - define the D3 Pie Chart Layout.

var pie = d3.layout.pie()
    .sort(null)
    .value(function(d) { return d.population; });

We pass NULL to the dot sort because we do not want the data sorted for the pie chart based on the data.

We also define the accessor function, that will be used to get the relevant population numbers out of the data we bind to the SVG Group Elements.


The next code creates the SVG Container and transform translates the inner SVG Group Element to the middle of the SVG Container.

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

BROWSER HIGHLIGHT - open the body element, the SVG element and click on the SVG Group Element.


Next is where we are going to differ a bit from the code of the example.

d3.csv("data.csv", function(error, data) {
    callbackError = error;
    callbackData  = data;
    console.log([callbackError, callbackData.length]);
});

Instead of defining an anonymous callback function that does all the generating of the chart in one go, we'll define a callback function that assigns the data and error to variables.

We'll then use the callbackError and callbackData variables to build the Pie Chart.

Inside of the callback function, we have a console log of an array of the callbackError and callbackData dot length so we can see what is in each one of them.

We can see that the callbackError is null and that the length of the callbackData array is 7 elements.


Let's look at the first element.

callbackData[0];

It is a JavaScript Object with two key,value pairs.

The first pair has the key "age" and the value of "<5" as a string.

The second pair has the key "population" and the value of "2704659" [2,704,659] as a string.


Let's look at the second element.

callbackData[1];

It is a JavaScript Object with two key,value pairs.

The first pair has the key "age" and the value of "5-13" as a string.

The second pair has the key "population" and the value of "4499890" [4,499,890] as a string.

From this you can tell that the callbackData array is made up of 7 JavaScript objects, each which has 2 key,value pairs denoting the Age Group it represents and the total population of that Age Group written out as a string of numbers.


Next - we use the Array forEach iterator to go through the array of JavaScript Objects and change the population string values to JavaScript numbers for each object.

callbackData.forEach(function(d) {
    d.population = +d.population;
});


We then check to make sure the population string was converted to a number correctly.

callbackData[0];

Yes it was, the population is now a JavaScript Number.


Before we get to the code that uses the D3 pattern to bind data to SVG Group elements, let's take a look at what happens when we pass the callbackData variable to the D3 Pie Layout Function.

pie(callbackData);

As the callbackData variable is an array of 7 objects, we should expect that the D3 Pie Layout Function takes in each of the objects and creates new objects that have the starting and ending angles as well as the original value of the objects.

You can see that it returns an array of 7 objects.


Let's look at the first object from the results.

BROWSER click into the first object.

You can see that this object has four 4 key,value pairs.

The first key,value pair has a key of data and a value of an object.

The second key,value pair has a key of endAngle and value of a number.

The third key,value pair has a key of startAngle and a value of a number.

The fourth key,value pair has a key of value and a value of a number.


If we click into the object that is the value of the key data, we can see that it is the original object that was passed in.

BROWSER click into the object that is the value of the key "data"


Let's check to make sure they are the exact same objects using the JavaScript Identity Operator which is the three equal signs.

pie(callbackData)[0]['data'] === callbackData[0];

The JavaScript console returns true so we know they are in fact the same exact object.


Going back to the rest of the key,value pairs.

pie(callbackData);

Since this is an array of objects it makes sense that this is what we are going to pass into D3 Data Operator.


Let's now take a look at the code that uses the D3 pattern to bind data to SVG Group Elements with the class of "arc".

var g = svg.selectAll(".arc")
    .data(pie(callbackData))
  .enter().append("g")
    .attr("class", "arc");

BROWSER open the G element and show the 7 arcs.

You can see that this code generated 7 SVG Group elements with the class of "arc".


Let's take a look what data was bound the first SVG Group element with the class of "arc".

d3.select(".arc").data();

BROWSER click into the object.

You can see that it is the exact same object with 4 key,value pairs we looked at earlier from the results of passing the callbackData variable to the D3 Pie Layout function.

So each of the 7 SVG Group Elements will have it's respective age group object, start angle, end angle and value.


Before we use the D3 pattern a second time, let's see what happens when we pass in this data object to the arc generator function we defined earlier.

arc(d3.select(".arc").data()[0]);

Here we get data that was bound to the first SVG element and get the object inside of the array.

Then we pass it to the arc generator function.

You can see the result is something written in the SVG path Mini-Language.

This is what we want and this is what is passed to the d attribute of the path.

Now that we know what happens, let's use the D3 pattern the second time.


We use the D3 pattern a second time to bind the Data from each of the SVG Group Elements in the variable G to SVG Arcs.

g.append("path")
    .attr("d", arc)
    .style("fill", function(d) { return color(d.data.age); });

BROWSER Click into 1st g class="arc" to show

A path is appended to each SVG Group Element in the variable "g".

D3 implicitly uses the Data bound to the SVG Group Elements as an input to the D3 Arc Generation function we named arc earlier.

As we just saw, the D3 Arc Generation function then returns instructions in the SVG Path Mini-Language to create the arc.

Lastly, the fill of the arc is defined based on the color ordinal function.

Remember that since we didn't define the domain of the color function earlier, that this passing of data to the color ordinal function does two things.

One - it returns a color.

Two - if the data isn't yet present in the domain it adds it to the domain.

So after going through all of the age groups, the domain of the color ordinal function will contain all the age groups.


Let's look at the color ordinal scale domain.

color.domain();

You can see that it contains all the age groups.


Before we append the text, let's try running the JavaScript object bound to the first SVG Group Element with class arc through arc dot centroid.

arc.centroid(d3.select(".arc").data()[0]);

You can see that this returns an x and y coordinate for the specific object.

This is what will be used to place the text for each Pie Chart slice in the right place.


Finally, let's append the age group text labels to each slice of the Pie Chart.

g.append("text")
    .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
    .attr("dy", ".35em")
    .style("text-anchor", "middle")
    .text(function(d) { return d.data.age; });

Each slice will now have the right age group associated with it as a text label.


And there we go, we have the Pie Chart.


Let's close the Chrome Developer tools to get a better look.

BROWSER - close the Chrome Developer Tools.

BROWSER - zoom out.

You can see the full picture.


What is crucial to understand about this chart is that it uses the same pattern we have been seeing for working with nested data.

We first create an array of JavaScript objects that have data inside of each one.

This interior data consists of more JavaScript Objects with data inside of them.

In previous charts, we created an array of JavaScript objects inside of each object.


In this chart, we create one JavaScript Object inside of each object.

Once we have this array of objects where each object has an object inside of them, we can bind the outside objects to SVG Group Elements and we can bind the inside objects to SVG Path Elements based on the D3 Arc Generation Function and the D3 Pie Chart Layout function.

In this chart we use the D3 Pie Chart Layout Function to do the math behind the scenes for us.

<< Back To D3 Screencast and Written Tutorials Index