A tree visualization of the hierarchy of countries in the World using tabular data.
Inspired by Curran Kelleher's World Countries Hierarchy and Avra Goldman's how i met my friends. I applied a streamlined data model and leveraged new d3 v4 functions (to minimize calculations, concatenation, and complexity).
Changes:
Data from the United Nations Place Hierarchy.
--David
xxxxxxxxxx
<meta charset='utf-8'>
<head>
<title>Simple Radial Tree (d3 v4; CSV; 63 Lines)</title>
<script src="https://d3js.org/d3.v4.js"></script>
<link href="//fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css">
</head>
<style>
html {
background-color: black;
}
.glow { /* This trick adds a heavy white shadow around the text. */
text-shadow:
-1px -1px 3px black,
-1px 1px 3px black,
1px -1px 3px black,
1px 1px 3px black;
}
text {
font-family: "Open Sans", sans-serif;
pointer-events: none;
alignment-baseline: central;
fill: white;
}
path {
fill: none;
stroke: white; /* #4fb9b5; */
}
</style>
<svg>
<g></g>
</svg>
<script>
var vWidth = 900;
var vHeight = 800;
var vFontSize = [6,10,18,22];
var vColor = d3.scaleOrdinal().domain(["Oceania", "Africa", "Europe", "Latin America", "Asia"])
.range(["#ff6698", "#ffb366", "#ffff66", "#98ff66", "#6698ff"]);
// .range(["#fb5454", "#f1fb54", "#54befb"]);
// Prepare our physical space
var g = d3.select('svg').attr('width', vWidth).attr('height', vHeight)
.select('g').attr('transform', 'translate(' + vWidth/2 + ',' + vHeight/2 + ')');
// Get the data from our CSV file
d3.csv('country-hierarchy.csv', function(error, vCsvData) {
if (error) throw error;
vData = d3.stratify()(vCsvData);
drawViz(vData);
});
function drawViz(vData) {
vData.each( function(d){
switch (d.depth) {
case 1: d.data.leg = d.id; break;
case 2: d.data.leg = d.parent.id; break;
case 3: d.data.leg = d.parent.parent.id; break;
}});
// Declare d3 layout
var vLayout = d3.cluster().size([2 * Math.PI, Math.min(vWidth, vHeight)/2 - 130]); // margin!
// Layout + Data
var vRoot = d3.hierarchy(vData);
var vNodes = vRoot.descendants();
var vLinks = vLayout(vRoot).links();
// Draw on screen
g.selectAll('path').data(vLinks).enter().append('path')
.attr('d', d3.linkRadial()
.angle(function (d) { return d.x; })
.radius(function (d) { return d.y; }));
var node = g.selectAll(".node").data(vNodes).enter().append('g')
.attr('transform', function(d) { return "translate(" + d3.pointRadial(d.x, d.y) + ")"; });
node.append("text")
.text(function (d){ return d.data.data.id; })
.attr("font-size", function (d){ return vFontSize[d.height] + "pt"; })
.attr("transform", function(d) { return "rotate(" + textRotation(d) + ")" })
.attr("text-anchor", function (d){
if(d.height === 0){ return (d.x > Math.PI) ? "end" : "start"; }
else { return "middle"; } })
.attr("dx", function (d){
if(d.depth === 3){ return (d.x > Math.PI) ? "-2px" : "2px"; }
else { return "0px"; } })
.style("fill", function(d){
//if(d.data.data.least_devd_country === "Yes") { return "blue";}
//else if (d.data.data.devd_region === "Yes") { return "green";}
return vColor(d.data.data.leg);
})
.classed("glow", function (d){ return d.height !== 0; });
function textRotation(d) {
var angle = d.x / Math.PI * 180 + 90;
if (d.depth < 2) { return 0;}
else if (angle <= 270) { return angle - 180;}
else { return angle;}
}
}
</script>
https://d3js.org/d3.v4.js