Built with blockbuilder.org
xxxxxxxxxx
<meta charset="utf-8">
<title>Contigious States of US</title>
<style>
.background {
fill: #eee;
}
line {
stroke: #fff;
}
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
text.active {
fill: red;
font-size: 120%;
font-style: bold;
}
</style>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<h1>Contiguous States of US</h1>
<h2>CS 725 Information Visualization - V7</h2>
<h3>Christos Tsolakis</h3>
<p>Order:
<select id="order">
<option value="name">Alphabetically</option>
<option value="count">by number of contiguous neighbors</option>
</select>
<p> Show also paths of length 2 : <input id="CBOX" type="checkbox" checked>
<script>
var margin = {top: 80, right: 0, bottom: 10, left: 33},
width = 720,
height = 720;
var x = d3.scale.ordinal().rangeBands([0, width]),
z = d3.scale.linear().domain([0, 2])
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("margin-left", +margin.left + "px")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.json("states.json", function(states) {
matrix =[];
nodes = states.nodes,
n = nodes.length;
// Compute index per node.
nodes.forEach(function(node, i) {
node.index = i;
node.count = 0;
matrix[i] = d3.range(n).map(function(j) { return {x: j, y: i, z: 0}; });
});
//connect all contiguous states
var connect = function(link) {
matrix[link.source][link.target].z = 1;
matrix[link.target][link.source].z = 1;
//needed for sorting
nodes[link.source].count += link.value;
nodes[link.target].count += link.value;
}
var connect_2_paths = function(link) {
states.links.forEach(function(item){
if(item.source == link.source && item.target != link.target )
{
if(matrix[item.target][link.target].z!=1)
{
matrix[item.target][link.target].z = 2;
matrix[link.target][item.target].z = 2;
}
}
else if(item.target == link.target && item.source!= link.source )
{
if(matrix[item.source][link.source].z!=1)
{
matrix[item.source][link.source].z = 2;
matrix[link.source][item.source].z = 2;
}
}
else if(item.source == link.target && item.target != link.source)
{
if(matrix[item.target][link.source].z!=1)
{
matrix[item.target][link.source].z = 2;
matrix[link.source][item.target].z = 2;
}
}
else if(item.target == link.source && item.source != link.target)
{
if(matrix[item.source][link.target].z!=1)
{
matrix[item.source][link.target].z = 2;
matrix[link.target][item.source].z = 2;
}
}
})
};
//connect adjacent states
states.links.forEach(connect);
//create 2-paths
states.links.forEach(connect_2_paths);
// Precompute the orders.
var orders = {
name: d3.range(n).sort(function(a, b)
{ return d3.ascending(nodes[a].name, nodes[b].name); }),
count: d3.range(n).sort(function(a, b)
{ return nodes[b].count - nodes[a].count; }),
};
// The default sort order.
x.domain(orders.name);
svg.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height);
var row = svg.selectAll(".row")
.data(matrix)
.enter().append("g")
.attr("class", "row")
.attr("transform", function(d, i) { return "translate(0," + x(i) + ")"; })
.each(row);
row.append("line")
.attr("x2", width);
row.append("text")
.attr("x", -6)
.attr("y", x.rangeBand() / 2)
.attr("dy", ".32em")
.attr("text-anchor", "end")
.text(function(d, i) { return nodes[i].name; });
var column = svg.selectAll(".column")
.data(matrix)
.enter().append("g")
.attr("class", "column")
.attr("transform", function(d, i) { return "translate(" + x(i) + ")rotate(-90)"; });
column.append("line")
.attr("x1", -width);
column.append("text")
.attr("x", 6)
.attr("y", x.rangeBand() / 2)
.attr("dy", ".32em")
.attr("text-anchor", "start")
.text(function(d, i) { return nodes[i].name; });
function row(row) {
var cell = d3.select(this).selectAll(".cell")
.data(row.filter(function(d) { return d.z; }))
.enter().append("rect")
.attr("class", "cell")
.attr("x", function(d) { return x(d.x); })
.attr("width", x.rangeBand())
.attr("height", x.rangeBand())
.style("fill-opacity", function(d) { return z(d.z); })
.style("fill", "blue")
.on("mouseover", mouseover)
.on("mouseout", mouseout);
}
function mouseover(p) {
d3.selectAll(".row text").classed("active", function(d, i) { return i == p.y; });
d3.selectAll(".column text").classed("active", function(d, i) { return i == p.x; });
}
function mouseout() {
d3.selectAll("text").classed("active", false);
}
d3.select("#CBOX").on("change",function(){
if(!this.checked)
{
svg.selectAll(".row")
.selectAll(".cell")
.style("fill-opacity",function(d) {
if(d.z>1)
return 0;
return z(d.z)
})
}
else{
svg.selectAll(".row")
.selectAll(".cell")
.style("fill-opacity",function(d) { return z(d.z)})
}
});
d3.select("#order").on("change", function() {
order(this.value);
});
function order(value) {
x.domain(orders[value]);
var t = svg.transition().duration(2500);
t.selectAll(".row")
.delay(function(d, i) { return x(i) * 4; })
.attr("transform", function(d, i) { return "translate(0," + x(i) + ")"; })
.selectAll(".cell")
.delay(function(d) { return x(d.x) * 4; })
.attr("x", function(d) { return x(d.x); })
t.selectAll(".column")
.delay(function(d, i) { return x(i) * 4; })
.attr("transform", function(d, i) { return "translate(" + x(i) + ")rotate(-90)"; });
}
});
</script>
<h3> Comments : </h3>
<ol>
<li>Querying for the existence of a specific path of length 1 is easy, e.g
TX (Texas) is contiguous with (AR) Arkansas </li>
<ul>
<li>However, it is difficult to find paths of length more than one
between states e.g. Is there any path of contiguous
states from Washington to Virginia ? </li>
</ul>
<li>The rearranging capabilities of the matrix make the task of finding which
states have more contiguous neighbors than others easier than the node link
diagram</li>
</ol>
<hr>
<hr>
<h3>Node-link Diagram </h3>
<script>
var width2 = 960,
height2 = 700;
var force = d3.layout.force()
.charge(-220)
.linkDistance(20)
.size([width2, height2]);
var svg2 = d3.select("body").append("svg")
.attr("width", width2)
.attr("height", height2)
.attr("transform","translate(" + 0 +"," + 700 +")")
d3.json("states.json", function(error, graph) {
if (error) throw error;
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg2.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var node = svg2.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 8)
// .style("fill", function(d) { return color(d.group); })
.call(force.drag);
node.append("title")
.text(function(d) { return d.name; });
force.on("tick", function() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
});
</script>
<h3> Comments : </h3>
<p> If someone wants to travel through all the states he/she
has to go through New-York (NY) since it is the connecting <br>
link between VT (Vermont), MA (Massachusetts), CT, VI (Virgin Islands),
RI (Rhode Island), ME (Maine), NH (New Hampshire) and the rest of US <br>
ME (Maine) is the only state that it is accessible through only one
state.
<br>
FL (Florida),SC (South Carolina),DC and WA (Washington) are accessible
only by two states, you can easily see that since they are on the boundary
<br>
of the graph and connected only with two other states.
<br>
Moreover one of the advantages here using the node-link is that it is very
easy to derive a route between states.
<br>
So, every topological/connectivity-related attribute can be easily acquired.
<p> Matrix code is heavily based on : <i><a href="https://bost.ocks.org/mike/miserables
">https://bost.ocks.org/mike/miserables</a></i>
<p> Node-link code is heavily based on : <i><a href="https://bl.ocks.org/mbostock/4062045">https://bl.ocks.org/mbostock/4062045</a></i>
<footer>
<aside>March 16, 2016</aside>
</footer>
https://d3js.org/d3.v3.min.js