You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4.7 KiB

Creating a Pie Chart

Set Up

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script src="https://d3js.org/d3.v4.min.js"></script>
    </head>
    <body>
        <svg>
            <g></g>
        </svg>
        <script src="app.js" charset="utf-8"></script>
    </body>
</html>

Set Config Vars

var WIDTH = 360;
var HEIGHT = 360;
var radius = Math.min(WIDTH, HEIGHT) / 2;

var dataset = [
    { label: 'Abulia', count: 10 },
    { label: 'Betelgeuse', count: 20 },
    { label: 'Cantaloupe', count: 30 },
    { label: 'Dijkstra', count: 40 }
];

Create an Ordinal Scale

An ordinal scale maps discrete values (can't be interpolated) to discrete values.

var mapper = d3.scaleOrdinal();
mapper.range([45, 63, 400]); //list each value for ordinal scales, not min/max
mapper.domain(['Bob', 'Sally', 'Zagthor']); //list each value for ordinal scales, not min/max

console.log(mapper('Bob'));
console.log(mapper('Sally'));
console.log(mapper('Zagthor'));

You cannot invert ordinal scales:

console.log(mapper.invert(45));

Create the color scale to map labels to colors

D3 comes with lots of pre-made color schemes:

They're just arrays:

console.log(d3.schemeCategory10)

Consequently, we can use them when setting a range:

var colorScale = d3.scaleOrdinal();
colorScale.range(d3.schemeCategory10);

We can generate an array of labels for the domain using JavaScript's map function:

colorScale.domain(dataset.map(function(element){
    return element.label;
}));

Set up the svg

Standard:

d3.select('svg')
    .attr('width', WIDTH)
    .attr('height', HEIGHT);

Add paths for each pie segment

var path = d3.select('g').selectAll('path')
    .data(dataset)
    .enter()
    .append('path')
    .attr('fill', function(d) {
        return colorScale(d.label);
    });

Generate an arc creating function

Next we want to do something like this:

.attr('d', function(datum){
    //return path string here
})

Fortunately, D3 can generate something like this for us:

var arc = d3.arc()
    .innerRadius(0) //to make this a donut graph, adjust this value
    .outerRadius(radius);

We could plug this function into it's right place, but it won't work yet:

var path = d3.select('g').selectAll('path')
    .data(dataset)
    .enter()
    .append('path')
    .attr('d', arc) //add this
    .attr('fill', function(d) {
        return colorScale(d.label);
    });

Format the data for the arc

  • The reason that our arc() function won't work is that the data isn't formatted properly for the function
  • The arc function we generated expects the data object to have things like start angle, end angle, etc
  • D3 can reformat our data so that it will work with our generated arc() function
var pie = d3.pie()
    .value(function(d) { return d.count; }) //use the 'count' property each value in the original array to determine how big the piece of pie should be
    .sort(null); //don't sort the values

pie is a function that takes an array of values as a param and returns an array of objects that are formatted for our arc function

console.log(pie(dataset));

We can use this when attaching data to our paths:

var path = d3.select('g').selectAll('path')
    .data(pie(dataset)) //reformat data for arc
    .enter()
    .append('path')
    .attr('d', arc)
    .attr('fill', function(d) {
        return colorScale(d.label);
    });
  • Unfortunately, now each object from the data array that's been attached to our path elements doesn't have a .label property
  • Fortunately, it does have a .data attribute that mirrors what the data looked like before we passed it to the pie() function
var path = d3.select('g').selectAll('path')
    .data(pie(dataset))
    .enter()
    .append('path')
    .attr('d', arc)
    .attr('fill', function(d) {
        return colorScale(d.data.label); //use .data property to access original data
    });

Adjust the position of the pie

The pie starts at (0,0), so we can move the group containing the pie:

var container = d3.select('g')
    .attr('transform', 'translate(' + (WIDTH / 2) + ',' + (HEIGHT / 2) + ')'); //pie center is at 0,0

Make a donut graph

If you want the pie to have a hole at the center, just adjust the inner radius of the arc() function:

var arc = d3.arc()
    .innerRadius(100) //to make this a donut graph, adjust this value
    .outerRadius(radius);