Grouped horizontal bar chart with legend. This uses parameters for many elements, including value column names in CSV, legend item text, colors, and axis labels.
Created
April 3, 2016 02:48
-
-
Save hrecht/13ad131fd8a95b0838151c178f7ace00 to your computer and use it in GitHub Desktop.
Grouped bar chart with legend
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
category | val0 | val1 | |
---|---|---|---|
cat1 | 161 | 343 | |
cat2 | 112 | 150 | |
cat3 | 210 | 131 | |
cat4 | 56 | 135 |
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 charset='utf-8' /> | |
<title>Grouped bar chart</title> | |
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script> | |
<style> | |
body { | |
font-family: "Arial", sans-serif; | |
} | |
.axis { | |
font-size: 13px; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke-width: 1px; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.label { | |
font-size: 13px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="graphic"></div> | |
<script> | |
var COLORS = ["#4391b5", "#d2d2d2"], | |
LABELS = ["Public", "Private"], | |
VALUES = ["val0", "val1"], | |
CATEGORIES = { | |
cat1: "Elementary school", | |
cat2: "Middle school", | |
cat3: "High school", | |
cat4: "College" | |
}, | |
data; | |
function wrap2(text, width, startingx) { | |
text.each(function () { | |
var text = d3.select(this), | |
words = text.text().split(/\s+/).reverse(), | |
word, | |
line = [], | |
lineNumber = 0, | |
lineHeight = 1.1, // ems | |
y = text.attr("y"), | |
dy = lineHeight * 1.2 | |
//dy = parseFloat(text.attr("dy")), | |
tspan = text.text(null).append("tspan").attr("x", startingx).attr("y", y).attr("dy", dy + "em"); | |
while (word = words.pop()) { | |
line.push(word); | |
tspan.text(line.join(" ")); | |
if (tspan.node().getComputedTextLength() > width) { | |
line.pop(); | |
tspan.text(line.join(" ")); | |
line = [word]; | |
tspan = text.append("tspan").attr("x", startingx).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word); | |
} | |
} | |
}); | |
} | |
function groupedChart() { | |
var color = d3.scale.ordinal() | |
.range(COLORS); | |
var margin = { | |
top: 70, | |
right: 40, | |
bottom: 45, | |
left: 100 | |
}; | |
var width = 960 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom; | |
var svg = d3.select("#graphic").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 legspacing = 25; | |
var legend = svg.selectAll(".legend") | |
.data(VALUES) | |
.enter() | |
.append("g") | |
legend.append("rect") | |
.attr("fill", color) | |
.attr("width", 20) | |
.attr("height", 20) | |
.attr("y", function (d, i) { | |
return i * legspacing - 60; | |
}) | |
.attr("x", 0); | |
legend.append("text") | |
.attr("class", "label") | |
.attr("y", function (d, i) { | |
return i * legspacing - 46; | |
}) | |
.attr("x", 30) | |
.attr("text-anchor", "start") | |
.text(function (d, i) { | |
return LABELS[i]; | |
}); | |
data.forEach(function (d) { | |
d[VALUES[0]] = +d[VALUES[0]]; | |
d[VALUES[1]] = +d[VALUES[1]]; | |
d.vals = VALUES.map(function (name) { | |
return { | |
name: name, | |
value: +d[name] | |
}; | |
}); | |
}); | |
var y0 = d3.scale.ordinal() | |
.rangeRoundBands([height, 0], .14); | |
var y1 = d3.scale.ordinal(); | |
var x = d3.scale.linear() | |
.range([0, width]) | |
.domain([0, d3.max( | |
[].concat(data.map(function (d) { | |
return (d[VALUES[0]]); | |
}), data.map(function (d) { | |
return (d[VALUES[1]]); | |
})))]); | |
y0.domain(data.map(function (d) { | |
return d.category; | |
})); | |
y1.domain(VALUES).rangeRoundBands([0, y0.rangeBand()]); | |
x.domain([0, d3.max(data, function (d) { | |
return d3.max(d.vals, function (d) { | |
return d.value; | |
}); | |
})]); | |
var yAxis = d3.svg.axis() | |
.scale(y0) | |
.tickSize(0) | |
.tickFormat(function (d) { | |
return CATEGORIES[d]; | |
}) | |
.orient("left"); | |
var gy = svg.append("g") | |
.attr("class", "y axis") | |
.call(yAxis) | |
.selectAll(".tick text") | |
.attr("transform", function (d) { | |
return "translate(0," + -0.25 * y0.rangeBand() + ")"; | |
}) | |
.call(wrap2, 90, -5); | |
var bars = svg.selectAll(".bar") | |
.data(data) | |
.enter().append("g") | |
.attr("class", "group") | |
.attr("transform", function (d) { | |
return "translate(0," + y0(d.category) + ")"; | |
}); | |
bars.selectAll("rect") | |
.data(function (d) { | |
return d.vals; | |
}) | |
.enter().append("rect") | |
.attr("height", y1.rangeBand()) | |
.attr("y", function (d) { | |
return y1(d.name); | |
}) | |
.attr("x", x(0)) | |
.attr("width", function (d) { | |
return x(d.value); | |
}) | |
.attr("fill", function (d) { | |
return color(d.name); | |
}); | |
bars.selectAll("text") | |
.data(function (d) { | |
return d.vals; | |
}) | |
.enter().append("text") | |
.attr("class", "label") | |
.attr("y", function (d) { | |
return y1(d.name) + y1.rangeBand() / 2 + 4; | |
}) | |
.attr("x", function (d) { | |
return x(d.value) + 6; | |
}) | |
.attr("text-anchor", "start") | |
.text(function (d) { | |
return d.value; | |
}); | |
} | |
d3.csv("data.csv", function (rates) { | |
data = rates; | |
groupedChart(); | |
}) | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment