Created
March 21, 2016 20:15
-
-
Save JenHLab/681648ebf01471b351f1 to your computer and use it in GitHub Desktop.
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
City | Drove_Alone | Carpooled | Public_Transportation | Walked | Bicycle | Taxi_Motorcycle | Work_at_Home | |
---|---|---|---|---|---|---|---|---|
Washington DC | 109902 | 18748 | 122831 | 40082 | 12606 | 3878 | 15192 | |
Los Angeles | 1194792 | 173981 | 193510 | 63911 | 19528 | 28405 | 102193 | |
San Francisco | 165314 | 34250 | 150244 | 47037 | 17353 | 10503 | 32423 | |
New York City | 822821 | 177907 | 2113347 | 379800 | 37604 | 63926 | 150416 | |
Boston | 126543 | 20968 | 109104 | 48163 | 6225 | 2948 | 12122 | |
Seattle | 185236 | 30509 | 71188 | 33778 | 13438 | 4721 | 24335 | |
Chicago | 609654 | 108735 | 332316 | 81857 | 17104 | 18326 | 53757 | |
Houston | 775255 | 124612 | 43920 | 20428 | 5107 | 19406 | 32685 | |
Dallas | 444209 | 63458 | 23652 | 10384 | 1153 | 9807 | 24229 | |
Atlanta | 138885 | 15409 | 20275 | 9326 | 1622 | 2433 | 14800 | |
Detroit | 141216 | 25064 | 18135 | 6724 | 8151 | 4075 | 6724 | |
Miami | 126948 | 17244 | 20913 | 8255 | 1651 | 2201 | 6053 |
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
<!DOCTYPE html> | |
<!-- code loosely inspired by this block https://gist.github.com/mstanaland/6100713 --> | |
<meta charset="utf-8"> | |
<head> | |
<link href='https://fonts.googleapis.com/css?family=Amiri' rel='stylesheet' type='text/css'> | |
<style> | |
body { | |
font-family: serif; | |
font: 12px; | |
padding: 50px; | |
} | |
h1{ | |
font-family: 'Amiri', serif; | |
} | |
#form { | |
position: relative; | |
right: 10px; | |
top: 10px; | |
padding-bottom: 20px; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.bar { | |
fill: steelblue; | |
} | |
.x.axis path { | |
display: none; | |
} | |
.tooltip { | |
position: absolute; | |
z-index: 10; | |
} | |
.tooltip p { | |
background-color: white; | |
border: gray 1px solid; | |
padding: 2px; | |
max-width: 180px; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>Commuting Preferences in Top Congested U.S. Cities</h1> | |
<div id="form"> | |
<label><input type="radio" name="mode" value="bycount" checked>Total Commuters</label> | |
<label><input type="radio" name="mode" value="bypercent">As Percent of Commuting Preferences</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 = 980, fullheight = 500; | |
var margin = {top: 20, right: 170, bottom: 80, left: 80}, | |
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 color = d3.scale.category20(); | |
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("cities_commuters.csv", function(error, data) { | |
if (error) { | |
console.log(error); | |
} | |
data.sort(function(a, b) {return d3.ascending(a.City,b.City);}); | |
// how would we sort by largest total bar? what would we have to calculate? | |
var cities = ["Drove_Alone","Carpooled","Public_Transportation","Walked", | |
"Bicycle","Taxi_Motorcycle","Work_at_Home"]; | |
color.domain(cities); | |
xScale.domain(data.map(function(d) { return d.City; })); | |
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") | |
.text("Commuters"); | |
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(cities, data) { | |
return cities.map(function(city) { | |
return data.map(function(d) { | |
return {x: d.City, y: +d[city], city: city}; | |
}) | |
}); | |
} | |
function transitionPercent() { | |
yAxis.tickFormat(d3.format("%")); | |
stack.offset("expand"); // use this to get it to be relative/normalized! | |
var stacked = stack(makeData(cities, 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(cities, data)); | |
transitionRects(stacked); | |
} | |
function transitionRects(stacked) { | |
// this domain is using the last of the stacked arrays, which is the last city, and getting the max height. | |
yScale.domain([0, d3.max(stacked[stacked.length-1], function(d) { return d.y0 + d.y; })]); | |
var city = svg.selectAll("g.city") | |
.data(stacked); | |
city.enter().append("g") | |
.attr("class", "city") | |
.style("fill", function(d, i) { return color(d[0].city); }); | |
// then data for each, plus mouseovers - a nested selection/enter here | |
city.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()) | |
.on("mouseover", mouseover) | |
.on("mousemove", mousemove) | |
.on("mouseout", mouseout); | |
// the thing that needs to transition is the rectangles themselves, not the g parent. | |
city.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 | |
city.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 cities_reversed = cities.slice().reverse(); | |
var legend = svg.selectAll(".legend") | |
.data(cities_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) | |
.attr("width", 18) | |
.attr("height", 18) | |
.style("fill", function(d) {return color(d)}); | |
legend.append("text") | |
.attr("x", width + 24) | |
.attr("y", 9) | |
.attr("dy", ".35em") | |
.style("text-anchor", "start") | |
.text(function(d, i) { return cities_reversed[i].replace(/_/g, " "); }); | |
} | |
function mouseover(d) { | |
// this will highlight both a dot and its line. | |
var number; | |
d3.select(this) | |
.transition() | |
.style("stroke", "black"); | |
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>Mode of Transportation: " + d.city.replace(/_/g, " ") + | |
"<br>Commuters: " + number + | |
"<br>City: " + d.x + " </p>"); | |
} | |
function mousemove(d) { | |
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"); | |
tooltip.style("display", "none"); // this sets it to invisible! | |
} | |
}); | |
</script> | |
<p><i>Sources:</i><br> | |
<a href="http://factfinder.census.gov/faces/nav/jsf/pages/index.xhtml">American FactFinder. US Census Bureau. 2016.</a>. | |
<br> | |
<a href="http://d2dtl5nnlpfr0r.cloudfront.net/tti.tamu.edu/documents/mobility-scorecard-2015.pdf">2015 Urban Mobility Scorecard. Texas A&M Transportation Institute. 2016.</a>. | |
</p> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment