Built with blockbuilder.org
Live at http://bl.ocks.org/ChristosT/raw/31f947147d5191a179fb/
Built with blockbuilder.org
Live at http://bl.ocks.org/ChristosT/raw/31f947147d5191a179fb/
| <!DOCTYPE html> | |
| <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="http://bl.ocks.org/mbostock/4062045">http://bl.ocks.org/mbostock/4062045</a></i> | |
| <footer> | |
| <aside>March 16, 2016</aside> | |
| </footer> |
| { | |
| "nodes":[ | |
| {"name": "AL" }, | |
| {"name": "AR" }, | |
| {"name": "AZ" }, | |
| {"name": "CA" }, | |
| {"name": "CO" }, | |
| {"name": "CT" }, | |
| {"name": "DC" }, | |
| {"name": "DE" }, | |
| {"name": "FL" }, | |
| {"name": "GA" }, | |
| {"name": "IA" }, | |
| {"name": "ID" }, | |
| {"name": "IL" }, | |
| {"name": "IN" }, | |
| {"name": "KS" }, | |
| {"name": "KY" }, | |
| {"name": "LA" }, | |
| {"name": "MA" }, | |
| {"name": "MD" }, | |
| {"name": "ME" }, | |
| {"name": "MI" }, | |
| {"name": "MN" }, | |
| {"name": "MO" }, | |
| {"name": "MS" }, | |
| {"name": "MT" }, | |
| {"name": "NC" }, | |
| {"name": "ND" }, | |
| {"name": "NE" }, | |
| {"name": "NH" }, | |
| {"name": "NJ" }, | |
| {"name": "NM" }, | |
| {"name": "NV" }, | |
| {"name": "NY" }, | |
| {"name": "OH" }, | |
| {"name": "OK" }, | |
| {"name": "OR" }, | |
| {"name": "PA" }, | |
| {"name": "RI" }, | |
| {"name": "SC" }, | |
| {"name": "SD" }, | |
| {"name": "TN" }, | |
| {"name": "TX" }, | |
| {"name": "UT" }, | |
| {"name": "VA" }, | |
| {"name": "VT" }, | |
| {"name": "WA" }, | |
| {"name": "WI" }, | |
| {"name": "WV" }, | |
| {"name": "WY" } | |
| ], | |
| "links":[ | |
| {"source":0,"target":8,"value":1}, | |
| {"source":0,"target":9,"value":1}, | |
| {"source":0,"target":23,"value":1}, | |
| {"source":0,"target":40,"value":1}, | |
| {"source":1,"target":16,"value":1}, | |
| {"source":1,"target":22,"value":1}, | |
| {"source":1,"target":23,"value":1}, | |
| {"source":1,"target":34,"value":1}, | |
| {"source":1,"target":40,"value":1}, | |
| {"source":1,"target":41,"value":1}, | |
| {"source":2,"target":3,"value":1}, | |
| {"source":2,"target":30,"value":1}, | |
| {"source":2,"target":31,"value":1}, | |
| {"source":2,"target":42,"value":1}, | |
| {"source":3,"target":31,"value":1}, | |
| {"source":3,"target":35,"value":1}, | |
| {"source":4,"target":14,"value":1}, | |
| {"source":4,"target":27,"value":1}, | |
| {"source":4,"target":30,"value":1}, | |
| {"source":4,"target":34,"value":1}, | |
| {"source":4,"target":42,"value":1}, | |
| {"source":4,"target":48,"value":1}, | |
| {"source":5,"target":17,"value":1}, | |
| {"source":5,"target":32,"value":1}, | |
| {"source":5,"target":37,"value":1}, | |
| {"source":6,"target":18,"value":1}, | |
| {"source":6,"target":43,"value":1}, | |
| {"source":7,"target":18,"value":1}, | |
| {"source":7,"target":29,"value":1}, | |
| {"source":7,"target":36,"value":1}, | |
| {"source":8,"target":9,"value":1}, | |
| {"source":9,"target":25,"value":1}, | |
| {"source":9,"target":38,"value":1}, | |
| {"source":9,"target":40,"value":1}, | |
| {"source":10,"target":12,"value":1}, | |
| {"source":10,"target":21,"value":1}, | |
| {"source":10,"target":22,"value":1}, | |
| {"source":10,"target":27,"value":1}, | |
| {"source":10,"target":39,"value":1}, | |
| {"source":10,"target":46,"value":1}, | |
| {"source":11,"target":24,"value":1}, | |
| {"source":11,"target":31,"value":1}, | |
| {"source":11,"target":35,"value":1}, | |
| {"source":11,"target":42,"value":1}, | |
| {"source":11,"target":45,"value":1}, | |
| {"source":11,"target":48,"value":1}, | |
| {"source":12,"target":13,"value":1}, | |
| {"source":12,"target":15,"value":1}, | |
| {"source":12,"target":22,"value":1}, | |
| {"source":12,"target":46,"value":1}, | |
| {"source":13,"target":15,"value":1}, | |
| {"source":13,"target":20,"value":1}, | |
| {"source":13,"target":33,"value":1}, | |
| {"source":14,"target":22,"value":1}, | |
| {"source":14,"target":27,"value":1}, | |
| {"source":14,"target":34,"value":1}, | |
| {"source":15,"target":22,"value":1}, | |
| {"source":15,"target":33,"value":1}, | |
| {"source":15,"target":40,"value":1}, | |
| {"source":15,"target":43,"value":1}, | |
| {"source":15,"target":47,"value":1}, | |
| {"source":16,"target":23,"value":1}, | |
| {"source":16,"target":41,"value":1}, | |
| {"source":17,"target":28,"value":1}, | |
| {"source":17,"target":32,"value":1}, | |
| {"source":17,"target":37,"value":1}, | |
| {"source":17,"target":44,"value":1}, | |
| {"source":18,"target":36,"value":1}, | |
| {"source":18,"target":43,"value":1}, | |
| {"source":18,"target":47,"value":1}, | |
| {"source":19,"target":28,"value":1}, | |
| {"source":20,"target":33,"value":1}, | |
| {"source":20,"target":46,"value":1}, | |
| {"source":21,"target":26,"value":1}, | |
| {"source":21,"target":39,"value":1}, | |
| {"source":21,"target":46,"value":1}, | |
| {"source":22,"target":27,"value":1}, | |
| {"source":22,"target":34,"value":1}, | |
| {"source":22,"target":40,"value":1}, | |
| {"source":23,"target":40,"value":1}, | |
| {"source":24,"target":26,"value":1}, | |
| {"source":24,"target":39,"value":1}, | |
| {"source":24,"target":48,"value":1}, | |
| {"source":25,"target":38,"value":1}, | |
| {"source":25,"target":40,"value":1}, | |
| {"source":25,"target":43,"value":1}, | |
| {"source":26,"target":39,"value":1}, | |
| {"source":27,"target":39,"value":1}, | |
| {"source":27,"target":48,"value":1}, | |
| {"source":28,"target":44,"value":1}, | |
| {"source":29,"target":32,"value":1}, | |
| {"source":29,"target":36,"value":1}, | |
| {"source":30,"target":34,"value":1}, | |
| {"source":30,"target":41,"value":1}, | |
| {"source":31,"target":35,"value":1}, | |
| {"source":31,"target":42,"value":1}, | |
| {"source":32,"target":36,"value":1}, | |
| {"source":32,"target":44,"value":1}, | |
| {"source":33,"target":36,"value":1}, | |
| {"source":33,"target":47,"value":1}, | |
| {"source":34,"target":41,"value":1}, | |
| {"source":35,"target":45,"value":1}, | |
| {"source":36,"target":47,"value":1}, | |
| {"source":39,"target":48,"value":1}, | |
| {"source":40,"target":43,"value":1}, | |
| {"source":42,"target":48,"value":1}, | |
| {"source":43,"target":47,"value":1} | |
| ] | |
| } |