Skip to content

Instantly share code, notes, and snippets.

@bessiec
Last active November 25, 2016 19:39
Show Gist options
  • Save bessiec/3c882a1b9a137ad2c76006b34d080588 to your computer and use it in GitHub Desktop.
Save bessiec/3c882a1b9a137ad2c76006b34d080588 to your computer and use it in GitHub Desktop.
Chinese Emigration 1990-2010 via D3 Node Tree
{
"name": "Chinese Emigration",
"children":
[
{"name": "Africa",
"children":
[{"name": "Algeria", "arrivals": 759},
{"name": "Botswana", "arrivals": 2790},
{"name": "Cape Verde", "arrivals": 36},
{"name": "Central African Republic", "arrivals": 127},
{"name": "Congo", "arrivals": 686},
{"name": "Egypt", "arrivals": 618},
{"name": "Eritrea", "arrivals": 142},
{"name": "Gabon", "arrivals": 173},
{"name": "Ghana", "arrivals": 206},
{"name": "Guinea", "arrivals": 193},
{"name": "Lesotho", "arrivals": 68},
{"name": "Libya", "arrivals": 1289},
{"name": "Madagascar", "arrivals": 3472},
{"name": "Mali", "arrivals": 62},
{"name": "Mauritania", "arrivals": 279},
{"name": "Mauritius", "arrivals": 26638},
{"name": "Rwanda", "arrivals": 215},
{"name": "Sierra Leone", "arrivals": 354},
{"name": "South Africa", "arrivals": 24292},
{"name": "Sudan", "arrivals": 1747},
{"name": "Uganda", "arrivals": 689},
{"name": "Zambia", "arrivals": 130}
]
},
{"name": "East Asia",
"children":
[{"name": "Hong Kong", "arrivals": 962784},
{"name": "Japan", "arrivals": 441263},
{"name": "Macao", "arrivals": 133544},
{"name": "Mongolia", "arrivals": 8233},
{"name": "North Korea", "arrivals": 35254},
{"name": "South Korea", "arrivals": 476065}
]
},
{"name": "Europe",
"children":
[{"name": "Austria", "arrivals": 15082},
{"name": "Belgium", "arrivals": 10827},
{"name": "Bosnia & Herzegovina", "arrivals": 20},
{"name": "Bulgaria", "arrivals": 1039},
{"name": "Czech Republic", "arrivals": 7587},
{"name": "Denmark", "arrivals": 12225},
{"name": "Finland", "arrivals": 8735},
{"name": "France", "arrivals": 85704},
{"name": "Germany", "arrivals": 88759},
{"name": "Greece", "arrivals": 5303},
{"name": "Hungary", "arrivals": 17074},
{"name": "Iceland", "arrivals": 581},
{"name": "Ireland", "arrivals": 9863},
{"name": "Italy", "arrivals": 105742},
{"name": "Luxembourg", "arrivals": 759},
{"name": "Malta", "arrivals": 261},
{"name": "Netherlands", "arrivals": 52681},
{"name": "Norway", "arrivals": 9863},
{"name": "Poland", "arrivals": 1622},
{"name": "Portugal", "arrivals": 12051},
{"name": "Romania", "arrivals": 4222},
{"name": "Serbia", "arrivals": 423},
{"name": "Slovakia", "arrivals": 875},
{"name": "Slovenia", "arrivals": 976},
{"name": "Spain", "arrivals": 164357},
{"name": "Sweden", "arrivals": 26285},
{"name": "Switzerland", "arrivals": 14142},
{"name": "United Kingdom", "arrivals": 115926}
]
},
{"name": "Former Soviet Union",
"children":
[{"name": "Azerbaijan", "arrivals": 319},
{"name": "Estonia", "arrivals": 136},
{"name": "Georgia", "arrivals": 77},
{"name": "Kazakhstan", "arrivals": 5923},
{"name": "Kyrgyzstan", "arrivals": 154},
{"name": "Latvia", "arrivals": 404},
{"name": "Lithuania", "arrivals": 399},
{"name": "Moldova", "arrivals": 246},
{"name": "Russia", "arrivals": 47149},
{"name": "Turkmenistan", "arrivals": 206},
{"name": "Uzbekistan", "arrivals": 1058}]
},
{"name": "North America",
"children":
[{"name": "Canada", "arrivals": 610187},
{"name": "United States", "arrivals": 1910337}
]
},
{"name": "Oceania",
"children":
[{"name": "Australia", "arrivals": 369893},
{"name": "French Polynesia", "arrivals": 373},
{"name": "Guam", "arrivals": 676},
{"name": "New Caledonia", "arrivals": 87},
{"name": "New Zealand", "arrivals": 101865},
{"name": "Samoa", "arrivals": 11},
{"name": "Tonga", "arrivals": 90}
]
},
{"name": "Southeast Asia",
"children":
[{"name": "Brunei", "arrivals": 248},
{"name": "Cambodia", "arrivals": 3090},
{"name": "Laos", "arrivals": 1991},
{"name": "Myanmar", "arrivals": 11605},
{"name": "Philippines", "arrivals": 20870},
{"name": "Singapore", "arrivals": 120456},
{"name": "Thailand", "arrivals": 64617},
{"name": "Timor-Leste", "arrivals": 876},
{"name": "Vietnam", "arrivals": 7482}
]
},
{"name": "South Asia",
"children":
[{"name": "Bangladesh", "arrivals": 21322},
{"name": "Bhutan", "arrivals": 603},
{"name": "India", "arrivals": 600},
{"name": "Nepal", "arrivals": 14231},
{"name": "Sri Lanka", "arrivals": 48}
]
},
{"name": "Middle East",
"children":
[{"name": "Cyprus", "arrivals": 1591},
{"name": "Israel", "arrivals": 583},
{"name": "Jordan", "arrivals": 6002},
{"name": "Lebanon", "arrivals": 3957},
{"name": "Turkey", "arrivals": 1763}
]
}
]
}
<!DOCTYPE html>
<head>
<title>Chinese Emigration 1990-2010</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.6.7/d3-tip.js"></script>
<link href="https://fonts.googleapis.com/css?family=Raleway" rel="stylesheet">
<style>
body {
margin: 0 5% 5% 5%;
font-family: 'Raleway', sans-serif;
}
text {
fill: #000;
font-family: 'Raleway', sans-serif;
font-size: 18px;
pointer-events: none;
}
.node {
cursor: pointer;
}
.node circle {
stroke: #E80614;
fill: #a6cee3;
stroke-width: 1px
}
.node text {
font-size: 18px;
font-family: 'Raleway', sans-serif;
}
.link {
fill: none;
stroke: #1f78b4;
stroke-width: 2px;
}
.d3-tip {
line-height: 1;
font-weight: bold;
font-family: 'Raleway', sans-serif;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
</style>
</head>
<body>
<h1>Chinese Emigration Destinations 1990-2010</h1>
<h3>Dataset from <a href="http://www.global-migration.info/">THE GLOBAL FLOW OF PEOPLE</a></h3>
<p>Click on the white circles to expand. Click again on the now-filled circle to retract. Hover over circles for more info.</p>
<div id="container">
<script>
var minRadius = 2;
var maxRadius = 25;
var scale = d3.scale.linear()
.domain([1, 2000])
.range([minRadius,maxRadius]);
var margin = {top: 20, right: 10, bottom: 20, left: 180},
width = 1560 - margin.right - margin.left,
height = 1000 - margin.top - margin.bottom;
var i = 0,
duration = 750,
root;
var tree = d3.layout.tree()
.size([height, width]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; }); // converts start and end point so we are going left to right instead of up and down
var svg = d3.select("#container")
.append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var data = d3.json("china_flare.json", function(error, data) {
if (error) throw error;
root = data;
root.x0 = height / 2;
root.y0 = 0;
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
root.children.forEach(collapse);
update(root);
});
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
if (d.arrivals === undefined) {
return "<strong> <span style='color:#a6cee3'>" + d.name
} else if (d.arrivals ===1 ) {
return "<strong> <span style='color:#a6cee3'>" + d.name + ":<span style='color:#E80614'> " + d.arrivals + "</span> conversion</strong>";
} else {
return "<strong> <span style='color:#a6cee3'>" + d.name + ":<span style='color:#E80614'> " + d.arrivals + "</span> arrivals</strong>";}
});
d3.select(self.frameElement).style("height", "800px");
function update(source) {
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 275; });
// Update the nodes…
var node = svg.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", click)
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
nodeEnter.append("circle")
.attr("r", 2)
nodeEnter.append("text")
.attr("x", function(d) { return d.children || d._children ? -15 : 20; })
.attr("dy", ".35em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.attr("class", "text")
.text(function(d) { return d.name; })
.style("fill-opacity", 1);
node.call(tip)
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.select("circle")
.attr("r", function(d) {
if (d.arrivals == undefined)
return 5
else if (d.arrivals > 800000)
return 20
else if (d.arrivals > 500000)
return 15
else if (d.arrivals > 100000)
return 12
else if (d.arrivals > 50000)
return 10
else if (d.arrivals > 5000)
return 8
else
return scale(Math.sqrt(+d.arrivals))
})
.style("fill", function(d) { return d._children ? "fff" : "#0025A9"; });
nodeUpdate.select("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
.remove();
nodeExit.select("circle")
.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// Update the links…
var link = svg.selectAll("path.link")
.data(links, function(d) { return d.target.id; });
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", function(d) {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
// Toggle children on click.
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
</script>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment