Skip to content

Instantly share code, notes, and snippets.

@MLWhiz
Created October 13, 2015 15:03
Show Gist options
  • Save MLWhiz/c2404e17c3cb7b093bbe to your computer and use it in GitHub Desktop.
Save MLWhiz/c2404e17c3cb7b093bbe to your computer and use it in GitHub Desktop.
Polar Area Chart (Game of Thrones)
// data is for seasons 1-3 sourced from http://asoiaf.westeros.org/index.php/topic/94295-a-game-of-screentime/
// colors are assorted by most recent allegiances in season 5
var data_url = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/29725/got.json";
var colors_url = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/29725/house_colors.json";
var data, house_colors;
d3.json(data_url, loadData);
function loadData(json){
//data
data = sortData(json);
d3.json(colors_url, function(colors){
house_colors = colors;
visualize();
window.onresize = function(){
d3.select("svg").remove();
visualize();
};
});
}
function visualize(){
//style
var pad = 10;
var h = window.innerHeight-pad;
var w = window.innerWidth-pad;
var size = 680;
var r = size/8;
var barWidth = w/data.length;
var animTime = 1500;
var radiusScale = d3.scale.sqrt()
.domain([0, d3.max(data, function(d){ return d.episodes })])
.range([0, r*3]);
var colorScale = d3.scale.ordinal()
.domain(arrayFromProperty(house_colors,"family"))
.range(arrayFromProperty(house_colors,"color"));
//bars
var svg = d3.select("body")
.append("svg")
.attr("height", h)
.attr("width", w)
.style("margin", pad/2+"px 0 0 "+pad/2+"px");
var pie = d3.layout.pie()
.value(function(d){ return d.minutes + d.seconds/60; })
.sort(null);
var arc_zero = d3.svg.arc()
.outerRadius(r)
.innerRadius(r);
var arc = d3.svg.arc()
.outerRadius(function(d){ return r + radiusScale(d.data.episodes) })
.innerRadius(r);
var g = svg.append("g")
.attr("transform", "translate("+w/2+","+h/2+") rotate(-180)");
g.transition().duration(animTime)
.attr("transform", "translate("+w/2+","+h/2+")");
var bars = g.selectAll("g")
.data(pie(data)).enter()
.append("g")
.attr("class", "bar")
.attr("id", function(d,i){ return i });
bars.append("path")
.attr("d", arc_zero)
.attr("stroke", "#FFF")
.attr("fill", function(d){ return colorScale(d.data.family) })
.transition().duration(animTime)
.attr("d", arc);
//text info
var circle = g.append("circle")
.attr("fill", "#333")
.attr("r", 1)
.transition().duration(animTime)
.attr("r", r-5);
var title_default = "Game of Thrones";
var title = g.append("text")
.text(title_default)
.attr("xml:space", "preserve")
.attr("text-anchor", "middle")
.attr("font-family", "GameOfThrones, sans-serif")
.attr("font-size", size/70+"px")
.attr("fill", "white");
var subtitle_default = data.length + " Characters' Screen Time";
var subtitle = g.append("text")
.text(subtitle_default)
.attr("xml:space", "preserve")
.attr("text-anchor", "middle")
.attr("font-family", "Lato, sans-serif")
.attr("font-size", size/63+"px")
.attr("fill", "white")
.attr("y", size/40);
var subtitle_family = g.append("text")
.text("")
.attr("xml:space", "preserve")
.attr("text-anchor", "middle")
.attr("font-family", "Lato, sans-serif")
.attr("font-size", size/63+"px")
.attr("fill", "white")
.attr("y", size/10);
bars.on("mouseover", function(d){ title.text(d.data.name);
subtitle.text(d3.round(d.data.minutes + d.data.seconds/60, 1)+" min, "+d.data.episodes+" episodes");
subtitle_family.text(d.data.family); });
bars.on("mouseout", function(d){ title.text(title_default);
subtitle.text(subtitle_default);
subtitle_family.text(""); });
bars.on("click", function(d){ window.open(d.data.url, "_blank") });
}
function sortData(data){
var filter = "episodes";
//sort by filter
data.sort(sortProperty(filter));
//break array into families
var families = d3.nest()
.sortValues(sortProperty(filter))
.key(function(d) { return d.family; })
.entries(data);
//sort families by total filter
families.forEach(function(family){
family.episodes = 0;
family.values.forEach(function(member){
family.episodes += member.episodes;
})
});
families.sort(sortProperty(filter));
//move "other" to end no matter what
families.forEach(function(obj,i){
if (obj.key === "Other"){
families.push(families[i])
families.splice(i,1);
return;
}
});
return flattenTree(families);
}
function flattenTree(tree){
var arr = [];
tree.forEach(function(e,i){
arr.push(e.values);
});
if (arr[0] instanceof Array)
return d3.merge(arr);
else
return arr;
}
function arrayFromProperty(arr, prop){
var new_arr = [];
arr.forEach(function(value){
new_arr.push(value[prop]);
});
return d3.set(new_arr).values();
}
function sortProperty(property){
return (function(a, b) {
if (a[property] < b[property])
return 1;
else if (a[property] > b[property])
return -1;
return 0;
});
}
<script src="http://d3js.org/d3.v3.js"></script>
@import url(http://fonts.googleapis.com/css?family=Lato);
@font-face {
font-family: GameOfThrones;
src: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/29725/got.ttf);
}
html, body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.bar {
&:hover{
opacity:.8;
cursor: pointer;
cursor: hand;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment