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:
- https://github.com/d3/d3-scale/blob/master/README.md#category-scales
- https://github.com/d3/d3-scale-chromatic#categorical
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
pathelements doesn't have a.labelproperty - Fortunately, it does have a
.dataattribute that mirrors what the data looked like before we passed it to thepie()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);