Skip to content

Instantly share code, notes, and snippets.

@DimsumPanda
Last active November 18, 2015 16:40
Show Gist options
  • Save DimsumPanda/43d6281c087b3108ea2f to your computer and use it in GitHub Desktop.
Save DimsumPanda/43d6281c087b3108ea2f to your computer and use it in GitHub Desktop.
Week 10: tooltips
country health military agriculture industry other
Angola 4716918208 6090753194 12492068927 71768457098 29094977306
Burundi 217641361.8 60859466.19 1081116170 481389568.8 873499009.4
Benin 378787504.5 86003151.12 3033957326 1164099198 3644374278
Burkina Faso 776970502.4 163320783.7 2735466520 3366516879 5084048108
Botswana 813296539.8 298461703.3 378531741.5 5592224894 7896791935
Cameroon 1509798861 392840650.6 6766538984 8832000686 12066325474
Cabo Verde 80007150.05 9507426.794 155529136.7 305009655.1 1287856014
Ethiopia 2406019516 384546149.5 21398416446 5678928137 17656818710
Gabon 656309488.1 254027994.7 572771392.1 7699015690 8022958739
Ghana 2618934668 254990532.7 10901717151 13996624845 20812470790
Guinea 292532470.7 192533797 1261136505 2347400264 2138122448
Kenya 2459012791 860560896.1 16158866212 11025721950 24426652138
Lesotho 246483149.8 47940984.56 120203632 639369984.8 1093682584
Madagascar 449329815.7 74044567.06 2799184412 1713924075 5576991123
Mozambique 1049477156 157892114.4 4431050497 3269335797 6549441296
Mauritania 190749669.4 144215640 1034620092 2078157843 1610011694
Mauritius 575113525.3 23200896.38 384319641.6 2897855051 8047566284
Malawi 323692446 68597692.75 1289166315 667421084.1 1534643637
Namibia 1000626196 396311275.9 817001466.3 4312704475 6405562477
Rwanda 838131225.1 82480717.13 2511459306 1119640725 2970294224
Senegal 628562765 236737916 2592072269 3555032466 7779293593
Sierra Leone 583709949.9 30279061.34 2923798490 390873277.4 999612207.2
Zambia 1349338580 381400693.1 2586720240 9079359853 13423986912
<!DOCTYPE html>
<!-- code loosely inspired by this block https://gist.github.com/mstanaland/6100713 -->
<meta charset="utf-8">
<style>
body {
font: 12px sans-serif;
padding: 50px;
}
svg {
background-color: rgb(255, 255, 255);
}
svg rect:hover {
opacity: .3;
}
svg circle: hover {
opacity: .3;
}
svg g {
fill: #ACACAC;
}
svg g text.label,
svg g text.ylabel {
fill: #2A2A2A;
}
svg {
background-color: #fff;
}
#form {
position: relative;
right: 10px;
top: 10px;
padding-bottom: 20px;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.line {
stroke: #FF9900;
fill: none;
stroke-opacity: 25%;
stroke-width: 1px;
}
.unfocused {
stroke-opacity: 25%;
}
.focused {
stroke-width: 2px;
stroke-opacity: 100%;
}
.bar {
fill: steelblue;
}
.x.axis path {
display: none;
}
.tooltip {
position: absolute;
z-index: 10;
}
.tooltip p {
background-color: rgba(255,255,255,1);
padding: .5em 1em;
font-size: 12px;
line-height: 17px;
color: black;
}
.tooltipHeader {
font-weight: 700;
font-size: 12.5px;
}
</style>
<body>
<h2>Breakdown of GDP (in USD) in 2013 in Selected Sub-Saharan African Countries</h2>
<p>WorldBank data. Emphasis on the percentage of GDP spent on healthcare services (public and private) in Sub-Saharan countries.</p>
<p>Industry refers to Industry, value added in GDP (in USD) from mining, manufacturing, construction, electricity, water, and gas.</p>
<div id="form">
<label><input type="radio" name="mode" value="bycount" checked>Raw Count</label>
<label><input type="radio" name="mode" value="bypercent">Percent of GDP</label>
</div>
<div id="chart"></div>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script>
var margin = {top: 20, right: 150, bottom: 50, left: 40},
width = 980 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var xScale = d3.scale.ordinal()
.rangeRoundBands([0, width], .3);
var yScale = d3.scale.linear()
.rangeRound([height, 0]);
var color = d3.scale.category20();
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.innerTickSize([0]);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.tickFormat(d3.format(".2s")); // for the stacked totals version
var stack = d3.layout
.stack(); // default view is "zero" for the count display.
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var tooltip = d3.select("body")
.append("div")
.attr("class", "tooltip");
var percentClicked = false;
d3.csv("gdp.csv", function(error, data) {
if (error) {
console.log(error);
}
console.log(data);
data.sort(function(a,b) { return +a.health - +b.health;});
// how would we sort by largest total bar? what would we have to calculate?
var gdp = ["other","industry","agriculture", "military", "health"];
console.log("gdpcomponents",gdp);
var stacked = stack(makeData(gdp, data)); // needed for default view
console.log(stacked);
xScale.domain(data.map(function(d) { return d.country; }));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("dy", ".5em")
.attr("transform", "rotate(-30)")
.style("text-anchor", "end");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("GDP");
var country = svg.selectAll(".country")
.data(stacked)
.enter().append("g")
.attr("class", "country")
.style("fill", function(d, i) { return color(i); });
var rectangles = country.selectAll("rect")
.data(function(d) {
// console.log("array for a rectangle");
return d; }) // this just gets the array for bar segment.
.enter().append("rect")
.attr("width", xScale.rangeBand());
// this just draws them in the default way, now they're appended.
transitionCount();
drawLegend();
d3.selectAll("input").on("change", handleFormClick);
// All the functions for stuff above!
function handleFormClick() {
if (this.value === "bypercent") {
percentClicked = true;
transitionPercent();
} else {
percentClicked = false;
transitionCount();
}
}
function makeData(gdp, data) {
return gdp.map(function(component) {
return data.map(function(d) {
return {x: d["country"], y: +d[component], component: component};
})
});
}
function transitionPercent() {
yAxis.tickFormat(d3.format("%"));
stack.offset("expand"); // use this to get it to be relative/normalized!
var stacked = stack(makeData(gdp, data));
// call function to do the bars, which is same across both formats.
transitionRects(stacked);
}
function transitionCount() {
yAxis.tickFormat(d3.format(".2s")); // for the stacked totals version
stack.offset("zero");
var stacked = stack(makeData(gdp, data));
transitionRects(stacked);
}
function transitionRects(stacked) {
// this domain is using the last of the stacked arrays, which is the last illness, and getting the max height.
yScale.domain([0, d3.max(stacked[stacked.length-1], function(d) { return d.y0 + d.y; })]);
// attach new fixed data
var country = svg.selectAll(".country")
.data(stacked);
// same on the rects
country.selectAll("rect")
.data(function(d) {
console.log("array for a rectangle");
return d;
}) // this just gets the array for bar segment.
svg.selectAll("g.country rect")
.transition()
.duration(250)
.attr("x", function(d) {
return xScale(d.x); })
.attr("y", function(d) {
return yScale(d.y0 + d.y); }) //
.attr("height", function(d) {
return yScale(d.y0) - yScale(d.y0 + d.y); }); // height is base - tallness
svg.selectAll(".y.axis").transition().call(yAxis);
}
// =====================================================================
// Building a legend by hand, based on http://bl.ocks.org/mbostock/3886208
// ===================================================================
function drawLegend() {
var legend = svg.selectAll(".legend")
.data(color.domain().slice()) // what do you think this does?
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + Math.abs((i-5) * 20) + ")"; });
// Added the absolute value and transition. I reversed the names, so that I can continue to use category20(), but have health as green to make it stand out.
legend.append("rect")
.attr("x", width)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width + 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d, i) { return gdp[i]; });
}
// ================================================================
// Mouse Events
// ================================================================
rectangles
.on("mouseover", mouseoverFunc)
.on("mousemove", mousemoveFunc)
.on("mouseout", mouseoutFunc);
function mouseoverFunc(d) {
console.log("moused over", d.x);
if(percentClicked) {
tooltip
.style("display", null)
.html("<p><span class='tooltipHeader'>" + d.x + "</span><br>"+ d.component + ": " + d3.format("%")(d.y) + "</p>");
} else {
console.log("gdp", d.component, "percent", d.y);
tooltip
.style("display", null)
.html("<p><span class='tooltipHeader'>" + d.x + "</span><br>"+ d.component + ": " +d.y + "%</p>");
}
}
function mousemoveFunc(d) {
tooltip
.style("top", (d3.event.pageY - 5) + "px")
.style("left", (d3.event.pageX + 10) + "px");
}
function mouseoutFunc(d) {
return tooltip.style("display", "none"); // this sets it to invisible!
}
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment