Last active
March 21, 2016 15:43
-
-
Save captainelaine/eda2ef3808315c6b825a to your computer and use it in GitHub Desktop.
Week9: Stacked Transition.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Country | Mercedes | Ferrari | Williams | Sauber | Red_Bull | Force_India | Toro_Rosso | McLaren | Lotus | |
---|---|---|---|---|---|---|---|---|---|---|
Australian | 43 | 15 | 12 | 14 | 8 | 7 | 2 | 0 | 0 | |
Malaysian | 33 | 37 | 18 | 0 | 3 | 0 | 10 | 0 | 0 | |
Chinese | 43 | 27 | 18 | 5 | 2 | 0 | 0 | 0 | 6 | |
Bahrain | 40 | 28 | 13 | 0 | 10 | 4 | 0 | 0 | 6 | |
Spanish | 43 | 25 | 20 | 0 | 7 | 0 | 2 | 0 | 4 | |
Monaco | 40 | 26 | 0 | 2 | 22 | 6 | 1 | 4 | 0 | |
Canadian | 43 | 22 | 23 | 0 | 2 | 4 | 0 | 0 | 7 | |
Austrian | 43 | 12 | 25 | 0 | 1 | 10 | 4 | 0 | 6 | |
British | 43 | 19 | 22 | 0 | 8 | 8 | 0 | 1 | 0 | |
Hungarian | 12 | 25 | 0 | 1 | 33 | 0 | 12 | 12 | 6 | |
Belgian | 43 | 6 | 10 | 1 | 12 | 10 | 4 | 0 | 15 | |
Italian | 25 | 28 | 27 | 2 | 5 | 14 | 0 | 0 | 0 | |
Singapore | 12 | 40 | 10 | 1 | 26 | 6 | 6 | 0 | 0 | |
Japanese | 43 | 27 | 10 | 0 | 0 | 8 | 3 | 0 | 10 | |
Russian | 25 | 22 | 12 | 8 | 10 | 15 | 1 | 2 | 6 | |
United States | 43 | 15 | 0 | 2 | 1 | 10 | 18 | 8 | 4 | |
Mexican | 43 | 0 | 23 | 0 | 22 | 10 | 2 | 0 | 1 | |
Brazilian | 43 | 27 | 10 | 0 | 6 | 8 | 2 | 0 | 5 | |
Abu Dhabi | 43 | 27 | 4 | 0 | 9 | 16 | 0 | 0 | 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link href='https://fonts.googleapis.com/css?family=Ubuntu:300italic,500|Josefin+Sans:400italic' rel='stylesheet' type='text/css'> | |
<!DOCTYPE html> | |
<!-- code loosely inspired by this block https://gist.github.com/mstanaland/6100713 --> | |
<meta charset="utf-8"> | |
<style> | |
body { | |
font-size: 12px; | |
font-family: 'Ubuntu',sans-serif; | |
padding: 50px; | |
text-align: center; | |
} | |
#form { | |
position: relative; | |
right: 10px; | |
top: 20px; | |
padding-bottom: 20px; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: gray; | |
opacity:0.3; | |
stroke-width:1.5px; | |
shape-rendering: crispEdges; | |
} | |
.bar { | |
fill: steelblue; | |
} | |
.x.axis path { | |
display: none; | |
} | |
.tooltip { | |
position: absolute; | |
z-index: 10; | |
} | |
.tooltip p { | |
background-color:white; | |
border: white 2px solid; | |
padding: 2px; | |
max-width: 180px; | |
} | |
.focused { | |
opacity: 1; | |
} | |
.unfocused { | |
opacity: 0.6; | |
} | |
</style> | |
<body> | |
<h1>F1 teams' performances during the 2015 Championship</h1> | |
<p><a href="https://en.wikipedia.org/wiki/2015_Formula_One_season">Source: Wikipedia-Formula One 2015</a></p> | |
<p><em>Last season, team Mercedes, with their two drivers - Lewis Hamilton and Nico Rosberg, got both the driver and team champions.</em></p> | |
<p><em>This chart give you a direct view of how many points and the percentage of the won point each teams won in each countries' championships</em></p> | |
<p><em>You can easily find out in most time of the season, team Mercedes and Ferrari cover the first four places of races.</em></p> | |
<div id="form"> | |
<label><input type="radio" name="mode" value="bycount" checked>Raw Points won by teams</label> | |
<label><input type="radio" name="mode" value="bypercent">As Percent of points won by teams</label> | |
</div> | |
<div id="chart"></div> | |
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script> | |
<script> | |
var currentMode = "bycount"; | |
var fullwidth = 1100, fullheight = 600; | |
var margin = {top: 50, right: 150, bottom: 70, left: 120}, | |
width = fullwidth - margin.left - margin.right, | |
height = fullheight - margin.top - margin.bottom; | |
var xScale = d3.scale.ordinal() | |
.rangeRoundBands([0, width], .3); | |
var yScale = d3.scale.linear() | |
.rangeRound([height, 0]); | |
var xAxis = d3.svg.axis() | |
.scale(xScale) | |
.orient("bottom") | |
.innerTickSize([0]); | |
var yAxis = d3.svg.axis() | |
.scale(yScale) | |
.orient("left") | |
.tickFormat(d3.format(".2s")); // for the stacked totals version | |
var stack = d3.layout | |
.stack(); // default view is "zero" for the count display. | |
var svg = d3.select("#chart").append("svg") | |
.attr("width", fullwidth) | |
.attr("height", fullheight) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var tooltip = d3.select("body").append("div").attr("class", "tooltip"); | |
d3.csv("2015season.csv", function(error, data) { | |
if (error) { | |
console.log(error); | |
} | |
//data.sort(function(a, b) {return d3.ascending(a.Country,b.Country);}); | |
// how would we sort by largest total bar? what would we have to calculate? | |
var raceteam = ["Mercedes","Ferrari","Williams","Red_Bull","McLaren"]; | |
var color = d3.scale.ordinal().domain(raceteam).range(["rgb(177,181,182)","red","rgb(51,133,229)","rgb(172,62,100)","rgb(248,160,53)"]); | |
xScale.domain(data.map(function(d) { return d.Country; })); | |
svg.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + height + ")") | |
.call(xAxis) | |
.selectAll("text") | |
.attr("dy", ".5em") | |
.attr("transform", "rotate(-30)") | |
.style("text-anchor", "end"); | |
svg.append("g") | |
.attr("class", "y axis") | |
.call(yAxis) | |
.append("text") | |
.attr("transform", "rotate(-90)") | |
.attr("y", 6) | |
.attr("dy", ".71em") | |
.style("text-anchor", "end"); | |
svg.append("text") | |
.attr("class", "xlabel") | |
.attr("transform", "translate(" + (margin.left + width / 2) + " ," + | |
(height + margin.bottom) + ")") | |
.style("text-anchor", "middle") | |
.style("fill", "gray") | |
.attr("dy", "-10px") | |
.attr("dx", "-120px") | |
.text("Championship"); | |
svg.append("text") | |
.attr ("class", "ylabel") | |
.attr("transform", "rotate(-90)") | |
.attr("y", 0 - margin.left + 30) // you may need to adjust this | |
.attr("x", 0 - (height / 2)) // you may need to adjust | |
.attr("dy", "3em") | |
.style("fill", "gray") | |
.style("text-anchor", "middle") | |
.text("Points"); | |
transitionCount(); // this will use the by-count stack, and make the data, and draw. | |
drawLegend(); | |
d3.selectAll("input").on("change", handleFormClick); | |
// All the functions for stuff above! | |
function handleFormClick() { | |
if (this.value === "bypercent") { | |
currentMode = "bypercent"; | |
transitionPercent(); | |
} else { | |
currentMode = "bycount"; | |
transitionCount(); | |
} | |
} | |
function makeData(raceteam, data) { | |
return raceteam.map(function(raceteam) { | |
return data.map(function(d) { | |
return {x: d.Country, y: +d[raceteam], raceteam: raceteam}; | |
}) | |
}); | |
} | |
function transitionPercent() { | |
yAxis.tickFormat(d3.format("%")); | |
stack.offset("expand"); // use this to get it to be relative/normalized! | |
var stacked = stack(makeData(raceteam, data)); | |
// call function to do the bars, which is same across both formats. | |
transitionRects(stacked); | |
} | |
function transitionCount() { | |
yAxis.tickFormat(d3.format(".2s")); // for the stacked totals version | |
stack.offset("zero"); | |
var stacked = stack(makeData(raceteam, data)); | |
transitionRects(stacked); | |
} | |
function transitionRects(stacked) { | |
// this domain is using the last of the stacked arrays, which is the last illness, and getting the max height. | |
yScale.domain([0, d3.max(stacked[stacked.length-1], function(d) { return d.y0 + d.y; })]); | |
var raceteam = svg.selectAll("g.raceteam") | |
.data(stacked); | |
raceteam.enter().append("g") | |
.attr("class", "raceteam") | |
.style("fill", function(d, i) { return color(d[0].raceteam); }); | |
// then data for each, plus mouseovers - a nested selection/enter here | |
raceteam.selectAll("rect") | |
.data(function(d) { | |
console.log("array for a rectangle", d); | |
return d; }) // this just gets the array for bar segment. | |
.enter().append("rect") | |
.attr("width", xScale.rangeBand()) | |
.attr("class", "unfocused") | |
.classed("class","focused") | |
.on("mouseover", mouseover) | |
.on("mousemove", mousemove) | |
.on("mouseout", mouseout); | |
// the thing that needs to transition is the rectangles themselves, not the g parent. | |
raceteam.selectAll("rect") | |
.transition() | |
.duration(250) | |
.attr("x", function(d) { | |
return xScale(d.x); }) | |
.attr("y", function(d) { | |
return yScale(d.y0 + d.y); }) // | |
.attr("height", function(d) { | |
return yScale(d.y0) - yScale(d.y0 + d.y); }); // height is base - tallness | |
raceteam.exit().remove(); // there's actually nothing removed here - we just transition. | |
svg.selectAll(".y.axis").transition().call(yAxis); | |
} | |
// Building a legend by hand, based on http://bl.ocks.org/mbostock/3886208 | |
function drawLegend() { | |
// reverse to get the same order as the bar color layers | |
var raceteam_reversed = raceteam.slice().reverse(); | |
var legend = svg.selectAll(".legend") | |
.data(raceteam_reversed) // make sure your labels are in the right order -- if not, use .reverse() here. | |
.enter().append("g") | |
.attr("class", "legend") | |
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); | |
legend.append("rect") | |
.attr("x", width+5) | |
.attr("width", 18) | |
.attr("height", 18) | |
.style("fill", function(d) {return color(d)}); | |
legend.append("text") | |
.attr("x", width + 29) | |
.attr("y", 8) | |
.attr("dy", ".35em") | |
.style("text-anchor", "start") | |
.text(function(d, i) { return raceteam_reversed[i].replace(/_/g, " "); }); | |
} | |
function mouseover(d) { | |
// this will highlight both a dot and its line. | |
var number; | |
d3.select(this) | |
.transition() | |
.attr("class", "focused"); | |
if (currentMode == "bypercent") { | |
number = d3.format(".1%")(d.y); | |
} else { | |
number = d.y; | |
} | |
tooltip | |
.style("display", null) // this removes the display none setting from it | |
.html("<p>Team: " + d.raceteam.replace(/_/g, " ") + | |
"<br>Points: " + number + | |
"<br>Race Country: " + d.x + " </p>"); | |
} | |
function mousemove(d) { | |
d3.select(this) | |
.attr("class","focused") | |
tooltip | |
.style("top", (d3.event.pageY - 10) + "px" ) | |
.style("left", (d3.event.pageX + 10) + "px"); | |
} | |
function mouseout(d) { | |
d3.select(this) | |
.transition() | |
.style("stroke", "none") | |
.attr("class","unfocused") | |
tooltip.style("display", "none"); // this sets it to invisible! | |
} | |
}); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment