Skip to content

Instantly share code, notes, and snippets.

@cingraham
Last active May 15, 2019 18:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cingraham/7424289 to your computer and use it in GitHub Desktop.
Save cingraham/7424289 to your computer and use it in GitHub Desktop.
Table 1-1: Congressional Seats by Region and State
date Alabama Arkansas Florida Georgia Louisiana Mississippi North Carolina South Carolina Tennessee Texas Virginia Kentucky Maryland Missouri Oklahoma West Virginia Connecticut Maine Massachusetts New Hampshire Rhode Island Vermont Delaware New Jersey New York Pennsylvania Illinois Indiana Michigan Ohio Wisconsin Iowa Kansas Minnesota Nebraska North Dakota South Dakota Arizona Colorado Idaho Montana Nevada New Mexico Utah Wyoming Alaska California Hawaii Oregon Washington
region South South South South South South South South South South South Border Border Border Border Border NewEngland NewEngland NewEngland NewEngland NewEngland NewEngland MidAtlantic MidAtlantic MidAtlantic MidAtlantic Midwest Midwest Midwest Midwest Midwest Plains Plains Plains Plains Plains Plains RockyMountains RockyMountains RockyMountains RockyMountains RockyMountains RockyMountains RockyMountains RockyMountains PacificCoast PacificCoast PacificCoast PacificCoast PacificCoast
1910 10 7 4 12 8 8 10 7 10 18 10 11 6 16 8 6 5 4 16 2 3 2 1 12 43 36 27 13 13 22 11 11 8 10 6 3 3 1 4 2 2 1 1 2 1 0 11 0 3 5
1930 9 7 5 10 8 7 11 6 9 21 9 9 6 13 9 6 6 3 15 2 2 1 1 14 45 34 27 12 17 24 10 9 7 9 5 2 2 1 4 2 2 1 1 2 1 0 20 0 3 6
1940 9 7 6 10 8 7 12 6 10 21 9 9 6 13 8 6 6 3 14 2 2 1 1 14 45 33 26 11 17 23 10 8 6 9 4 2 2 2 4 2 2 1 2 2 1 0 23 0 4 6
1950 9 6 8 10 8 6 12 6 9 22 10 8 7 11 6 6 6 3 14 2 2 1 1 14 43 30 25 11 18 23 10 8 6 9 4 2 2 2 4 2 2 1 2 2 1 1 30 1 4 7
1960 8 4 12 10 8 5 11 6 9 23 10 7 8 10 6 5 6 2 12 2 2 1 1 15 41 27 24 11 19 24 10 7 5 8 3 2 2 3 4 2 2 1 2 2 1 1 38 2 4 7
1970 7 4 15 10 8 5 11 6 8 24 10 7 8 10 6 4 6 2 12 2 2 1 1 15 39 25 24 11 19 23 9 6 5 8 3 1 2 4 5 2 2 1 2 2 1 1 43 2 4 7
1980 7 4 19 10 8 5 11 6 9 27 10 7 8 9 6 4 6 2 11 2 2 1 1 14 34 23 22 10 18 21 9 6 5 8 3 1 1 5 6 2 2 2 3 3 1 1 45 2 5 8
1990 7 4 23 11 7 5 12 6 9 30 11 6 8 9 6 3 6 2 10 2 2 1 1 13 31 21 20 10 16 19 9 5 4 8 3 1 1 6 6 2 1 2 3 3 1 1 52 2 5 9
2000 7 4 25 13 7 4 13 6 9 32 11 6 8 9 5 3 5 2 10 2 2 1 1 13 29 19 19 9 15 18 8 5 4 8 3 1 1 8 7 2 1 3 3 3 1 1 53 2 5 9
2010 7 4 27 14 6 4 13 7 9 36 11 6 8 8 5 3 5 2 9 2 2 1 1 12 27 18 18 9 14 16 8 4 4 8 3 1 1 9 7 2 1 4 3 4 1 1 53 2 5 10
<!DOCTYPE html>
<meta charset="utf-8">
<html>
<head>
<title>Table 1-1: Apportionment of Congressional Seats, by Region and State, 1910-2010</title>
<link rel = "stylesheet" type = "text/css" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css">
<style type="text/css">
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: auto;
padding-top: 10px;
padding-left: 10px;
position: relative;
width: 960px;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 2.5px;
}
h3 {
color: #333;
}
svg { background:rgb(255,255,255);position:relative;}
svg:not(:root) { overflow: hidden; }
.y.axis line {
stroke: #ccc;
stroke-dasharray: 1,3;
}
.x.axis line {
stroke: #666;
stroke-dasharray: 3,1;
}
.y.axis path {
display: none;
}
.y.axis .zero line {
stroke: #333;
}
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.y.axis line {
stroke-dasharray: 5,5;
}
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js" type="text/javascript"></script>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.2/js/bootstrap.min.js" type="text/javascript"></script>
</head>
<body>
<h3><b>Apportionment of Congressional Seats, by Region and State, 1910-2010</b></h3>
<h4 id= "location">United States</h4>
<p id = "detailtext">Select a region or mouse over a line for more detail.</p>
<div class="btn-group" id="select">
<button type="button" class="btn btn-default active" value = "None">None</button>
<button type="button" class="btn btn-default" value = "South">South</button>
<button type="button" class="btn btn-default" value = "Border">Border</button>
<button type="button" class="btn btn-default" value = "NewEngland">New England</button>
<button type="button" class="btn btn-default" value = "MidAtlantic">Mid-Atlantic</button>
<button type="button" class="btn btn-default" value = "Midwest">Midwest</button>
<button type="button" class="btn btn-default" value = "Plains">Plains</button>
<button type="button" class="btn btn-default" value = "RockyMountains">Rocky Mountains</button>
<button type="button" class="btn btn-default" value = "PacificCoast">Pacific Coast</button>
</div>
<div id = "#container"></div>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript">
//set margins, height, and width
var margin = {top: 5, right: 20, bottom: 20, left: 40},
w = 960 - margin.left - margin.right,
h = 500 - margin.top - margin.bottom;
//set up formatting for dates(x-axis) and percentages (data labels)
var parseDate = d3.time.format("%Y").parse;
var formatpct = d3.format("+.1%");
//variables indicating which region is selected, and placeholders in order to revert the caption text
var selectedRegion = "none;"
var prevText = "", prevRegion = "";
//x and y-axis scales. I hard-coded the y-max because I'm lazy; you could also dig this up with d3.max
var x = d3.time.scale()
.range([0, w]);
var y = d3.scale.linear()
.range([h, 0])
.domain([0, 53]);
//total seats by region in 1910
var totals1910 = {
South: 104,
Border: 47,
NewEngland: 32,
MidAtlantic: 92,
Midwest: 86,
Plains: 41,
RockyMountains: 14,
PacificCoast:19
};
//total seats by region in 2010
var totals2010 = {
South: 138,
Border: 30,
NewEngland: 21,
MidAtlantic: 58,
Midwest: 65,
Plains: 21,
RockyMountains: 31,
PacificCoast: 71
};
//color scale -- d3's prebuilt 10-category ordinal scale
var color = d3.scale.category10();
//set up the line generator
var line = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.value); });
//set up your axes
var xAxis = d3.svg.axis()
.scale(x)
.tickSize(5)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
//add svg to the document
var svg = d3.select("body").append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//read the data file
d3.csv("apportionment.csv", function(error, data) {
//use date formatting function ensure D3 is reading dates properly
data.forEach(function(d,i) {
d.date = parseDate(d.date);
});
//set x-axis domain using d3.extent (same as calling both min and max)
x.domain(d3.extent(data, function(d) { return d.date; }));
//set color domain - basically return all columns that aren't the date column
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
//create an array to store the region data, currently held in the second header row of our data file
var regions = data[0];
//now that we've stored the regions in a separate array, we can trim that row from the data file
data = data.filter(function(d, i) { return i > 0; });
//formatting the data so that the line generator reads it properly
var states = color.domain().map(function(name, i) {
return {
name: name,
region: regions[name],
values: data.map(function(d) {
return {date: d.date, value: +d[name]};
})
};
});
//append axes
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + h + ")")
.call(xAxis);
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("Number of seats");
//append a group for each state
var state = svg.selectAll(".state")
.data(states)
.enter().append("g")
.attr("class", "state");
//draw the lines, and call functions on mouseover and mouseout
state.append("path")
.attr("class", function(d) { return "line " + d.region; })
.attr("d", function(d) { return line(d.values); })
.attr("id", function(d) { return d.name; })
.style("stroke", function(d) { return color(d.region); })
.style("opacity", "0.1")
.on("mouseover", function(d) { showDetail(d); })
.on("mouseout", function(d) { removeDetail(d); });
//tell it what to do when you click one of the filter buttons at top
d3.selectAll(".btn")
.on("click", function() {
var reg = this.value;
var display = this.innerHTML;
getHighlight(reg, display);
});
});
//this function highlights the selected line and updates the caption at the top of the page
function showDetail(line) {
prevText = d3.selectAll("#detailtext").html();
prevRegion = d3.selectAll("#location").html();
var total1910 = line.values[0].value;
var total2010 = line.values[9].value;
var pctChange = formatpct((total2010 - total1910)/total1910);
if(total1910 == 0) {
pctChange = "N/A%";
};
var highlighted = svg.selectAll("path").filter(function(g) {return g.name == line.name; });
highlighted.transition().duration(250).style({"opacity":"1"});
d3.selectAll("#location")
.html(line.name);
d3.selectAll("#detailtext")
.html("<p>" + line.name + " had <b>" + total1910 + " seats</b> in 1910" + " and <b>" + total2010 + " seats</b> in 2010, a change of <b>" + pctChange + "</b>");
}
//basically the reverse of the previous - note that we use prevRegion and prevText to revert back to the prior header/caption. This is because this text will differ depending on whether a region is selected
function removeDetail(line) {
var highlighted = svg.selectAll("path").filter(function(g) {return g.name ==line.name; });
highlighted.transition().duration(250).style("opacity", function() {
if(selectedRegion == line.region) {
return 0.8;
} else {
return 0.1;
}
});
d3.selectAll("#location")
.html(prevRegion);
d3.selectAll("#detailtext")
.html(prevText);
}
//update lines and captions when you select a region
function getHighlight (region, displaytext) {
d3.selectAll("#location")
.html(displaytext);
var total1910 = totals1910[region];
var total2010 = totals2010[region];
var pctChange = formatpct((total2010 - total1910)/total1910);
selectedRegion = region;
if(region == "None") {
d3.selectAll("#location")
.html("United States");
d3.selectAll("#detailtext")
.html("<p>Select a region or mouse over a line for more detail.</p>");
} else {
d3.selectAll("#location")
.html(displaytext);
d3.selectAll("#detailtext")
.html("<p>States in the " + displaytext + " region had <b>" + total1910 + " seats</b> in 1910" + " and <b>" + total2010 + " seats</b> in 2010, a change of <b>" + pctChange + "</b>");
}
d3.selectAll(".line")
.transition()
.duration(500)
.style({"opacity":"0.1","stroke-width":"2.5"});
if(region != "none") {
d3.selectAll("." + region)
.transition()
.duration(500)
.style({"opacity":"0.8","stroke-width":"5"})
}
}
d3.select(self.frameElement).style("height", "700px");
</script>
<script type="text/javascript">
// allow buttons to indicate whether they're selected
$("#select button").click(function() {
$("#select button").removeClass("active");
$(this).addClass("active");
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment