Created
June 24, 2012 22:39
-
-
Save zmaril/2985338 to your computer and use it in GitHub Desktop.
Animated Bubble Chart
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
var BubbleChart, root, | |
__bind = function(fn, me){ | |
return function() | |
{ return fn.apply(me, arguments); | |
}; | |
}; | |
BubbleChart = (function() { | |
BubbleChart.name = 'BubbleChart'; | |
function BubbleChart(data) { | |
this.hide_details = __bind(this.hide_details, this); | |
this.show_details = __bind(this.show_details, this); | |
this.move_to_center = __bind(this.move_to_center, this); | |
this.display_layout = __bind(this.display_layout, this); | |
this.start = __bind(this.start, this); | |
this.create_chart = __bind(this.create_chart, this); | |
this.create_nodes = __bind(this.create_nodes, this); | |
this.year1_filter = __bind(this.year1_filter, this); | |
this.year2_filter = __bind(this.year2_filter, this); | |
this.year3_filter = __bind(this.year3_filter, this); | |
this.year4_filter = __bind(this.year4_filter, this); | |
this.year5_filter = __bind(this.year5_filter, this); | |
this.redraw_year = __bind(this.redraw_year, this); | |
this.data = data; | |
this.width = 940; | |
this.height = 500; | |
this.tooltip = CustomTooltip("tooltip", 190); | |
this.center = { | |
x: this.width / 2, | |
y: this.height / 2 | |
}; | |
this.layout_gravity = -0.01; | |
this.damper = 0.1; | |
this.vis = null; | |
this.nodes = []; | |
this.force = null; | |
this.circles = null; | |
this.fill_color = d3.scale.ordinal().domain(["low", "medium", "high"]).range(["#d9e3ec", "#e1bebc", "#dbe9b9"]); | |
//use the max total_amount in the data as the max in the scale's domain | |
var max_size = d3.max(this.data, function(d) { | |
return parseInt(d.total_trade); | |
}); | |
this.radius_scale = d3.scale.pow().exponent(0.5).domain([0, max_size]).range([1, 90]); | |
this.create_nodes(); | |
this.create_chart(); | |
}; | |
//create node objects that will serve as the data behind each bubble | |
BubbleChart.prototype.create_nodes = function() { | |
var _this = this; | |
this.data.forEach(function(d) { | |
var node; | |
node = { | |
id:d.id, | |
region:d.region, | |
radius: _this.radius_scale(parseInt(d.total_trade)), | |
value: d.total_trade, | |
importsto: d.imports_to, | |
exportsfrom: d.exports_from, | |
tbalance: d.trade_balance, | |
group: d.group, | |
year: d.year, | |
x: Math.random() * 900, | |
y: Math.random() * 800, | |
}; | |
return _this.nodes.push(node); | |
}); | |
return this.nodes.sort(function(a, b) { | |
return b.value - a.value; | |
}); | |
}; | |
//create svg and then circle representation for each node | |
BubbleChart.prototype.create_chart = function() { | |
var that, _this = this; | |
this.vis = d3.select("#vis") | |
.append("svg") | |
.attr("width", this.width) | |
.attr("height", this.height) | |
.attr("id", "svg_vis"); | |
/*not working! | |
var nest = d3.nest() | |
.key(function(d) { return d.region; }) | |
.key(function(d) { return d.country; }) | |
.entries(csv);*/ | |
this.circles = this.vis.selectAll("circle").data(this.nodes, function(d) {return d.id;}); | |
that = this; | |
this.circles.enter() | |
.append("circle") | |
//.attr("r", 0) | |
.attr("opacity", 0.9) | |
.attr("fill", __bind(function(d) {return this.fill_color(d.group);}, this)) | |
.attr("stroke-width", 2).attr("stroke", __bind(function(d) {return d3.rgb(this.fill_color(d.group)).darker();}, this)) | |
.attr("id", function(d) {return "bubble_" + d.id;}) | |
.on("mouseover", function(d, i) {return that.show_details(d, i, this);}) | |
.on("mouseout", function(d, i) {return that.hide_details(d, i, this);}) | |
.on("click", function(d, i) { alert("Do something"); }); | |
return this.circles.transition() | |
.duration(1000) | |
.attr("r", function(d) {return d.radius;}); | |
}; | |
BubbleChart.prototype.year1_filter = function() { | |
var that, _this = this; | |
this.circles = this.vis.selectAll("circle").data(this.nodes.filter(function(d){return d.year == 2010;})); | |
return this.redraw_year(); | |
}; | |
BubbleChart.prototype.year2_filter = function() { | |
var that, _this = this; | |
this.circles = this.vis.selectAll("circle").data(this.nodes.filter(function(d){return d.year == 2009;})); | |
return this.redraw_year(); | |
}; | |
BubbleChart.prototype.year3_filter = function() { | |
var that, _this = this; | |
this.circles = this.vis.selectAll("circle").data(this.nodes.filter(function(d){return d.year == 2008;})); | |
return this.redraw_year(); | |
}; | |
BubbleChart.prototype.year4_filter = function() { | |
var that, _this = this; | |
this.circles = this.vis.selectAll("circle").data(this.nodes.filter(function(d){return d.year == 2007;})); | |
return this.redraw_year(); | |
}; | |
BubbleChart.prototype.year5_filter = function() { | |
var that, _this = this; | |
this.circles = this.vis.selectAll("circle").data(this.nodes.filter(function(d){return d.year == 2006;})); | |
return this.redraw_year(); | |
}; | |
BubbleChart.prototype.redraw_year = function(){ | |
var that, _this = this; | |
that = this; | |
//new circles enter | |
this.circles.enter().append("circle") | |
.attr("r", 0) | |
.attr("opacity", 0.9) | |
.attr("fill", __bind(function(d) {return this.fill_color(d.group);}, this)) | |
.attr("stroke-width", 2).attr("stroke", __bind(function(d) {return d3.rgb(this.fill_color(d.group)).darker();}, this)) | |
.attr("id", function(d) {return "bubble_" + d.id;}) | |
.on("mouseover", function(d, i) {return that.show_details(d, i, this);}) | |
.on("mouseout", function(d, i) {return that.hide_details(d, i, this);}) | |
.attr("r", function(d) {return d.radius;}); | |
//update existing circles | |
this.circles | |
.attr("r", 0) | |
.attr("opacity", 0.9) | |
.attr("fill", __bind(function(d) {return this.fill_color(d.group);}, this)) | |
.attr("stroke-width", 2).attr("stroke", __bind(function(d) {return d3.rgb(this.fill_color(d.group)).darker();}, this)) | |
.attr("id", function(d) {return "bubble_" + d.id;}) | |
.on("mouseover", function(d, i) {return that.show_details(d, i, this);}) | |
.on("mouseout", function(d, i) {return that.hide_details(d, i, this);}) | |
.attr("r", function(d) {return d.radius;}) | |
.transition().duration(300); | |
//exit | |
this.circles.exit().transition().duration(300).remove(); | |
return this.display_layout(); | |
}; | |
//Charge function to allow for accurate collision detection with nodes of different sizes | |
BubbleChart.prototype.charge = function(d) { | |
return -Math.pow(d.radius, 2.0)/ 8; | |
}; | |
//Starts up the force layout with default values | |
BubbleChart.prototype.start = function() { | |
return this.force = d3.layout.force().nodes(this.nodes).size([this.width, this.height]); | |
}; | |
//Sets up force layout to display all nodes in one circle | |
BubbleChart.prototype.display_layout = function() { | |
this.force.gravity(this.layout_gravity).charge(this.charge).friction(0.9).on("tick", __bind(function(e) { | |
return this.circles.each(this.move_to_center(e.alpha)).attr("cx", function(d) { | |
return d.x; | |
}).attr("cy", function(d) { | |
return d.y; | |
}); | |
}, this)); | |
this.force.start(); | |
}; | |
//Moves all circles towards the the center of the visualization | |
BubbleChart.prototype.move_to_center = function(alpha) { | |
return __bind(function(d) { | |
d.x = d.x + (this.center.x - d.x) * (this.damper + 0.02) * alpha; | |
return d.y = d.y + (this.center.y - d.y) * (this.damper + 0.02) * alpha; | |
}, this); | |
}; | |
//Show tooltip | |
BubbleChart.prototype.show_details = function(data, i, element) { | |
var content; | |
d3.select(element).attr("stroke", "#42464a"); | |
content = "<span class=\"title\"><span class=\"value\"> " + data.region + "</span></span><br/></br>"; | |
content += "<span class=\"name\">Imports:</span><span class=\"value\"> $" + (addCommas(data.importsto)) + "</span><br/>"; | |
content += "<span class=\"name\">Exports:</span><span class=\"value\"> $" + (addCommas(data.exportsfrom)) + "</span><br/></br>"; | |
content += "<span class=\"name\">Year:</span><span class=\"value\"> " + data.year + "</span>"; | |
return this.tooltip.showTooltip(content, d3.event); | |
}; | |
//Hide tooltip | |
BubbleChart.prototype.hide_details = function(data, i, element) | |
{ | |
var _this = this; | |
d3.select(element).attr("stroke", function(d) | |
{ | |
return d3.rgb(_this.fill_color(d.group)).darker(); | |
}); | |
return this.tooltip.hideTooltip(); | |
}; | |
return BubbleChart; | |
})(); | |
root = typeof exports !== "undefined" && exports !== null ? exports : this; | |
$(function() { | |
var chart, render_chart, render_vis; | |
chart = null; | |
render_vis = function(csv) { | |
return render_chart(csv); | |
}; | |
render_chart = function(csv) { | |
chart = new BubbleChart(csv); | |
chart.start(); | |
return root.display_layout(); | |
}; | |
root.display_layout = __bind(function() { | |
return chart.display_layout(); | |
}, this); | |
root.year1_filter = __bind(function() { | |
return chart.year1_filter(); | |
}, this); | |
root.year2_filter = __bind(function() { | |
return chart.year2_filter(); | |
}, this); | |
root.year3_filter = __bind(function() { | |
return chart.year3_filter(); | |
}, this); | |
root.year4_filter = __bind(function() { | |
return chart.year4_filter(); | |
}, this); | |
root.year5_filter = __bind(function() { | |
return chart.year5_filter(); | |
}, this); | |
root.toggle_view = __bind(function(view_type) { | |
if(view_type == 2009) | |
{ | |
return root.year2_filter(); | |
} | |
else if(view_type == 2008) | |
{ | |
return root.year3_filter(); | |
} | |
else if(view_type == 2007) | |
{ | |
return root.year4_filter(); | |
} | |
else if(view_type == 2006) | |
{ | |
return root.year5_filter(); | |
} | |
else | |
{ | |
return root.year1_filter(); | |
} | |
}, this); | |
return d3.csv("data/TradeRegion1.csv", render_vis); | |
}); |
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> | |
<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | |
<title>US FOREIGN TRADE</title> | |
<meta name="viewport" content="width=device-width,initial-scale=1"> | |
</head> | |
<body> | |
<section id="wrapper"> | |
<header> US Foreign Trade</header> | |
<section> | |
<nav id="year_selection"> | |
<a href ="#" id="2010" class="btn active">2010</a> | |
<a href ="#" id="2009" class="btn">2009</a> | |
<a href ="#" id="2008" class="btn">2008</a> | |
<a href ="#" id="2007" class="btn" >2007</a> | |
<a href ="#" id="2006" class="btn" >2006</a> | |
</nav> | |
</section> | |
<section id="information"> | |
<p>Values are in millions of dollars.</p> | |
<p>All values are not seasonally adjusted except: | |
0004 World (seasonally adjusted)</p> | |
<p>Country codes beginning with the number 0 (zero) are unofficial country | |
codes created by the Foreign Trade Division for organizational use only. | |
These codes are not valid for reporting or statistical purposes. </p> | |
<p> | |
<section id="keys"></section> | |
</section> | |
<section id="vis"></section> | |
</section> | |
<footer> | |
<p>SOURCE - U.S. Department of Commerce, Bureau of the Census, Foreign Trade | |
Division. </p> | |
<p> For more information, contact Matthew Przybocki (301-763-3148) | |
or Maria Iseman (301-763-2311), Foreign Trade Division.</p> | |
</footer> | |
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script> | |
<script src="http://d3js.org/d3.v2.min.js"></script> | |
<script src="BubbleChart.js"></script> | |
<script type="text/javascript"> | |
$(document).ready(function() { | |
$(document).ready(function() { | |
$('#year_selection a').click(function() { | |
var view_type = $(this).attr("id"); | |
$('#year_selection a').removeClass('active'); | |
$(this).toggleClass('active'); | |
toggle_view(view_type); | |
return false; | |
}); | |
}); | |
}); | |
</script> | |
</body> | |
</html> |
We can make this file beautiful and searchable if this error is corrected: It looks like row 2 should actually have 1 column, instead of 2 in line 1.
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
region id imports_to exports_from total_trade group trade_balance year | |
Australia and Oceania 1 11777.7 25312.1 37089.8 medium 13,534.40 2010 | |
Australia and Oceania 2 10921.3 22415.5 33336.8 medium 11,494.10 2009 | |
Australia and Oceania 3 14196.9 25367.1 39564 medium 11,170.20 2008 | |
Australia and Oceania 4 12177.2 22385.6 34562.8 medium 10,208.30 2007 | |
Australia and Oceania 5 11701.7 20740.8 32442.5 medium 9,039.20 2006 | |
Caribbean 6 13214.6 21344.2 34558.8 medium 8,129.50 2010 | |
Caribbean 7 12263.9 17695.3 29959.2 medium 5,431.30 2009 | |
Caribbean 8 18970.6 23104.8 42075.4 medium 4,134.20 2008 | |
Caribbean 9 18734.6 19238.2 37972.7 medium 503.6 2007 | |
Caribbean 10 18567.4 16916.8 35484.1 medium -1,650.60 2006 | |
Central America 11 20559.2 24667.3 45226.4 medium 4,108.10 2010 | |
Central America 12 15927.5 20028.5 35956.1 medium 4,101.00 2009 | |
Central America 13 16046.7 24862.1 40908.8 medium 8,815.40 2008 | |
Central America 14 15020.7 20873.3 35894 medium 5,852.70 2007 | |
Central America 15 14588.5 17767.8 32356.3 medium 3,179.40 2006 | |
Eastern Africa 16 1116.2 2147.2 3263.4 low 1,031.00 2010 | |
Eastern Africa 17 1072.3 2045.4 3117.6 low 973.1 2009 | |
Eastern Africa 18 1386.4 1841 3227.4 low 454.6 2008 | |
Eastern Africa 19 1231.8 1490.1 2722 low 258.3 2007 | |
Eastern Africa 20 1232.8 1178.4 2411.1 low -54.4 2006 | |
Eastern Asia 21 463578. 189029.5 652607.7 high -274,548.60 2009 | |
Eastern Asia 23 568881.5 216384.3 785265.8 high -352,497.20 2008 | |
Eastern Asia 24 560950.7 204482.7 765433.4 high -356,468.00 2007 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment