Let’s make a chart! I’m going to try to replicate a chart from Golden State of Mind where we were voting on players for a NBA draft board (fear not, you won’t have to know what the heck that means to follow along here). Here’s a snapshot of it:
Here’s my version followed by the code to implement it:
First, we define our dataset, which is an array of objects:
var players = [
{"First": "Harrison", "Last": "Barnes", "Votes": 61},
{"First":"Andre", "Last":"Drummond", "Votes":27},
{"First":"Bradley", "Last":"Beal", "Votes":"58"},
{"First":"Meyers", "Last":"Leonard", "Votes":8},
{"First":"Jared", "Last":"Sullinger", "Votes":8},
{"First":"Damian", "Last":"Lillard", "Votes":5},
{"First":"Terrence", "Last":"Jones", "Votes":2},
{"First":"Austin", "Last":"Rivers", "Votes":2},
{"First":"Perry", "Last":"Jones", "Votes":2},
{"First":"Others","Last":"","Votes":6}
],
There are surely many different ways to read in the data, but that one made sense to me. Now we’ll define some other variables that will help us make the chart later:
maxVotes = Math.max.apply(Math,players.map(function(o){return o.Votes;})),
minVotes = Math.min.apply(Math,players.map(function(o){return o.Votes;})),
numVotes = players.reduce(function(a,b) {return a+parseInt(b.Votes);},0),
xOffset = 50,
numPlayers = players.length,
svgHeight = numPlayers*55,
svgWidth = maxVotes + 200,
yOffset = svgHeight/(numPlayers+1);
We’ll sort the array by votes in descending order (actually this is an improvement over the above chart):
function sorter(a,b) {
return b.Votes - a.Votes;
}
players.sort(sorter);
Next we insert the svg and draw a border around it:
d3.select("body").append("svg")
.attr("width",svgWidth)
.attr("height",svgHeight);
d3.select("svg").append("rect")
.attr("x",0)
.attr("y",0)
.attr("width",svgWidth)
.attr("height",svgHeight)
.attr("style","fill-opacity:0; stroke:black;stroke-width:6px");
Then we draw the bars:
d3.select("svg")
.append("g").attr("class","bars")
.selectAll("rect")
.data(players)
.enter()
.append("rect")
.attr("x",xOffset)
.attr("style","fill:gold; stroke:black")
.attr("y", function(d,i) {
return yOffset*i+50;
})
.attr("width", function(d,i) {
return d.Votes*2;
})
.attr("height", 20);
Followed by the labels above each bar containing player names:
d3.select("svg")
.append("g").attr("class","names")
.selectAll("text")
.data(players)
.enter()
.append("text")
.attr("x", xOffset)
.attr("y", function(d,i) {
return yOffset*i+45;
})
.attr("style","font-family: sans-serif; font-size: 12pt")
.text(function(d) {return d.First+" "+d.Last;});
The number of votes each player received is placed to the right of the bars (I think an improvement in readability over the original):
d3.select("svg")
.append("g").attr("class","votes")
.selectAll("text")
.data(players)
.enter()
.append("text")
.attr("x", function(d,i) {
return xOffset+d.Votes*2+5;
})
.attr("y", function(d,i) {
return yOffset*i+45+20;
})
.attr("style","font-family: sans-serif; font-size: 10pt")
.text(function(d) {return parseInt(d.Votes) + " votes";});
And the % of total votes each player received is placed to the left of the bars:
d3.select("svg")
.append("g").attr("class","percent")
.selectAll("text")
.data(players)
.enter()
.append("text")
.attr("x", 10)
.attr("y", function(d,i) {
return yOffset*i+45+20;
})
.attr("style","font-family: sans-serif; font-size: 10pt")
.text(function(d) {
return d3.format(".2p")(d.Votes/numVotes);
});
Finally, I put the total number of votes below the chart:
d3.select("body").append("div")
.text(numVotes+" votes");
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.v2.js"></script>
<style type="text/css">
</style>
</head>
<body>
<script>
var players = [
{"First": "Harrison", "Last": "Barnes", "Votes": 61},
{"First":"Andre", "Last":"Drummond", "Votes":27},
{"First":"Bradley", "Last":"Beal", "Votes":"58"},
{"First":"Meyers", "Last":"Leonard", "Votes":8},
{"First":"Jared", "Last":"Sullinger", "Votes":8},
{"First":"Damian", "Last":"Lillard", "Votes":5},
{"First":"Terrence", "Last":"Jones", "Votes":2},
{"First":"Austin", "Last":"Rivers", "Votes":2},
{"First":"Perry", "Last":"Jones", "Votes":2},
{"First":"Others","Last":"","Votes":6}
],
maxVotes = Math.max.apply(Math,players.map(function(o){return o.Votes;})),
minVotes = Math.min.apply(Math,players.map(function(o){return o.Votes;})),
numVotes = players.reduce(function(a,b) {return a+parseInt(b.Votes);},0),
xOffset = 50,
numPlayers = players.length,
svgHeight = numPlayers*55,
svgWidth = maxVotes + 200,
yOffset = svgHeight/(numPlayers+1);
function sorter(a,b) {
return b.Votes - a.Votes;
}
players.sort(sorter);
d3.select("body").append("svg")
.attr("width",svgWidth)
.attr("height",svgHeight);
d3.select("svg").append("rect")
.attr("x",0)
.attr("y",0)
.attr("width",svgWidth)
.attr("height",svgHeight)
.attr("style","fill-opacity:0; stroke:black;stroke-width:6px");
d3.select("svg")
.append("g").attr("class","bars")
.selectAll("rect")
.data(players)
.enter()
.append("rect")
.attr("x",xOffset)
.attr("style","fill:gold; stroke:black")
.attr("y", function(d,i) {
return yOffset*i+50;
})
.attr("width", function(d,i) {
return d.Votes*2;
})
.attr("height", 20);
d3.select("svg")
.append("g").attr("class","names")
.selectAll("text")
.data(players)
.enter()
.append("text")
.attr("x", xOffset)
.attr("y", function(d,i) {
return yOffset*i+45;
})
.attr("style","font-family: sans-serif; font-size: 12pt")
.text(function(d) {return d.First+" "+d.Last;});
d3.select("svg")
.append("g").attr("class","votes")
.selectAll("text")
.data(players)
.enter()
.append("text")
.attr("x", function(d,i) {
return xOffset+d.Votes*2+5;
})
.attr("y", function(d,i) {
return yOffset*i+45+20;
})
.attr("style","font-family: sans-serif; font-size: 10pt")
.text(function(d) {return parseInt(d.Votes) + " votes";});
d3.select("svg")
.append("g").attr("class","percent")
.selectAll("text")
.data(players)
.enter()
.append("text")
.attr("x", 10)
.attr("y", function(d,i) {
return yOffset*i+45+20;
})
.attr("style","font-family: sans-serif; font-size: 10pt")
.text(function(d) {
return d3.format(".2p")(d.Votes/numVotes);
});
d3.select("body").append("div")
.text(numVotes+" votes");
</script>
</body>
</html>
|
Categories :bar charts • data joins