Skip to content

Instantly share code, notes, and snippets.

@hrecht
Created April 3, 2016 02:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hrecht/13ad131fd8a95b0838151c178f7ace00 to your computer and use it in GitHub Desktop.
Save hrecht/13ad131fd8a95b0838151c178f7ace00 to your computer and use it in GitHub Desktop.
Grouped bar chart with legend

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.

category val0 val1
cat1 161 343
cat2 112 150
cat3 210 131
cat4 56 135
<!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