Skip to content

Instantly share code, notes, and snippets.

@armollica
Last active December 5, 2015 13:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save armollica/71f9ff702ec99f3e11c5 to your computer and use it in GitHub Desktop.
Save armollica/71f9ff702ec99f3e11c5 to your computer and use it in GitHub Desktop.
Neighboring Geography Selection

Testing out selecting neighboring geographic units. Uses TopoJSON's topojson.neighbors(objects) function.

Hover to highlight a county and it's neighboring counties. This lets you see how a county compares to its immediate neighbors for a given variable, here the 2014 unemployment rate.

Data sources: Unemployment data from U.S. Bureau of Labor Statistics. Shapefile from U.S. Census Bureau, cleaned up with QGIS, simplified with mapshaper.org. Color palette from ColorBrewer

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Neighboring Geography Selection</title>
<style>
body {
font: 9px sans-serif;
}
.county {
stroke: slategrey;
stroke-width: 1px;
}
.bar {
stroke: lightgrey;
stroke-width: .5px;
}
.q-0 { fill: #f7f7f7; }
.q-1 { fill: #d9d9d9; }
.q-2 { fill: #bdbdbd; }
.q-3 { fill: #969696; }
.q-4 { fill: #636363; }
.q-5 { fill: #252525; }
.hovered {
webkit-transition: 250ms;
-moz-transition: 250ms;
-o-transition: 250ms;
transition: 250ms;
fill: red;
font-weight: bold;
}
.neighbor {
webkit-transition: 250ms;
-moz-transition: 250ms;
-o-transition: 250ms;
transition: 250ms;
fill: rgb(255, 129, 129);
font-weight: bold;
}
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis path {
display: none;
}
svg {
position: absolute;
}
.map {
left: 300px;
}
</style>
</head>
<body>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.19/topojson.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/queue-async/1.0.7/queue.min.js"></script>
<script>
var margin = {top: 10, left: 70, bottom: 40, right: 20},
width = 960/2 - margin.left - margin.right,
height = 700 - margin.top - margin.bottom;
var projection = d3.geo.conicConformal()
.rotate([90, 0])
.center([.2, 44.75])
.parallels([29.5, 45.5])
.scale(6000)
.translate([
(width + margin.left + margin.right) / 2,
(height + margin.top + margin.bottom) / 2
])
.precision(.1);
var path = d3.geo.path()
.projection(projection);
var scale = {
x: d3.scale.linear().range([0, width]),
y: d3.scale.ordinal().rangeBands([height, 0], .1),
color: d3.scale.quantize()
.range(d3.range(6))
};
var axis = {
x: d3.svg.axis().scale(scale.x).orient("bottom"),
y: d3.svg.axis().scale(scale.y).orient("left")
};
var chart = d3.select("body").append("svg")
.attr("class", "chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var map = d3.select("body").append("svg")
.attr("class", "map")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")");
chart.append("g")
.attr("class", "y axis");
d3.json("wi.json", ready)
function ready(error, wi) {
if (error) throw error;
var countyData = cleanData(wi);
scale.x.domain([0, d3.max(countyData, function(d) { return d.unemployment_rate; })]);
scale.y.domain(countyData.map(function(d) { return d.name; }));
scale.color.domain(d3.extent(countyData, function(d) { return d.unemployment_rate; }));
// Draw map
var counties = map.selectAll(".county").data(countyData)
.enter().append("path")
.attr("class", function(d) { return "county q-" + scale.color(d.unemployment_rate); })
.attr("d", path)
.on("mouseenter", mouseenter)
.on("mouseleave", mouseleave);
// Draw bar chart
var bars = chart.selectAll(".bar").data(countyData)
.enter().append("rect")
.attr("x", function(d) { return scale.x(0); })
.attr("y", function(d) { return scale.y(d.name); })
.attr("width", function(d) { return scale.x(d.unemployment_rate); })
.attr("height", function(d) { return scale.y.rangeBand(); })
.attr("class", function(d) { return "bar q-" + scale.color(d.unemployment_rate); })
.on("mouseenter", mouseenter)
.on("mouseleave", mouseleave);
var labels = chart.selectAll(".label").data(countyData)
.enter().append("text")
.attr("x", function(d) { return scale.x(d.unemployment_rate); })
.attr("y", function(d) { return scale.y(d.name); })
.attr("dx", 3)
.attr("dy", 7)
.style("text-anchor", "start")
.text(function(d) { return d.unemployment_rate; });
chart.select(".x.axis")
.call(axis.x)
.append("text")
.attr("x", width)
.attr("y", 30)
.style("text-anchor", "end")
.text("Unemployment Rate (%)");
chart.select(".y.axis")
.call(axis.y);
function mouseenter(hovered) {
counties
.classed("hovered", function(d) { return d === hovered; })
.classed("neighbor", function(d) { return hovered.neighbors.indexOf(d) !== -1; });
bars
.classed("hovered", function(d) { return d === hovered; })
.classed("neighbor", function(d) { return hovered.neighbors.indexOf(d) !== -1; });
labels
.classed("hovered", function(d) { return d === hovered; })
.classed("neighbor", function(d) { return hovered.neighbors.indexOf(d) !== -1; });
chart.select(".y.axis").selectAll("g")
.classed("hovered", function(name) { return name === hovered.name; })
.classed("neighbor", function(name) {
return hovered.neighbors
.filter(function(d) { return d.name === name; }).length > 0;
});
}
function mouseleave() {
counties
.classed("hovered", false)
.classed("neighbor", false);
bars
.classed("hovered", false)
.classed("neighbor", false);
labels
.classed("hovered", false)
.classed("neighbor", false);
chart.select(".y.axis").selectAll("g")
.classed("hovered", false)
.classed("neighbor", false);
}
}
function cleanData(wi) {
var features = topojson.feature(wi, wi.objects.wi).features,
neighbors = topojson.neighbors(wi.objects.wi.geometries),
countyData = features
.map(function(d,i) {
d.neighbors = features.filter(function(d1, i1) {
return neighbors[i].indexOf(i1) !== -1;
});
d.unemployment_rate = +d.properties["wi-data__2"];
d.name = d.properties.NAME;
return d;
})
.sort(function(a, b) {
return b.unemployment_rate - a.unemployment_rate;
});
return countyData;
}
d3.select(self.frameElement)
.style("width", 800 + "px")
.style("height", (height + margin.top + margin.bottom) + "px");
</script>
</body>
</html>
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment